MIT6.S081
MIT6.S081 Fall 2020.
syscall lab
这个实验需要自己实现一些系统功能调用
前置知识
- xv6的启动过程
- Qemu启动RISC-V模拟,在只读内存中读取并运行启动加载程序(boot loader)
- CPU在_entry(kernel/entry.S)以机器模式执行,此时没有分页,虚拟地址直接映射
- 启动加载程序加载内核到0x80000000
- 调用start()函数
- 进入内核模式,执行kernel/main.c
- userinit()创建第一个进程
- exec调用user/inti.c,创建标准输入输出,并启动shell程序
- 系统功能调用的全过程
- 用户态中实现应用程序,调用user.h中的系统调用C接口
- 通过usys.S(由usys.pl生成),将系统调用号加载到a7,然后进入内核态
- 调用syscall函数,先取出a7得到系统调用号,然后执行syscallnum
- 系统调用中获取参数
C接口是int trace(int),系统调用却是uint64 sys_trace(void)
所以需要用一种方式获取参数
也就是argaddr和argint,分别获取地址和整数类型参数
如果需要实现一个系统功能调用
- 用户态
- user/user.h里面是用户态的接口
- user/usys.pl(perl语言),用于生成usys.S
- 内核态
- kernel/syscall.c和syscall.h
syscall.h里面定义了系统功能调用号 - sysproc.c中增加系统功能的实现
- 用户态->内核态
- kernel/proc.c和proc.h
-
struct proc
-
struct sysinfo
-
struct run & kmem
// 空闲内存链表,每个空闲区大小PGSIZE
struct run {
struct run *next;
};
// 当前进程空闲内存信息
struct {
struct spinlock lock;
struct run *freelist;
} kmem;
trace
根据传入的系统功能调用号,来跟踪进程的系统功能调用情况
调用方式:trace mask command [command args]
根据hints来看
该实验已经实现了一个用户态的trace,但是需要自己添加:
- 用户态的接口,user.h中C接口的声明和usys.pl中entry。
- 在内核态syscall.h中添加系统调用号;syscall.c中添加sys_trace的声明,并在syscall函数中输出相应的系统功能调用信息
- sysproc中添加sys_trace的实现,把mask传递到trace_mask里
sysinfo
实现一个sysinfo的系统调用
sysinfo:
- 当前空闲内存的大小freemem
- 非UNUSED状态进程数量
添加系统调用的方法和trace差不多
实现sys_sysinfo
- 获取用户传入地址addr(用户空间)
- 内核空间创建sysinfo,并获取相应参数get_freemem()及get_nproc()
- 将sysinfo copyout到addr上(参考sys_ftat)
这个实验思路上不算很难,但是需要去理解xv6内核代码里面定义的一些结构和函数,还是花了挺多时间,也参考了网上的一些教程。