Project 2
250 points
Due by 11:59pm on May 4, 2012.
In Project 2, you will create a new custom kernel by adding some new system calls to the 3.0.4 Linux Kernel, and write a small program to test these system calls.
If you are using VirtualBox, we would suggest taking a snapshot of the current state of your VM. This will help you quickly restore your VM to a previous state if you run into any problems with the kernel during your project.
Before you begin, create a custom kernel specific for Project 2 by creating a new working copy /usr/src/project2 of the kernel sources from the 3.0.4 vanilla linux kernel sources. Then update your /usr/src/linux symlink to point to /usr/src/project2.
Hereafter let $linux stand for the /usr/src/linux directory with the working copy of the kernel sources.
Name your custom kernel for Project 2 as 3.0.4-GLUSERNAME-cs421prj2, where GLUSERNAME is your UMBC GL username.
Ways to Lose Points before your project is even tested:
- You will lose points if you do not follow directions and name the patch file correctly
- You will lose points if you do not follow directions and name your functions as specified
- You will lose points if you do not follow directions and your patchfile is too large (>1MiB) -- A new ignorelist for this project is included here.
- You will lose points if you do not use the correct kernel sources (you should be using the same vanilla sources as were used in Project 1).
- You will lose points if you include the helloWorld syscall that is usually a stepping stone and described in the tutorial provided (the only syscalls added to your kernel should be the seven described in the next section)
Part 1: Add the system calls to the kernel
You will add a few new system calls for managing mailboxes. Those mailboxes are to be used for asynchronous communication by processes in the system. The mailboxes and their contents all exist only in the Kernel address space. You will develop the system calls specified below in order to access the mailboxes and their contents by user processes.
You can make the following assumptions. There are at most 256 mailboxes, and each mailbox is identified by an unsigned (long) integer. Each mailbox can hold up to 128 messages which are to be retrieved in a FIFO order. The content of each message is a null-terminated string of at most 512 bytes (including the null).
The signature and semantics for your system calls must be:
- long mkMbox421(unsigned long mbxID) that creates a new empty mailbox with ID mbxID, if it does not already exist, and returns 0.
- long rmMbox421(unsigned long mbxID) that removes mailbox with ID mbxID, if it is empty, and returns 0.
- long countMbox421() that returns the number of existing mailboxes.
- long listMbox421(unsigned long *mbxList, unsigned long K) that returns a list of up to K mailbox IDs in the user-space variable mbxList. It returns the number of IDs in mbxList.
- long sendMsg421(unsigned long mbxID, char *msg, unsigned long N) that appends the string message msg of length N to the (pre-existing) mailbox mbxID. It returns the number of characters of the message successfully copied to the mailbox.
- long receiveMsg421(unsigned long mbxID, char *msg, unsigned long N, unsigned char flag) that copies up to N characters from the first message in the mailbox mbxID to the user--space string variable msg, and then removes the message from the mailbox if flag is non-zero. It returns the number of characters successfully copied.
- long countMsg421(unsigned long mbxID) that returns the number of messages in the mailbox mbxID.
Each system call returns an appropriate non-negative integer on success, and a negative integer on failure which indicative of the error that occurred.
Make sure that your system calls have exactly the same signatures as above, (since otherwise our test programs will fail, and thus your assignment as well!) Function/variable names are case sensitive (CASE does matter!!). In addition, you MUST keep the functions in the order above in the syscall table. Any kernel panics/failures will result in a very substantial reduction of points.
Part 2: User mode driver and test programs
Write two user mode driver programs (sendDriver and receiveDriver) to demonstrate that your system calls work correctly.
- The sendDriver takes a command-line argument mbxID. It reads a string message (until EOF) and sends it to the mailbox mbxID. It informs the user on stderr of the number N of characters successfully send, and then it prints on stdout the prefix of length N of the message. It prints an appropriate error message on stderr if an error occurred.
- The receiveDriver takes three command-line arguments: mbxID, N, and flag. The driver is to receive up to N characters from the next message in the mailbox mbxID, and remove from the message from the mailbox if flag is positive. It informs the user on stderr of the number K of characters successfully received, and then it prints on stdout the contents of the message received. It prints an appropriate error message on stderr if an error occurred.
Note that you should use your own test program to test your system calls, to ensure that they work as specified and they can handle all kinds of (good and bad) inputs.
Hints & References
- Creating A Simple System Call in the 3.0.4 Linux Kernel
- Kernel Korner: System Calls
- Recall that a system call is a software trap or interrupt. This means that when adding a new system call, you will need to update the system call dispatch table (i.e. the interrupt vector) with new entry/entries, and generate stub(s) that will be used by user programs. Look at files $linux/arch/x86/kernel/syscall_table_32.S and $linux/arch/x86/include/asm/unistd_32.h, the directory $linux/include/linux.
- You should always check the validity of addresses in the user address space passed to your system calls, and use appropriate functions from the Kernel API whenever transfering data between kernel and user address space (see User Space Memory Access, the Kernel API, and related links in Dr. Kalpakis' Class Linux Resources and the resources from last semester's CMSC421).
- In the critical section of the code you write (e.g. when you access the new kernel variables), you should try to avoid any race conditions by using appropriate kernel locking.
- Refer to the "Kernel Synchronization" chapter in ULK as well as the Unreliable Guide To Locking.
What to submit
You should submit the following items in a project2 directory in your Git repository:
- The patch patchprj2.diff generated to patch the kernel sources.
- All of the source code for your driver programs, as well as a Makefile to build each one (please place these in their own subdirectories within the project2 directory)
- Any updated or added kernel source files (in case your patch fails for some reason). You may use subdirectories as needed here.
- A README describing (in detail) your approach to the project, as well as where each of the files that you included in the above item go in the kernel source tree. If you use any resources not linked to from this project, please cite them in your README as well.
- A typescript showing the execution of your driver programs.
It is important that you follow the guidelines for what to submit above, as well as the guidelines for assignments stated in the syllabus. Failure to do so may result in 0 points for the assignment.
Please be sure that ALL of the required files are in your repository before the due date and that you pushed them to the server using git push. No excuses will be accepted if the files are not on the server when the project is due! Please double-check that you have submitted the assignment properly (re-clone your repository to check it).