mit6.s081 lab2 System calls

Posted by UseeHere on Sat, 02 Oct 2021 22:31:54 +0200

Add mit warehouse

  • Add remote
git remote add mit git://g.csail.mit.edu/xv6-labs-2020
  • Pull branch from mit
git fetch mit
git checkout syscall
chapter 2
System call tracing

Write a program to track the system call called by another program, print the syscall num and syscall num of the tracked syscall, and the return value of calling syscall. It should be noted that if trace is identified in the mask, the trace information of trace syscall also needs to be printed when trace is called for the first time

$ trace 32 grep hello README
3: syscall read -> 1023
3: syscall read -> 966
3: syscall read -> 70
3: syscall read -> 0

$ trace 2147483647 grep hello README
4: syscall trace -> 0
4: syscall exec -> 3
4: syscall open -> 3
4: syscall read -> 1023
4: syscall read -> 966
4: syscall read -> 70
4: syscall read -> 0
4: syscall close -> 0

The following modifications are mainly made:
1. Add trace program in Makefile
2. The trace program has been completed in user / trace. C, but syscall trace has not been completed, so the main work of this exercise is to complete syscall trace
3. Add a mask member to the process structure in kernel/proc.h to record which syscall s need to be tracked
3. Complete sys in kernel/sysproc.c_ trace(),sys_trace is the function actually executed by trace syscall, sys_ The main work of the trace function is to modify the mask in the process. The way to obtain the parameters of the trace syscall from the user space is to use the argint function (such as argint (0, & mask)). Argint actually obtains the register contents of the corresponding position from the process's trapframe
4. Modify fork()(kernel/proc.c) to create a new process and inherit the mask value of the parent process
5. Modify syscall()(kernel/syscall.c). The work to be done in this part is to declare an array of syscall name string s, which is used to obtain the corresponding syscall name according to syscall num. Another job is to get the mask value of the current process to determine whether the currently called syscall is tracked and print out the corresponding information if it needs to be tracked.

  • kernel/sysproc.c
uint64 sys_trace(void) {
    int mask = 0;
    if (argint(0, &mask) < 0)
      return -1;
    myproc()->mask = mask;
    return 0;
}
  • kernel/syscall.c
    Add sys_ Function declaration for systrace
extern uint64 sys_trace(void);

Add sys to the function pointer array syscalls_ Trace function pointer

[SYS_trace]   sys_trace,

Modify function syscall

char* system_call_name[] = {
    "",
    "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]();
    int mask = p->mask;
    if ((mask >> num) & 0x1) {
      printf("%d: syscall %s -> %d\n", p->pid, system_call_name[num], p->trapframe->a0);
    }
  } else {
    printf("%d %s: unknown sys call %d\n",
            p->pid, p->name, num);
    p->trapframe->a0 = -1;
  }
}
  • Added in kernel/syscall.h
#define SYS_trace  22
  • Add in user/user.h
int trace(int);
  • Added in usys.pl
entry("trace");

usys.pl generates the contents of system call under user mode, specifically setting the corresponding syscall num to register a7, and then calling ecall

Sysinfo

The content of this part is to implement sysinfo syscall. sysinfo is used to collect information in the system, including the size of free memory (bytes) in the system and the number of processes in the system. These two information are recorded in struct sysinfo(kernel/sysinfo.h)

  • The prototype of the user mode calling function of sysinfo is int sysinfo(struct sysinfo *). The work in this syscall is to pass in the sysinfo structure and fill the results into the sysinfo structure
  • First, add the declaration of syscall in the same steps as trace
  • Then, a function to obtain the free memory capacity is added in kernel/kalloc.c. according to other functions in kmalloc.c, a free linked list is maintained in the system, and each linked list node is a page of PGSIZE. Therefore, to obtain the free memory capacity is to traverse the free linked list to obtain the number of free linked list nodes, and the free content capacity is the number of free linked list nodes * PGSIZE, In the process of traversing the free linked list, you need to lock the free linked list
// Get free memory capacity
uint64 get_free_memory_info() {
  struct run *r;
  int freelist_size = 0;
  
  acquire(&kmem.lock);
  r = kmem.freelist;
  while (r) {
    freelist_size++;
    r = r->next;
  }
  uint64 res = freelist_size * PGSIZE;
  release(&kmem.lock);
  return res;
}
  • Add a function to get the number of process es in the system in kernel/proc.c, maintain an array struct proc proc[NPROC] in proc.c, and traverse this array. If the state of proc is not UNUSED, it indicates that this is a valid proc. Count the number of valid proc and return it
uint64 get_proc_num() {
  struct proc *p;
  uint64 proc_num = 0;
  for (p = proc; p < &proc[NPROC]; p++) {
    if (p->state != UNUSED)
      proc_num++;
  }
  return proc_num;
}
  • Declare the above two functions in kernel/defs.h
  • Implementing sys in kernel/sysproc.c_ sysinfo function. In this function, the pointer to the sysinfo structure passed in by the user (user_info) can be implemented by argaddr. First, declare a sysinfo kernel in the function_ Info, obtain the free memory capacity and the number of processes in the system through the above two functions, and fill in the kernel_info, and then the kernel_ Copy the contents of info to user_ Info involves the memory copy operation from kernel space to user space. You can refer to sys_fstat() (kernel/sysfile.c) and filestat() (kernel/file.c) use copyout to copy. The parameters of copyout are the pagetable of the current process, the target memory start address of user space, the copy memory momentum address of kernel space, and the length to be copied
uint64 sys_sysinfo(void) {
  uint64 user_info;
  if (argaddr(0, &user_info) < 0)
    return -1;
  struct sysinfo kernel_info;
  kernel_info.freemem = get_free_memory_info();
  kernel_info.nproc = get_proc_num();
  
  struct proc *p = myproc();
  if (copyout(p->pagetable, user_info, (char*)&kernel_info, sizeof(kernel_info)) < 0)
    return -1;
  return 0;
}

Topics: C