CS 1550 – Project 3: Syscalls

Due: Tuesday, November 13, 2007

Project Description

 

We know from our description of the kernel that it provides fundamental operations that help us to interact with resources. These system calls include things like read, write, open, close, and fork. With access to the source code for the Linux kernel, we have the ability to extend the kernel’s standard functionality with our own.

In this assignment we will be creating a simple interface for passing small text messages from one user to another by way of the kernel.

How it Will Work

 

There will be a userspace application called osmsg that allows a user to send and receive short text messages. To send a message the user will issue a command like:

osmsg -s jrmst106 “Hello world”

which will queue up a message to be sent to the user jrmst106 when they get their messages with the following command:

osmsg -r

This would output something like the following:

abc123 said: “Hello world”

Notice that this is more like email than instant messages, due to the fact that the recipient needs to explicitly request their messages. If there is more than one message waiting to be received, they will all be displayed at once. A message is discarded from the system after it has been read.

Syscall Interface

 

The osmsg application will do the sending and receiving of messages via two new system calls, which you will implement. The syscalls should look like the following:

asmlinkage long sys_cs1550_send_msg(const char __user *to, const char __user *msg, const char __user *from)

This function sends a single message given the three string parameters. The return value should be 0 for success, and a negative number on error.

asmlinkage long sys_cs1550_get_msg(const char __user *to,  char __user *msg,  char __user *from)

This function takes the recipient’s username as an input, and then returns via the two other parameters the message and sender. Notice that this only returns one message, but there may be many messages to deliver. The return value should be used to indicate if there are more messages to receive: 1 means to call the function again, 0 means that there are no more to deliver, and a negative number indicates an error. The msg and from pointers need to be pointing to space allocated in the user program’s address space.

Implementation

 

There are two halves of implementation, the syscalls themselves, and the osmsg program.

For the syscalls, have them modify a linked list of messages. Memory in the kernel can be allocated by kmalloc() You can make the nodes of the linked list structures with fixed sized fields. Make the fields reasonably sized however.

Because this is a memory resident data structure, the messages will not survive a reboot. This is fine. You may want to make a shell script to add a lot of messages quickly into the emulator.

Adding a New Syscall

 

To add a new syscall to the Linux kernel, there are three main files that need to be modified:

  1. linux-2.6.23.1/kernel/sys.c

This file contains the actual implementation of the system calls.

  1. linux-2.6.23.1/arch/i386/kernel/syscall_table.S

This file declares the number that corresponds to the syscalls

  1. linux-2.6.23.1/include/asm/unistd.h

This file exposes the syscall number to C programs which wish to use it


Setting up the Kernel Source (To do in recitation)

 

  1. Copy the linux-2.6.23.1.tar.bz file to your local space under /u/OSLab/username
    cp /u/OSLab/original/linux-2.6.23.1.tar.bz2 .
  2. Extract
    tar xfj linux-2.6.23.1.tar.bz2
  3. Change into linux-2.6.23.1/ directory
    cd linux-2.6.23.1
  4. Copy the .config file
    cp /u/OSLab/original/.config .
  5. Build
    make ARCH=i386 bzImage

You should only need to do this once, however redoing step 2 will undo any changes you've made and give you a fresh copy of the kernel should things go horribly awry.

Rebuilding the Kernel

 

To build any changes you made, from the linux-2.6.23.1/ directory, simply:

make ARCH=i386 bzImage

Copying the Files to QEMU

 

From QEMU, you will need to download two files from the new kernel that you just built. The kernel itself is a file named bzImage that lives in the directory linux-2.6.23.1/arch/i386/boot/  There is also a supporting file called System.map in the linux-2.6.23.1/ directory that tells the system how to find the system calls. 


Use scp to download the kernel to a home directory (/root/ if root):

scp USERNAME@thot.cs.pitt.edu:/u/OSLab/USERNAME/linux-2.6.23.1/arch/i386/boot/bzImage .

scp USERNAME@thot.cs.pitt.edu:/u/OSLab/USERNAME/linux-2.6.23.1/System.map .

Installing the Rebuilt Kernel in QEMU

 

As root (either by logging in or via su):

cp bzImage /boot/bzImage-devel

cp System.map /boot/System.map-devel

and respond ‘y’ to the prompts to overwrite. Please note that we are replacing the -devel files, the others are the original unmodified kernel so that if your kernel fails to boot for some reason, you will always have a clean version to boot QEMU.

Under some circumstances you may need to update the bootloader when the kernel changes. To do this (and you can do it every time you install a new kernel if you like) as root type:

lilo

lilo stands for LInux Loader, and is responsible for the menu that allows you to choose which version of the kernel to boot into.

Booting into the Modified Kernel

 

As root, you simply can use the reboot command to cause the system to restart. When LILO starts (the red menu) make sure to use the arrow keys to select the linux(devel) option and hit enter.

Implementing and Building the osmsg Program

 

As you implement your syscalls, you are also going to want to test them via your co-developed osmsg program. The first thing we need is a way to use our new syscalls. We do this by using the syscall() function. The syscall function takes as its first parameter the number that represents which system call we would like to make. The remainder of the parameters are passed as the parameters to our syscall function. We have the syscall numbers exported as #defines of the form __NR_syscall via our unistd.h file that we modified when we added our syscalls.

However if we try to build our code using gcc, the <linux/unistd.h> file that will be preprocessed in will be the one of the kernel version that thot.cs.pitt.edu is running and we will get an undefined symbol error. This is because the default unistd.h is not the one that we changed. What instead needs to be done is that we need to tell gcc to look for the new include files with the -I option:

gcc –m32 –o osmsg –I /u/OSLab/USERNAME/linux-2.6.23.1/include/ osmsg.c

Running osmsg

 

We cannot run our osmsg program on thot.cs.pitt.edu because its kernel does not have the new syscalls in it. However, we can test the program under QEMU once we have installed the modified kernel. We first need to download osmsg using scp as we did for the kernel. However, we can just run it from our home directory without any installation necessary.

File Backups

 

One of the major contributions the university provides for the AFS filesystem is nightly backups. However, the /u/OSLab/ partition is not part of AFS space. Thus, any files you modify under your personal directory in /u/OSLab/ are not backed up. If there is a catastrophic disk failure, all of your work will be irrecoverably lost. As such, it is my recommendation that you:

Backup all the files you change under /u/OSLab to your ~/private/ directory frequently!

Loss of work not backed up is not grounds for an extension. You have been warned.

Hints and Notes

 

Requirements and Submission

 

You need to submit:

 

Make a tar.gz file as in the first assignment, named USERNAME-project3.tar.gz

Copy it to ~jrmst106/submit/ by the deadline for credit.