Adding Syscalls to Xv6

Written on: May 08, 2016

Background

Xv6 is a very popular simple operating system used in many undergraduate Operating Systems courses. One of the foundations of the interactions that happen within an operating system is system calls and adding a system call to the OS is usually one of the first tasks given to someone starting out. If you came here looking for solutions to your assignment I highly recommend closing this tab and working it out on your own; I guarantee you it’s not as difficult as it seems.

I’ll be walking through the steps of how to add a syscall to Xv6 by adding a syscall called random which will return the random number 4.

Jump to explanation

What files to change

In order to add a working system call to your operating system you will need to edit the following files:

We’ll add our actual syscall to sysproc.c but you can also append it to any other files that contain syscalls like sysfile.c

syscall.h

syscall.h contains the syscall numbers for each syscall in the OS.

At the bottom we’ll add our new syscall with the next available number:

#define SYS_fork    1
#define SYS_exit    2
#define SYS_wait    3
#define SYS_pipe    4
#define SYS_read    5
#define SYS_kill    6
...
#define SYS_mknod  17
#define SYS_unlink 18
#define SYS_link   19
#define SYS_mkdir  20
#define SYS_close  21
#define SYS_random 22

syscall.c

syscall.c contains the functions used by syscalls to get arguments. We’ll add our syscall to the array of syscalls. Remember that we defined SYS_random as 22 which corresponds to that spot in the array.

static int (*syscalls[])(void) = {
    [SYS_fork]    sys_fork,
    [SYS_exit]    sys_exit,
    [SYS_wait]    sys_wait,
    ...
    [SYS_mkdir]   sys_mkdir,
    [SYS_close]   sys_close,
    [SYS_random]  sys_random, // will call sys_random() when syscalls[22] is chosen.
};

We also need to add an extern function header so the syscall can actually be called here when we define it later in a different file.

...
extern int sys_unlink(void);
extern int sys_wait(void);
extern int sys_write(void);
extern int sys_uptime(void);
extern int sys_random(void);

user.h

user.h is the file used by user programs so the user can access system call. Here we’ll add our user level definition of the syscall

...
int getpid(void);
char* sbrk(int);
int sleep(int);
int uptime(void);
int random(void);

usys.S

usys.S contains a short amount of assembly code to move the number of the called syscall into the %eax register.

...
SYSCALL(getpid)
SYSCALL(sbrk)
SYSCALL(sleep)
SYSCALL(uptime)
SYSCALL(random)

sysproc.c”

sysproc.c is one of the files that contains syscalls.

int sys_random(void) {
    return 4;
}

Explanation

The process of our syscall getting executed is as follows:

  • A user program includes ‘user.h’ in their program and calls ‘random()’ to get a random number.
  • This causes a trap which ends up in usys.S. Here ‘random’ is put through the SYSCALL macro which moves the numerical value of SYS_random into %eax.
  • We set the value of SYS_random to 22 in syscall.h. The macro also sets the trap number to T_SYSCALL and returns to trap.c which branches into the syscall branch and calls syscall() which was included from ‘defs.h’.
  • We get the number stored in %eax to figure out which syscall to run from the onces defined in the system call table syscalls[] in syscall.c; in our case it would be syscalls[22] which is sys_random().
  • Finally, our system call returns a random number which happens to be 4 and returns it back through the trap frame to the calling function/program.