mit6.s081 lab2: system calls
1.system call tracing(moderate)
要求:创建一个系统调用来实现跟踪特性,它采用一个参数来指定跟踪哪一个系统调用,例如:跟踪fork系统调用,程序调用trace(1<<SYS_fork),其中SYS_fork是kernel/syscall.h中的系统调用号。如果在掩码中设置了系统调用的编号,则必须修改须
xv6的内核,以便在每个系统调用即将返回时输出一行。这一行应包括进程id、系统调用的名称和返回值。不需要打印系统调用参数。用于跟踪的系统调用应能够跟踪调用它的进程以及随后的子进程,但不能影响其它的进程。
要实现的效果:
trace 32 grep hello README,表示执行grep hello README时,read系统调用发生时,跟踪并打印要求的东西。
$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0
这里32表示的是1<<SYS_read的结果。
提示:
- 在makefile中添加$U/_trace
- 这个时候直接运行make qemu会发现无法编译user/trace.c,trace这个系统调用还没有实现,即在用户态下的存根还不存在。要在user/user.h中将系统调用声明出来(即int trace(int)),在user/usys.pl中添加存根(entry("trace")),在 kernel/syscall.h中添加系统调用号。
这里Makefile 调用 perl 脚本 user/usys.pl,它生成 user/usys.S,即实际的系统调用存根,它使用 RISC-V 中的ecall回调指令转换到内核。
在完成了上面的操作之后就算是修复了编译问题了,这时可以成功的make qemu了。一旦修复了编译问题,就运行trace 32 grep hello README; 它将失败,因为您还没有在内核中实现系统调用。 - 在 kernel/sysproc.c 中添加 sys _ trace ()函数,该函数通过在 proc 结构中的新变量中记住参数来实现新的系统调用(参见 kernel/proc.h)。从用户空间检索系统调用参数的函数在 kernel/syscall.c 中,您可以在 kernel/sysproc.c 中看到它们的使用示例。(没看太明白,但是可以以照猫画虎的做)
- 修改 fork ()(参见 kernel/proc.c) ,将跟踪掩码从父进程复制到子进程。
- 修改 kernel/syscall.c 中的 syscall ()函数以打印跟踪输出。您需要添加要索引到的系统调用名称数组。
可以知道的信息:
在根据提示完成相关的文件配置之后,可以知道目前需要在kernel/sysproc.c中来完成sys_trace()这个函数。
根据提示三以及参考sysproc.c中的其它函数,先大致做一个测试:
uint64
sys_trace(void)
{
printf("sys_trace:hi\n");
return 0;
}
当运行trace 32 grep hello README的时候可以看到输出就是我们在sys_trace中所打印的东西,就也意味着这里要实现trace系统调用被调用时要输出的东西。
再根据提示三中的从用户空间检索系统调用参数的函数在 kernel/syscall.c 中,转到syscall.c中最下面可以看到syscall函数.在这个函数中首先定义了一个整型的num来记录一个参数,当if判断不成功的时候它会打印“pid(进程号) name(所传入的调用名字):unknown sys call”这样的信息,那么大致可以知道当if判断成功的时候,应该就是对要执行的系统调用做处理,由于每次调用成功会去找到syscalls[num],那么可以推测是根据num来判断是哪一个系统调用,因此不妨再写一个存放系统调用名字的数组来打印一下试试

这时make qemu试一下,可以发现随着xv6的启动,调用的系统调用被打印出来,如下图所示:

