lab2 主要实现两个系统调用
添加系统调用过程
-
user/user.h
里添加系统调用函数,这个lab需要添加两个系统调用,下图中最后两个:trace 和 sysinfo
-
user/usys.pl
里添加一个entry,这个文件会生成user/usys.S
,就是系统调用的具体实现,之后会使用ecall
指令跳转到相应的系统调用去执行。
-
kernel/syscall.h
添加系统调用的编号
-
kernel/syscall.c
添加系统调用的函数映射,syscalls
这个数组存放了所有指向系统调用的实现函数指针
- 最后就是实现系统调用函数
1.trace
实现trace,输入mask,需要trace对应位为1的系统调用,每个系统调用对应一个数字,如系统调用fork对应数字为SYS_fork,如果要trace fork,那么mask & (1 << SYS_fork) = 1
即可。trace输出 进程号、系统调用函数名、系统调用返回值。
$ 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
具体实现过程:
- 按照之前过程添加 trace系统调用
- trace需要每个进程保存mask,因此在
kernel/proc.h
中proc结构体添加mask,这里只简单的用了int,因为目前系统调用20几个,31位够用。如果考虑可扩展性的话,可以使用数组。
- 有了这个标志,可以直接写出trace的实现了。在
kernel/sysproc.c
添加sys_trace
函数,函数里只需要将当前进程的tracemask
置为mask即可。
- 子进程也需要修改mask,修改
kernel/proc.c
里的fork,子进程继承父进程的tracemask
- 最后就是输出,
kernel/syscall.c
的syscall函数添加输出,因为只能得到系统调用对应的数字编号,因此还需要添加该编号到名字的映射。
2.sysinfo
sysinfo用于得到为分配的内存字节数以及不处于UNUSED
状态的进程数。
实现:
- 像之前一样添加系统调用
sysinfo
. - 获取未分配的内存字节数,在
kernel/kalloc.c
里添加,kmem.freelist
表示空闲页块头结点,因此遍历到末尾即可,最后需要乘上页大小。
- 获取不为
UNUSED
状态的进程数,在kernel/proc.c
里添加,也是遍历一遍就行。
- 最后就是添加sysinfo系统调用,我是在
kernel/sysproc.c
里添加的,需要加sysinfo.h
头文件,调用上面两个函数获取fennmem
和nproc
,之后用copyout
将其从内核空间复制到用户空间。
总结
刚开始做没有什么头绪,之后看源码,了解了大致系统调用过程后再回头看看实现也不是很复杂。