首页 > 其他分享 >mit6.s081 lab2: system calls

mit6.s081 lab2: system calls

时间:2023-04-22 22:33:11浏览次数:53  
标签:kernel 调用 trace mit6 proc sys lab2 syscall s081

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测试结果

标签:kernel,调用,trace,mit6,proc,sys,lab2,syscall,s081
From: https://www.cnblogs.com/dreamer-q/p/17344299.html

相关文章

  • MIT6.5830-2022 Lab 1: SimpleDB
    SimpleDB组成:classes:表示fields,tuples,tupleschemas。classes:作用于tuples的谓词和条件类。methods:在硬盘上存储关系(如heapfiles),处理并发控制和事务。classes:处理tuples的操作类(select,join,insert,delete等)。bufferpool:在内存中缓存活跃的......
  • MATLAB2022b + win10 + cuda12.0 + matconvnet GPU编译
    我使用的是visualstudio2017 具体参考:https://blog.csdn.net/amyliu5200/article/details/120717854?spm=1001.2014.3001.5506但是其中我直接使用了: vl_compilenn('enableGpu',true)然后配置成功后:vl_testnn('gpu',true)则会出现:   ......
  • 含分布式电源的33节点配电网matlab模型图,支持matlab2021a版及以上版本运行
    含分布式电源的33节点配电网matlab模型图,支持matlab2021a版及以上版本运行,分布式电源可自行修改输出功率以及调整接入配电网节点的位置,联系可附含分布式电源的33节点配电网潮流计算程序以及节点电压图YID:1860675346223268......
  • mit6.s081 lab1:Unix Utilities
    1sleep(easy)要求:为xv6实现UNIX程序睡眠;睡眠需要暂停一段用户指定的时间。刻度是由xv6内核定义的时间概念,即定时器芯片两次中断之间的时间。解决的程序应该在user/sleep.c文件中。 一些小提示:查看user/中的其它程序,如echo.c,grep.c或rm.c,明白如何获取传递给程序的......
  • MIT6.1810的学习笔记
    Chapter0OperatingsysteminterfacesProcessesandmemory这一节主要了解一下基础的xv6中的systemcall其中fork是对进程本身进行操作的它复制当前进程的全部内容以及当前进程的fd表也就是说子进程会做和原进程相同的事且对相同的file进行操作。(需要注意,子进程......
  • 下载并安装matlab2018
    欢迎来到我的友链小屋下载链接:链接:https://pan.baidu.com/s/1zo_8g0iqWxEwbNa9-FesFw 提取码:4r1w 百度网盘vip:在拼多多搜索百度网盘一天vip 安装流程:http://www.zhanshaoyi.com/8567.html......
  • 《安富莱嵌入式周报》第307期:开源智能制冷板,Keil MDK6发布时间,编程助手Github Copilot
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 视频版:https://www.bilibili.com/video/BV1fV4y1X7sk 1、Keil......
  • 超简单的Matlab2022b软件切换中/英文界面方法教程(附软件下载)
    在中文Windows操作系统中,MATLAB2015b之后版本安装默认为中文版,但有部分用户还是习惯使用英文界面下的MATLAB(个人偏好),下面以R2022b版分享一下中/英文界面的切换方法,超简单。......
  • xv6 page fault —— MIT6.S081操作系统工程
    当硬件对用户使用的虚拟地址进行翻译时,若该虚拟地址不正确,比如尚未映射、权限不足等,硬件会产生一个pagefault陷阱给操作系统,就是这样一个看似简单平常的机制,却给了操作系......
  • MIT6.828_锁
    JOS中的锁JOS中只有自旋锁,用于大内核锁的实现:staticinlinevoidlock_kernel(void){ spin_lock(&kernel_lock);}自旋锁结构如下:structspinlock{ unsignedlock......