[6.s081]Lab System Calls

Overview

This lab intends to teach us how to implement basic system calls, and how to read/write data between the kernel space and the user space. https://pdos.csail.mit.edu/6.S081/2021/labs/syscall.html

System Call Tracing

Implements a simple tracing user program, which can tell the kernel to print the system call info when the call is made. I added a field in the process field and check this when the calls get executed. If the calls are the ones we are going to trace, print the names and the pid.

// sysproc.c
uint64
sys_trace(void) {
    int trace_bitmask;
    if(argint(0, &trace_bitmask) < 0) {
        return -1;
    }
    myproc()->trace_bitmask = trace_bitmask;
    return 0;
}

// syscall.c
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]();
        if(((1 << num) & p->trace_bitmask) != 0) {
            printf("%d: syscall %s -> %d\n", p->pid, name_map[num], p->trapframe->a0);
        }
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}

Adding a system call requires several steps: 1. Add the call stub in the user space(user/user.h, user/usys.pl) 2. Implement the call in the kernel space(kernel/sysproc.c, kernel/syscall.c) 3. When implementing the system call, using argint() or argaddr() to get the parameter you passed in. Since they will be copied to the corresponding kernel stack's register.

Getting the infomation we want to print is simple, we can obtain the current process info by invoking myproc().

Sysinfo

Similar to the last one. We need to first implement two helper functions to get the info we need:

// proc.c
uint64
freeprocs(void)
{
    struct proc *p;
    uint64 res = 0;
    acquire(&pid_lock);
    for(int i = 0; i < NPROC; ++i) {
        p = &proc[i];
        if(p->state != UNUSED) {
            res++;
        }
    }
    release(&pid_lock);
    return res;
}

// kalloc.c
uint64
freebytes(void)
{
    struct run *r;
    uint64 res = 0;
    acquire(&kmem.lock);
    r = kmem.freelist;
    while(r) {
        res += 4096;
        r = r->next;
    }
    release(&kmem.lock);
    return res;
}

Then implement the system calls in kernel/sysproc.c:

uint64
sys_sysinfo(void)
{
    uint64 addr;
    if(argaddr(0, &addr) < 0) {
        return -1;
    }
    struct proc *p = myproc();
    struct sysinfo info;
    info.freemem = freebytes();
    info.nproc = freeprocs();
    if(copyout(p->pagetable, addr, (char *)&info, sizeof(info))<0) {
        return -1;
    }
    return 0;
}