Programming assignment #3 - Warmup with Linux and Xen

Due by Friday, Feb 23.

The managing TA for all Xen/Linux track assignments is Hemayet Hossain. All email inquiries about this assignment should be addressed to the TA and cc the instructor. This assignment will be examined through demo with the TA. The demo time should be conducted with the TA by Friday, February 23 or earlier. We expect each demo will take 20-30 minutes. Please reserve your time slot with the TA ahead of the time.

This is a group assignment. You should form a group of two to complete this assignment. Discuss with your group members early to establish safe and flexible policies for managing your code. You are encouraged to help (and seek help from) people in other groups (except sharing code, of course). Note that we will not distinguish grades within a group.

Disclaimer: This assignment is adapted from a project developed by Dr. Jason Nieh at Columbia University.

Adding a system call

Write a new system call in Linux. The system call you write should take one argument (pointer to a data structure) and return various information for the process identified by the pid in the data structure. All return information will be put into the data structure. Note that you will be adding this system call to the linux-2.6.10-xenU kernel we provided to you. For the following discussion all relative paths refer to the top of your kernel source directory kernel/linux-2.6.10-xenU.

The prototype for your system call will be:

	int prinfo(struct prinfo *info);
    

You can define struct prinfo as

struct prinfo {
	long state;			/* current state of process */
	long nice;			/* process nice value */
	pid_t pid;			/* process id (input) */
	pid_t parent_pid;		/* process id of parent */
	pid_t youngest_child_pid;	/* process id of youngest child */
	pid_t younger_sibling_pid;	/* pid of the oldest among younger siblings */
	pid_t older_sibling_pid;	/* pid of the youngest among older siblings */
	unsigned long start_time; 	/* process start time */
	long user_time;			/* CPU time spent in user mode */
	long sys_time;			/* CPU time spent in system mode */
	long cutime;			/* total user time of children */
	long cstime;			/* total system time of children */
	long uid;			/* user id of process owner */
	char comm[16];			/* name of program executed */
};
    
in include/linux/prinfo.h as part of your solution. Note that pid_t is defined in include/linux/types.h. Sibling processes are those sharing the same parent. Young/old comparison between processes are made based their start time.

Each system call must be assigned a number. You can use any that is not yet used by the kernel. Your system call should return 0 unless an error occurs. Your code should handle errors that can occur but not handle any errors that cannot occur. At a minimum, your system call should detect whether the input prinfo structure is null and return -22 if so. The referenced error code is defined as EINVAL in include/asm/errno.h.

Hint: Linux maintains a list of all processes in a doubly linked list. Each entry in this list is a task_struct structure, which is defined in include/linux/sched.h. In include/asm/current.h, current is defined as an inline function which returns the address of the task_struct of the currently running process. All of the information to be returned in the prinfo structure can be determined by starting with current.

Another Hint: In order to learn about system calls, you may also find it helpful to search the Linux kernel for other system calls and see how they are defined. The file kernel/timer.c might give some useful examples of this. The getpid system call might be a useful starting point. The system call sys_getpid defined in kernel/timer.c uses current and provides a good reference point for defining your system call.

Important Note: When adding a system call, you need to register it in the system call table in entry.S for your architecture. For i386, you might find two such files arch/i386/kernel/entry.S and arch/xen/i386/kernel/entry.S. Although a regular kernel (not customized for Xen) only has the former file, in this case you have to work on the latter. You might also find it is readonly in default. Go ahead to make it writable.

Testing and analyzing the system call at user level

To test your system call, write a simple program that calls the prinfo system call with an input pid. Your program should print all the process state information for the calling process. Run the program several times. Which fields in the prinfo structure do not change? Which ones do and how frequent? Prepare the answers in a writeup before the demo.

Although system calls are generally accessed through a library (libc), your test program should access your system call directly. This is accomplished by utilizing the appropriate _syscall macro in /usr/include/asm/unistd.h. Which _syscall macro you use is determined by the number of arguments passed to your system call.

The output of the program should be easy to read. The ps command will provide valuable help in verifying the accuracy of information printed by your program. You can access detailed information on the ps command by entering man ps.

Help and debugging

A Linux kernel reference book would be very helpful. For instance, Chapter 4 of the Linux Kernel Development book gives detailed instructions on building a system call. You might also be able to find online help on this.

Debugging the kernel can be a pain. And it is good to build up some debugging experience now so you are better prepared to deal with more complexed programming later. You can use printk to print out stuff inside the kernel. To request printk messages be sent to a log file, insert the following line into the /etc/syslog.conf file:

	kern.*		/var/log/kern.log
This will cause printk messages to be written to /var/log/kern.log after next reboot. There are also a few kernel debuggers out there. We haven't had much luck with any of them. If you manage to get any of them working, please let us know.

Have fun hacking!!!