【MIT 6.S081】实验二:system calls。主要贡献:知识讲解与流程图
前言已经是第二章的内容了,这一章不再是停在用户态去完成实验,而会深入到内核态,增加内核态的系统调用。实验使用win10 + wsl2 Ubuntu 20.04完成。内容总览在上一个实验中,您使用系统调用编写了一些实用程序。在本实验中,您将向 xv6 添加一些新的系统调用,这将帮助您了解它们的工作原理,并让您了解 xv6 内核的一些内部结构。您将在以后的实验中添加更多系统调用。包括:trace:建一
前言
已经是第二章的内容了,这一章不再是停在用户态去完成实验,而会深入到内核态,增加内核态的系统调用。
实验使用win10 + wsl2 Ubuntu 20.04完成。
内容总览
在上一个实验中,您使用系统调用编写了一些实用程序。在本实验中,您将向 xv6 添加一些新的系统调用,这将帮助您了解它们的工作原理,并让您了解 xv6 内核的一些内部结构。您将在以后的实验中添加更多系统调用。
包括:
-
trace:建一个新的系统调用
trace
来控制跟踪。它应该接受一个参数,一个整数"mask",代表了要追踪的系统调用。例如,为了跟踪 fork 系统调用,程序调用
trace(1 << SYS_fork)
,其中 SYS_fork 是来自 kernel/syscall.h 的系统调用号。 -
Sysinfo:新建系统调用
Sysinfo
,收集有关正在运行的系统的信息。
reference
ref1
:第二章实验要求ref2
:MIT6.s081-2020 操作系统入门 Lab2 System Callsref3
:MIT 6.S081 2020 Lab2 system calls讲解ref4
:MIT 6.S081 Lab2
十分感谢以上大佬开源的贡献。知识参考:课程内容翻译 github
内容1:System call tracing
在本作业中,您将添加一个系统调用跟踪功能,该功能可能会在以后调试实验时帮助您。
您将创建一个新的系统调用trace
来控制跟踪。它应该接受一个参数,一个整数"mask",代表了要追踪的系统调用。
例如,为了跟踪 fork 系统调用,程序调用 trace(1 << SYS_fork)
,其中 SYS_fork 是来自 kernel/syscall.h 的系统调用号。
**如果掩码中设置了系统调用的编号,则必须修改 xv6 内核以在每个系统调用即将返回时打印出一行。**该行应包含进程id、系统调用的名称和返回值;您不需要打印系统调用参数。系统调用trace
应该启用对调用它的进程以及它随后派生的任何子进程的跟踪,但不应影响其他进程。
提示和理解
题目理解
这个trace()
函数的作用是,第一个参数是掩码,因为int是32位最多能表示31个系统调用,被置为1的那个系统调用位就会被跟踪并打印信息。例如trace 32 grep hello README
就会跟踪grep hello README
这个过程下的所有read命令
,因为1<<SYS_read
就是等于32
前置知识
网上有很多关于怎么完成这个实验的步骤说明,ref2
和ref3
我亲测都可以可以完成实验并且通过测试,但是很仔细说明原理的。所以我来解说下。
首先按照要求阅读 xv6 book,以及一些文件:
- 书本内容:Before you start coding, read Chapter 2 of the xv6 book, and Sections 4.3 and 4.4 of Chapter 4, and related source files:
- 用户态理解:The user-space code for systems calls is in user/user.h and user/usys.pl.
- 内核态理解:The kernel-space code is kernel/syscall.h, kernel/syscall.c.
- 进程设计:The process-related code is kernel/proc.h and kernel/proc.c.
但是这里缺少了关键的需要阅读文件,如果不看就不懂得做这个实验:
kernel/kalloc.c
1. Xv6内核源文件
这里是列出是为了让大家知道哪些文件决定着整个内核的功能,不然会对程序流程很懵逼。
文件 | 说明 |
---|---|
bio.c | 文件系统的磁盘块高速缓存 |
console.c | 连接到用户的键盘和屏幕 |
entry.S | 第一次启动指令 |
exec.c | 系统调用 |
fs.c | 文件系统 |
kalloc.c | 物理页面分配器 |
kernelvec.S | 处理来自内核的陷阱,以及计时器中断 |
log.c | 文件系统日志记录和崩溃恢复 |
main.c | 控制引导过程中其他模块的初始化 |
pipe.c | 管道 |
plic.c | RISC-V中断控制器 |
printf.c | 格式化输出到控制台。 |
proc.c | 进程和调度 |
sleeplock.c | 占据cpu的锁 |
spinlock.c | 不占据cpu的锁 |
start.c | 早期机器模式启动代码。 |
string.c | C的字符串 |
swtch.S | 线程切换 |
syscall.c | 映射:调度系统调用 -> 处理功能 |
sysfile.c | 与文件相关的系统调用 |
sysproc.c | 与进程相关的系统调用 |
trampoline.S | 在用户和内核之间切换的汇编代码 |
trap.c | 处理陷阱和中断的返回 |
uart.c | 串口控制台设备驱动程序 |
virtio_disk.c | 磁盘设备驱动程序 |
vm.c | 管理页表和地址空间 |
2. xv6 的进程视图
流程与代码
下面这张图很清晰地展示了做的流程。
具体的代码请参考reference2
# 功能测试
$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0
$ trace 2147483647 grep hello README
4: syscall trace -> 0
4: syscall exec -> 3
4: syscall open -> 3
4: syscall read -> 1023
4: syscall read -> 966
4: syscall read -> 70
4: syscall read -> 0
4: syscall close -> 0
$ grep hello README
$ trace 2 usertests forkforkfork
usertests starting
6: syscall fork -> 7
test forkforkfork: 6: syscall fork -> 8
8: syscall fork -> 9
9: syscall fork -> 10
9: syscall fork -> 11
10: syscall fork -> 12
...
9: syscall fork -> -1
10: syscall fork -> -1
12: syscall fork -> -1
OK
6: syscall fork -> 69
ALL TESTS PASSED
内容2:Sysinfo
在这个作业中,您将添加一个系统调用 sysinfo
,它收集有关正在运行的系统的信息。
系统调用接受一个参数:指向struct sysinfo
的指针(参见 kernel/sysinfo.h
)。
内核应填写此结构的字段:
freemem
字段应设置为空闲内存的字节数,nproc
字段应设置为状态不是UNUSED
的进程数。
我们提供了一个测试程序sysinfotest
;如果它打印“sysinfotest:OK”,你就通过了这个任务。
提示
都很直白,按照步骤走。
-
Add
$U/_sysinfotest
to UPROGS in Makefile -
Run
make qemu
;user/sysinfotest.c
will fail to compile. Add the system callsysinfo
, following the same steps as in the previous assignment. To declare the prototype for sysinfo()in user/user.h
you need predeclare the existence ofstruct sysinfo
:struct sysinfo; int sysinfo(struct sysinfo *);
Once you fix the compilation issues, run
sysinfotest
; it will fail because you haven’t implemented the system call in the kernel yet. -
sysinfo needs to copy a
struct sysinfo
back to user space; seesys_fstat()
(kernel/sysfile.c
) andfilestat()
(kernel/file.c
) for examples of how to do that usingcopyout()
. -
To collect the amount of free memory, add a function to
kernel/kalloc.c
-
To collect the number of processes, add a function to
kernel/proc.c
操作流程
这里ref4
讲得很详细,跟着ref4
就行,逻辑跟内容1差不多,就不画流程图了。
后话
这部分的实验,让我们知道了怎么新添一个系统调用,以及如何在用户态和系统态之间交换和打交道。第一个实验不熟悉,比较困难,画了流程图之后就清晰明了许多。第二个实验就熟悉了。
欢迎点赞和留言交流。
更多推荐
所有评论(0)