xv6 MP2: Adding System Calls


In this assignment, you will learn how to:

Exercise 1: The getcount system call (15 points)

The first system call you'll add is one we'll name getcount, which, when passed a valid system call number (listed in the file "syscall.h") as an argument, will return the number of times the referenced system call was invoked by the calling process.

E.g., the following test program:

#include "types.h"
#include "user.h"
#include "syscall.h"

main(int argc, char *argv[])
    printf(1, "initial fork count %d\n", getcount(SYS_fork));
    if (fork() == 0) {
        printf(1, "child fork count %d\n", getcount(SYS_fork));
        printf(1, "child write count %d\n", getcount(SYS_write));
    } else {
        printf(1, "parent fork count %d\n", getcount(SYS_fork));
        printf(1, "parent write count %d\n", getcount(SYS_write));
    printf(1, "wait count %d\n", getcount(SYS_wait));

should produce the following output (note that each character is output with a separate call to write in xv6):

initial fork count 0
child fork count 0
child write count 19
wait count 0
parent fork count 1
parent write count 41
wait count 1


You will need to modify a number of different files for this exercise, though the total number of lines of code you'll be adding is quite small. At a minimum, you'll need to alter syscall.h, syscall.c, user.h, and usys.S to implement your new system call (try tracing how some other system call is implemented, e.g., uptime, for clues). You will likely also need to update struct proc, located in proc.h, to add a syscall-count tracking data structure for each process. To re-initialize your data structure when a process terminates, you may want to look into the functions found in proc.c.

Chapter 3 of the xv6 book contains details on traps and system calls (though most of the low level details won't be necessary for you to complete this exercise).


To test your implementation, you'll run the getcount executable (when booted into xv6), which is based on the program above. Because the program depends on your implementation, however, it isn't compiled into xv6 by default. When you're ready to test, you should uncomment the line in the Makefile following the UPROGS declaration that builds getcount (delete the '#' character in front of the string "_getcount").

Note that while getcount only prints out counts for three different system calls, your implementation should support all the system calls listed in syscall.h. Feel free to add tests to the test program, located in getcount.c, for other system calls.

Exercise 2: The v2paddr system call (25 points)

Now that you've gotten the hang of how to add a system call to xv6, we'll tackle something a bit more interesting. The v2paddr system call will accept a virtual address (in the calling process's address space), and return the corresponding physical address. If the virtual address given is invalid, the system call should return -1.

For this exercise we are not providing a test program, so you'll have to write your own and add it to the Makefile (so that it gets compiled and added to the xv6 disk image). Make sure the executable for your test program is named "v2ptest". For help, see how the getcount program used in exercise 1 was added. Your test program should demonstrate that the system call works on virtual addresses of user-level instructions and both local and global data. It should also demonstrate that it fails gracefully (returning -1) when an invalid virtual address is specified.


You should carefully read through walkpgdir in the vm.c file --- it contains just about all the logic you need to implement the meat of the system call. It would also be a good idea to check out the macros defined in mmu.h which deal with paging details.


To submit your work, make sure to git add any new source files you created (there will likely only be one -- the test program that you wrote for exercise 2), then commit and push your work to the BitBucket repository, just as you did for MP1.