EXERCISE 0
阅读xv6 book第二章和第四章4.3和4.4节以及相关代码,理解xv6内核和系统调用
用户空间代码位于 user / user.h 和 user / usys.pl中 。
内核空间代码为 kernel / syscall.h ,kernel / syscall.c。
进程相关的代码是 内核/ proc.h 和 内核/ proc.c 。
代码阅读
user.h
定义了系统调用的一系列函数
fork
exit
wait
pipe
write
read
close
kill
exec
open
mknod
unlink
fstat
link
mkdir
chdir
dup
getpid
sbrk
sleep
uptime
ulib.c
stat
strcpy
memmove
strchr
strcmp
fprintf
printf
gets
strlen
memset
malloc
free
atoi
memcmp
memcpy
usys.S
定义SYSCALL(name)的汇编代码
syscall.h
定义system call numbers1~21
syscall.c
fetchaddr获取当前进村的uint64地址
fetchstr
argraw
argint获取32bit 系统调用
argaddr获取一个指针,不检查合法性(在copyin/copyout中做)
argstr获取n字长的系统调用 复制进buf
定义一系列的系统调用函数
void syscall(void) 系统调用函数。
proc.h
为内核上下文开关保存的寄存器。
struct context{ra; sp; s0~s11}
struct cpu{proc; context; noff; intena}CPU状态
trapframe
/trampoline.S中陷阱处理代码的每进程数据。
//坐在一个页面本身就在trampoline页面的下面
//用户页表。在内核页表中没有特别映射。
//sscratch寄存器指向这里。
//trampoline.S中的uservec在trapframe中保存用户寄存器,
//然后从trapframe的//kernel_sp、kernel_hartid、kernel_satp,初始化寄存器,并跳到kernel_trap。
//在trampoline.S设置中的usertrapret()和userret
//trapframe的内核,从trapframe,切换到user page表,然后进入user space。
//trapframe包括被调用者保存的用户寄存器,如s0-s11,因为通过usertrapret()返回用户路径不会通过整个内核调用堆栈。
procstate{UNUSED, SLEEPING, RUNNABLE, RUNNING, ZOMBIE}
struct proc{lock, state, parent, chan, killed, xstate, pid, kstack, sz, pagetable, trapframe, context, ofile, vwd, name}每个进程的状态
proc.c
cpus
proc
initproc
forkret
wakeup1
freeproc
procinit//启动时初始化proc table
cpuid
mycpu
myproc
allocpid
allocproc
freeproc
proc_pagetable
proc_freepagetable
userinit
growproc
fork
reparent
exit
wait
scheduler
sched
yield
forkret
sleep
wakeup
wakeup1
kill
either_copyout
either_copyin
procdump
EXERCISE 1 System Call Tracing
目的
创建新的系统调用trace来控制跟踪。它有一个参数,即整数掩码(mask),位数指定跟踪的那个系统调用。
eg. trace(1 << SYS_fork),跟踪fork调用,其中SYS_fork是系统调用号,位于kernel / syscall.h中 。 。
如果在掩码中设置了系统调用的编号,则必须修改xv6内核以在每个系统调用即将返回时打印出一行。
该行应包含pid,系统调用name和返回值。
无需打印系统调用参数。 trace系统调用应该跟踪调用它的进程和进程fork的孩子,但应该不会影响其他进程。
提示
- 添加到Makefile的UPROGS中
- 运行make qemu会发现不能编译trace.c,因为系统调用的用户空间不存在。天津一个原型系统调用到user/user.h,存根到user/usys.pl和syscall号kernel/syscall.h中。Makefile会调用perl脚本user/usys.pl,生成user/usys.S,该存根使用RISC-V ecall指令转换到内核。解决编译问题后,运行trace 32 grep hello README,会失败,因为还没有实现系统调用
- 在kernel/sysproc.c中添加一个sys_trace()函数,该函数通过记住新变量中的参数来实现新的系统调用。proc结构(参阅kernel/proc.h),从用户空间检索系统调用的函数位于kernel/syscall.c中,参阅kernel/sysproc.c获得用法示例。
- 修改fork()(参阅kernel/proc.c)以将trace的掩码从父进程复制进子进程中。
- 修改syscall.c的syscall()函数以打印trace的输出。需要添加一个系统调用名称数组来建立索引。
//Makefile
$U/_trace\
//user.h
int trace(int);// added by me.
//usys.pl