XV6 lab2 增加系统调用

发布时间 2024-01-06 11:29:33作者: ckxkexing

在本lab实验中,需要实现两个系统调用,分别为tracesysinfo

系统调用trace主要用于debug其他程序所执行的系统调用。打开trace,并通过mask设置需要观察的系统调用内容。在后续命令执行的时候,即可打印相关系统调用和其返回值。

系统调用sysinfo则用于统计空闲内存个数,以及执行的进程个数。

添加一个系统调用的基本步骤

  1. 系统调用需要提供用户态下的调用接口,需要在user/user.h文件下添加用户态函数原型。
  2. user/usys.pl文件中添加系统调用的入口。在Makefile文件中,该脚本用于生成汇编代码,将对应的系统调用号读入a7寄存器。
  3. 在内核部分,设置系统调用号,以及从系统调用号到索引的关系。在kernel/syscall.h添加新的系统调用号,并在kernel/syscall.c中建立系统调用号和函数的索引关系。
  4. 最后在kernel/sysproc文件中实现对应的系统调用(sys_trace,sys_sysinfo)等,完成具体的功能。

系统调用trace

  1. user/trace.c
  2. user/user.h
  3. user/usys.pl
  4. kernel/syscall.c
  5. kernel/sysproc.c

用户态到内核态时,由于页表不通用,寄存器也不通用。

  • 参数需要使用argaddr、argint、argstr等系列函数,从用户进程的trapframe中读取用户进程寄存器中的参数。
  • 由于页表不同,指针也不能直接互通访问,而是需要copyin、copyout方法结合进程的页表,才能顺利找到用户态指针对应的物理内存地址。完成数据的传输。

需要在proc结构中保存需要记录的系统调用,使用mask实现。

打印系统调用的实现,需要修改system call执行跳转的部分,若匹配mask,则打印该系统调用。

系统调用sysinfo

在这一部分,不仅需要添加sysinfo的调用逻辑,还需要实现系统调用的具体实现:

  • 从用户态读取保存信息的地址信息
  • 统计系统信息:空闲内存和运行程序数
  • 将信息通过copyout方法保存到用户态的空间中。
// sysinfo系统调用
uint64
sys_sysinfo(void)
{
  // 获取user sys info地址
  uint64 user_sys_info;
  if(argaddr(0, &user_sys_info) < 0)
    return -1;

  struct sysinfo kernel_sys_info;
  kernel_sys_info.freemem = k_count_free_memory();
  kernel_sys_info.nproc = count_proc();

  // 将kernel_sys_info拷贝回user空间
  if(copyout(myproc()->pagetable, user_sys_info, (char*)&kernel_sys_info, sizeof(struct sysinfo)) < 0)
    return -1;
  return 0;
}

其中k_count_free_memory()count_proc()需要分别在kernel/kalloc.ckernel/proc.c文件中实现。

// count free memory pages
uint64 
k_count_free_memory(void)
{
  uint64 res = 0;
  acquire(&kmem.lock);
  struct run *r = kmem.freelist;
  while(r){
    res += PGSIZE;
    r = r->next;
  }
  release(&kmem.lock);
  return res;
}
// count the number of processes.
int 
count_proc(void)
{
  int count = 0;
  struct proc *p;
  for(p = proc; p < &proc[NPROC]; p++) {
    acquire(&p->lock);
    if(p->state != UNUSED) {
      count++;
    }
    release(&p->lock);
  }
  return count;
}