这个时候就可以明确syscall是调用系统函数的一个入口,sys_trace是处理trace系统调用的地方,有了这两个函数就应该可以实现这个实验所要实现的效果。
在实现sys_trace函数的时候发现在其它的函数中都有这么一段代码:
int n;
if(argint(0, &n) < 0)
return -1;
那么继续照猫画虎,把这一段搬到sys_trace中用输出调试一下,即printf("sys_trace:hi,n is %d\n",n);,可以发现这段代码是把用户态得到的掩码传给n,比如trace 32 grep hello README得到的n就是32,这个n用于决定要追踪的函数,那么现在的问题就是:如何让syscall也可以获得这个值,毕竟在syscall中需要这个掩码来打印对应得系统调用。
这个时候再返回到提示三中,有这样一句话:在 kernel/sysproc.c 中添加 sys _ trace ()函数,该函数通过在 proc 结构体中的新变量中记住参数来实现新的系统调用(参见 kernel/proc.h),按照这个提示,我们应该在proc中添加变量来实现两个函数共用这一掩码值,而proc结构体所存得是每一个进程的状态信息。
到了这里,基本功能都能实现了,但是我们发现提示4:“修改 fork ()(参见 kernel/proc.c) ,将跟踪掩码从父进程复制到子进程”好像一直没有用到,于是去查看proc.c中的fork,发现在这里面有两个结构体np和p,我们需要将父进程p的相关信息复制给np,于是添加一行:np->trace_mask=p->trace_mask;
实现:
对syscall的修改
static char* syscall_names[]={
"fork","exit","wait","pipe","read","kill","exec","fstat","chdir",
"dup","getpid","sbrk","sleep","uptime","open","write","mknod",
"unlink","link","mkdir","close","trace"
};
void
syscall(void)
{
int num;
struct proc *p = myproc();
num = p->trapframe->a7;
if(num > 0 && num < NELEM(syscalls) && syscalls[num]) {
p->trapframe->a0 = syscalls[num]();//返回值放在a0这个寄存器中
int mask=p->trace_mask;
if((mask>>num)&1){
printf("%d: syscall %s -> %d\n",p->pid,syscall_names[num-1],p->trapframe->a0);
}
} else {
printf("%d %s: unknown sys call %d\n",
p->pid, p->name, num);
p->trapframe->a0 = -1;
}
}
对sys_trace的修改:
uint64
sys_trace(void)
{
int mask;//n是从用户态传进来的掩码,比如追踪的是fork传进来的就是32
if(argint(0, &mask) < 0)
return -1;
//printf("sys_trace:hi,n is %d\n",mask);
struct proc *p = myproc();
p->trace_mask=mask;//把掩码放到进程信息中
return 0;
}
补充:
在测试grep hello README的时候发现输出和预期的不太一样,在这里输出了上一次所跟踪的信息,后来发现在proc.c中根据注释发现有一个freeproc函数用于释放进程信息,我们需要在里面添加一行p->proc_mask=0

2.sysinfo(moderate)
要求:写一个sysinfo这个system call,需要获取当前空闲的内存大小填入struct sysinfo.freemem中,获取当前所有不是UNUSED的进程数量填入struct sysinfo.nproc中
提示:
- 在makefile中添加$U/_sysinfotest
- 运行 make qemu; user/sysinfotest.c 将无法编译。添加系统调用 sysinfo,步骤与前面的任务相同。要在 user/user.h 中声明 sysinfo ()的原型,需要预先声明 struct sysinfo 的存在:
struct sysinfo;
int sysinfo(struct sysinfo *);
- Sysinfo 需要将一个 struct sysinfo 复制回用户空间; 请参阅 sys _ fstat ()(kernel/sysfile.c)和 filestat ()(kernel/file.c)以获得如何使用 copy out ()实现这一点的示例。
- 要收集空闲内存量,请向 kernel/kalloc.c 添加一个函数
- 要收集进程数,请向 kernel/proc.c 添加一个函数
- 在sysproc.c中完成系统调用函数的编写,在syscall中记得对syscalls修改并extern
- 和前面一样先要在user/user.h中声明system callint sysinfo(struct sysinfo *)以及struct sysinfo,在user/usys.pl中注册entry,在kernel/syscall.h中注册一个syscall number,在kernel/sysproc.c中对uint64 sys_sysinfo(void)进行实现,注意要在sysproc.c中添加头文件sysinfo.h
实现:
sysproc.c中实现系统调用
uint64
sys_sysinfo(void)
{
struct sysinfo info;
uint64 addr;
struct proc *p=myproc();
info.freemem=acquire_freemem();
info.nproc=acquire_nproc();
if(argaddr(0, &addr) < 0)//入参放到addr里
return -1;
if(copyout(p->pagetable, addr, (char *)&info, sizeof(info)) < 0)//函数运算后的info结果放到addr里
return -1;
return 0;
}
kalloc.c中实现获取空闲内存
uint64 acquire_freemem()
{
struct run *r;
uint64 cnt=0;
acquire(&kmem.lock);
r = kmem.freelist;
while(r)
{
r=r->next;
cnt++;//链表的长度就是页表的个数
}
release(&kmem.lock);
return cnt*PGSIZE;//页表的个数乘以页表的大小就是整个系统空闲内存的大小
}
proc.c中实现获取使用进程数
uint64 acquire_nproc()
{
struct proc *p;
int cnt=0;
for(p = proc; p < &proc[NPROC]; p++) {
acquire(&p->lock);
if(p->state != UNUSED) {
cnt++;
}
release(&p->lock);
}
return cnt;
}
3测试结果

