操作系统实验报告 lab2 【System calls】
一、实验内容:
Part A System call trace
编译准备:
-
Add
$U/_trace
to UPROGS in Makefile
-
Add a prototype for the system call to
user/user.h
-
Add a stub to
user/usys.pl
-
Add a syscall number to
kernel/syscall.h
-
编译测试:
make qemu
,成功运行
实现trace:
-
实现思路:
根据提示,是要在
kernel/sysproc.c
中添加一个函数sys_trace()
,该函数要记住传进来的参数,并在struct proc中新加一个变量用于储存这一参数。结合前面的功能描述,这个参数就是mask
,也即trace 32 grep hello README
中的32
。查看
kernel/sysproc.c
中其他函数(如sys_exit()
),发现其没有参数,但使用了argint(0,&n)
来获取所需的n值,其用于获取第0个寄存器的信息并用n来储存。故mask
也应该用同样的方法来读取。同时要在
struct proc
中添加mask
变量再把
mask
赋值给当前proc
的mask
,根据sys_getpid()
,可用myproc()->mask
来进行赋值。 -
编写函数:先读取0号寄存器的内容到
mask
中,再把mask
赋给当前proc
的mask
子项复制:
-
Modify
fork()
(seekernel/proc.c
) to copy the trace mask from the parent to the child process.即把父进程的
mask
赋给子进程:
打印输出:
- 在
syscall()
中添加相应的trace项:
-
Add an array of syscall names to index into.
用于打印输出
-
输出实现:
首先,打印内容的结构是:
3: syscall read -> 1023
(3为pid,syscall为统一输出,read为系统调用的名字,1023为其返回值。pid直接用
myproc()->pid
即可获取系统调用的名字则通过上述的表中根据编号(
num
)获取,编号要与mask
进行匹配,匹配成功才要进行输出,mask
的第num
位为1则需打印输出。匹配过程考虑位运算,将1左移num
位,再&
上mask
,若当mask
的第num
位不为1时,结果为0。返回值调用
syscalls[num]()
后即得到,因p->trapframe->a0存储了该值,输出它即可。
测试:
Part B Sysinfo
编译准备:
-
重复Part A的操作:
-
其他准备:
Predeclare the existence of
struct sysinfo
Add
Student ID
for print
辅助函数:
To collect the amount of free memory, add a function to kernel/kalloc.c
阅读 kernel/kalloc.c
中的其他函数发现,有freelist可以使用,用一个while循环遍历该freelist,并让计数器count++,即可获取free的page数目,count*PGSIZE即为free memory。同时,涉及到临界区变量,该过程要加锁。
To collect the number of processes, add a function to kernel/proc.c
copy kernel/kalloc.c
中的其他函数的遍历方法,并置计数器count,当状态不为UNUSED即count++,该过程也要加锁。
实现sysinfo:
-
实现思路:
先创建一个
struct sysinfo
调用之前两个辅助函数获取
sysinfo
内的freemem
和nproc
值,再把学号赋值给
sid
并打印接下来进行
copyout
操作,将对应位置改为info
即可,注意前面参数的获取也要有,p
通过myproc()
获取,addr
从0号寄存器读入。 -
编写函数:注意要在
"defs.h"
添加辅助函数的定义
测试:
二、问题回答:
(1)System calls Part A部分,简述一下trace全流程.
trace
先调用user/trace.c
进行参数读入和预处理,再通过entry(trace)
从用户态转到内核态,执行后续操作。在内核态中具体调用sys_trace()
函数,该函数从0号寄存器中读入所谓的mask
,并将mask
放入mypro()
的mask
中。当进行syscall()
时,就会根据myproc()
的mask
是否与编号num
匹配来打印相应内容,完成trace
。
(2)kernel/syscall.h是干什么的,如何起作用的?
通过宏定义,将系统调用函数的名字作为标识符替换为数字编号。通过编号转化后,就可以将系统调用名字的数据转为数据放入寄存器(a7)中,当syscall需要时便从寄存器中读取编号,从而执行对应函数。
(3)命令 “trace 32 grep hello README”中的trace字段是用户态下的还是实现的系统调用函数trace?
trace字段应是在用户态下的函数user/trace.c
,通过内核调用sys_trace()
来实现具体操作。
三、问题解决:
【问题】在Part B的调用两个辅助函数获取sysinfo
内的freemem
和nproc
值时,出现错误,显示函数没有定义。
如上图的getfreemem()函数,其在kernel/kalloc.c
中实现。其定义按道理应添加在kernel/kalloc.h
中,然后include该.h文件即可,但并没有该.h文件。经代码搜索后发现kernel/kalloc.c
中函数的定义是在defs.h
中声明的,类似于user/user.h
,故应在 "defs.h"
添加辅助函数的定义。
四、实验感想:
-
通过这次实验具体函数的实现,理解了用户态和内核态的区别与关系,以及用户态是如何转到内核态的,这是在代码层面一直困扰我的问题。
-
这次实验还有一个地方有点颠覆我的认知,就是内核函数获取参数不是像之前写的代码那样靠传参,而是直接从寄存器中读。
五、实验参考:
标签:kernel,函数,trace,syscall,mask,Lab2,user From: https://www.cnblogs.com/jeekzhang/p/16830072.html