Homework 5:

Adding a System Call to Xv6

This assignment will teach you how to extend the xv6 kernel with new system calls. Specifically, we will add a system call that creates a new process and executes it from the entry point. In order to get started with it, we will need to setup Qemu and Xv6. You can follow these instructions to get them running.

Your goal is to add a new system call to the Xv6 kernel. The main point of the exercise is to learn some of the different pieces of the system call machinery.

The newproc() System Call

Name:

newproc

Synopsis:

int newproc(const char *pathname, const char** args);

Description:

Your system call will create a new process, combining the functionality of fork and exec in one single system call.

  1. pathname a valid path to the file of the program to be executed.
  2. args NULL terminated array of strings. These strings are the arguments of your program to execute. Each string is a '\0' terminated array of characters.

Return:

On successful invocation, your system call shall return the process ID of the new process.

Errors:

In case of an error, the kernel will undo the unfinished actions. If the arguments passed to the function are incorrect return -1. If there is any other error, return -2.

Considerations:

you should check that the system call's arguments are safe: e.g. pathname points to a valid binary file.

In order to test your system call we recommend you to create a user-level application newproc-test that calls newproc multiple times with correct and incorrect parameters. Your system call implementation cannot break! Please note that this user application does not implement your system call; it just tests it from the user-level perspective. You can get started with the following user application example. Feel free to extend it at your will. This file will not be graded:

// user-level application to test the "newproc" syscall #include "types.h" #include "user.h" int main(int argc, char *argv[]) { const char *args[] = {"echo", "NEWPROC_CALL", 0}; int ret; printf(1, "Test newproc syscall\n"); ret = newproc(args[0], args); printf(1, "returned: %d\n", ret); exit(); }

Including a system call will affect several files in the Xv6 source code, you will perhaps need to create new ones. Make sure of modifying the Makefile to count those potential files into the building process. In particular, the Xv6 Makefile maintains the user-level applications in the list UPROGS, and each application name on this list is the name of the source code without extension, and starting with an underscore. So to include your user-application newproc-test.c to this list, add _newproc-test to it. In this way, it will be incorporated in the file-system image of Xv6. So once you build and run Xv6 (make qemu-nox), you should be able to invoke your newproc-test program from the Xv6 shell.

The Chapter 3: Traps, interrupts and drivers in the Xv6 book will be of great help in this assignment. While reading it, make sure of following the references to the code lines in the source code listing handout to understand what the book is talking about.

The files syscall.h and syscall.c are a good starting point. The functions argXXX() present in the later one will be of great use in your system call. The Xv6 book talks about them. Additionally, there is a portion of syscall.c very interesting:

static int (*syscalls[])(void) = { [SYS_fork] sys_fork, [SYS_exit] sys_exit, ... [SYS_close] sys_close, };

It is a bit difficult to read. But you can look at the first line from inside out:

  • Is just a variable called syscalls, that is an array... syscalls[]
  • of pointers... (*syscalls[])
  • to functions... (*syscalls[])()
  • functions that receive no arguments... (*syscalls[])(void)
  • functions that receive no arguments and return integers int (*syscalls[])(void)

The following lines contain the notation [I] F,. This just to explicitly set the index I (defined in syscall.h) to the element F (function name, which acts as a pointer to itself). Oh, and the array is only known to the current file (static). Who said C was difficult?... This array should be familiar to you. If not, review the lecture notes.

Finally, note how many system call implementations start with a sanity check and arguments gathering (such as sys_exec in sysfile.c), and then the actual implementation(sys_exec ends up calling exec, which is defined in file.c). You may find this idea useful for your own implementation.

In order for Gradescope to test your system call, it will create its own custom program (maybe different from your newproc-test) and invoke your system call from it.

Hints and Strategy

To test your implementation, in the user-application newproc-test, you can call your system call, creating a well known process, like echo. Upon correct invocation, you should see the effects of echo (printing on the screen) and you should also receive the process id of echo as the return value of the system call.

We strongly recommend you to follow this two steps strategy to successfully create your newproc() system call:

Observe an existing system call

Look at all the pieces of code involved in some simple existing system call, for example uptime. Some more complex (and related to our homework) system calls are fork and exec. To search across the source code, you can make use of the tool grep, to search a text across all the source files. For example, if you want to know all the parts in which the string uptime appears, you can use:

$ cd <root directory of Xv6> $ grep -rin -C 1 -e "uptime" *.[chS]

This will, starting at the current directory:

  • -e "uptime": search for the expression "uptime"
  • -r: recursively
  • -i: in a case insensitive mode (remove it if you want to be strict)
  • -n: showing the file-name and the line number in which it appears
  • -C 1: showing 1 line before, and 1 line after the actual match to give you some context
  • *.[chS]: Restrict the search to only files ending with .c, .h, or .S

Follow the same steps

Now that you have a good idea of the parts involved, replicate all of that to create your own system call. This will maybe be adding an extra line of code here and there, adding a couple of new C files, editing some build steps, etc.

Your Assignment

Your assignment is to implement the aforementioned newproc system call, and write a short README-HW5-REQ.md file explaining what you have done and how it works.

Extra credit 1 (10%): Redirection

Extend your system call to receive two file descriptors: one for redirecting the standard input of the newly created process, and another for the standard output. The new synopsis should look like this:

int newproc(const char *pathname, const char** args, const int in, const int out);

The file descriptors must be opened before the call of newproc. If no input, or output redirection is wanted, then -1 must be passed.

Include a README-HW5-EX1.md file explaining what you have done and how it works. Modify the newproc-test tester to test this new functionality.

Submit your Work

Submit your solution (the zip archive) through Gradescope in the assignment called HW5 - System Call. Please put all the required files for each part in an independent folder. Each part must be self-contained and independent from each other.

Also, include a README-HW5-???.md in each part, explaining what you have done and how it works. If you have done extra credit then place all the required files in a new folder extra1.

Make sure of removing all compile-time generated files before submitting your work. They make the submission and grading process slower, and could induce errors during the testing/grading.

You can resubmit as many times as you wish. If you have any problems with the structure the autograder will tell you. The structure of the zip file should be the following:

homework5.zip ├── required/ │ ├── README-REQ.md # your explanation │ ├── newproc-test.c # your tester program │ ├── ... # other files you may have created │ └── ... # Xv6 files │ └── extra1/ # optional ├── README-EX1.md # your explanation ├── newproc-test.c # your tester program ├── ... # other files you may have created └── ... # Xv6 files