mit6.s081 lab2: system calls的更多相关文章
- MIT 6.828 JOS学习笔记18. Lab 3.2 Part B: Page Faults, Breakpoints Exceptions, and System Calls
现在你的操作系统内核已经具备一定的异常处理能力了,在这部分实验中,我们将会进一步完善它,使它能够处理不同类型的中断/异常. Handling Page Fault 缺页中断是一个非常重要的中断,因为我 ...
- Hooking Android System Calls for Pleasure and Benefit
The Android kernel is a powerful ally to the reverse engineer. While regular Android apps are hopele ...
- MIT6.S081/6.828 实验1:Lab Unix Utilities
Mit6.828/6.S081 fall 2019的Lab1是Unix utilities,主要内容为利用xv6的系统调用实现sleep.pingpong.primes.find和xargs等工具.本 ...
- MIT-6.828-JOS-lab5:File system, Spawn and Shell
Lab 5: File system, Spawn and Shell tags: mit-6.828 os 概述 本lab将实现JOS的文件系统,只要包括如下四部分: 引入一个文件系统进程(FS进程 ...
- MIT6.828 Lab2 内存管理
Lab2 0. 任务介绍 你将编写一个内存管理代码.主要分为两大部分.分别对物理内存和虚拟内存的管理. 对于物理内存,每次分配内存分配器会为你分配4096bytes.也称为一个页(在大部分操作系统中一 ...
- 【MIT6.S081/6.828】手把手教你搭建开发环境
目录 1. 简介 2. 安装ubuntu20.04 3. 更换源 3.1 更换/etc/apt/sources.list文件里的源 3.2 备份源列表 3.3 打开sources.list文件修改 3 ...
- Linux Kernel sys_call_table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux
目录 . sys_call_table:系统调用表 . 内核符号导出表:Kernel-Symbol-Table . Linux 32bit.64bit环境下系统调用入口的异同 . Linux 32bi ...
- Linux Kernel sys_call_table、Kernel Symbols Export Table Generation Principle、Difference Between System Calls Entrance In 32bit、64bit Linux【转】
转自:http://www.cnblogs.com/LittleHann/p/4127096.html 目录 1. sys_call_table:系统调用表 2. 内核符号导出表:Kernel-Sym ...
- Linux System Calls Hooking Method Summary
http://www.cnblogs.com/LittleHann/p/3854977.html http://www.cnblogs.com/cozy/articles/3175615.html h ...
- MIT6.828 JOS系统 lab2
MIT6.828 LAB2:http://pdos.csail.mit.edu/6.828/2014/labs/lab2/ LAB2里面主要讲的是系统的分页过程,还有就是简单的虚拟地址到物理地址的过程 ...
随机推荐
- 本地Stackedit Markdown编辑器设置远程访问
StackEdit是一个受欢迎的Markdown编辑器,在GitHub上拥有20.7k Star!,它支持将Markdown笔记保存到多个仓库,包括Gitee.GitHub和Gitea.此在线笔记工具 ...
- 本地训练,开箱可用,Bert-VITS2 V2.0.2版本本地基于现有数据集训练(原神刻晴)
按照固有思维方式,深度学习的训练环节应该在云端,毕竟本地硬件条件有限.但事实上,在语音识别和自然语言处理层面,即使相对较少的数据量也可以训练出高性能的模型,对于预算有限的同学们来说,也没必要花冤枉钱上 ...
- React 中常用技术
可以少去理解一些不必要的概念,而多去思考为什么会有这样的东西,它解决了什么问题,或者它的运行机制是什么? 1. React 中导出和导入 1.1 ES6 解析 ES6 的模块化的基本规则或特点: 每一 ...
- python列表删除元素之del,pop()和remove()
del函数 如果知道要删除元素在列表中的位置,可以使用del语句: list_1 = ['one', 'two', 'three'] print(list_1) del list_1[0] print ...
- 总结(5)--- Numpy和Pandas库常用函数
二.常用库 1.NumPy NumPy是高性能科学计算和数据分析的基础包.部分功能如下: ndarray, 具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组. 用于对整组数据进行快速运算的标准 ...
- vivado仿真(无需testbench)
vivado仿真(无testbench) 实现步骤 新建一个工程并添加自己编写的Verilog文件 添加后vivado会自动识别文件中的module 创建block design文件,添加模块 添加前 ...
- 用友U8+与百胜E3的数据对接:实现企业数字化业务的集成与协作
用友U8+作为中国企业最佳经营管理平台之一,在企业经营管理中广泛应用.然而,由于每个企业的内部管理方式和流程各不相同,标准软件功能难以完全适应所有企业的管理需求.同时,随着互联网和移动应用的发展,对于 ...
- P8594 「KDOI-02」一个仇的复 题解
我会组合数! 首先发现同一列只有被不同的横块填或被一个相同的竖块填,且用竖块填完1列之后,会分成两个封闭的长方形,而长方形内部则用横块来填充. 先考虑一个子问题,某个 \(2 \times n\) 长 ...
- 【.NET】控制台应用程序的各种交互玩法
老周是一个不喜欢做界面的码农,所以很多时候能用控制台交互就用控制台交互,既方便又占资源少.有大伙伴可能会说,控制台全靠打字,不好交互.那不一定的,像一些选项类的交互,可以用键盘按键(如方向键),可比用 ...
- IIS下使用SSL证书
IIS下使用SSL证书 本文介绍windowsServer下SSL证书配置及IIS站点配置 1. 生成SSL证书 在阿里云申请免费SSL证书 登录阿里云管理控制台,打开SSL证书管理 选择免费证 ...