Due: Friday 9/22/06
This assignment has two goals:
At the end of this assignment, here, is a list of resources, one of which is a simple function (sxtime) to return the date and time as a formatted string. We will use this function as a data source in our code below.
Here we investigate methods of moving information out of and into the kernel. Printk allows us to output information directly to the user; however, to get information to a program we use a file. The /proc filesystem has a set of kernel hooks to allow us to easily output information, and for more control we can create our own character device and implement its read and write methods.
Assignment: Create a module named sxtime which does the following:
Hand in: Makefile and sxtime.c
The basic method for entering the kernel from user space is the kernel call - e.g. in the section above, the open() and read() system calls were used. Here we implement a custom kernel call.
Since the system call list is kept in a fixed table in the kernel, this cannot be done in a module and must instead be done by modifying and recompiling the kernel itself. (see ) To hand in the assignment you will use a common method for packaging and exchanging kernel modifications, the patch.
Assignment: Add a system call, 'sxtime', which takes 3 arguments - flag, buf, and len.
If flag has any other value, return an error. (-EINVAL) As for the read() call, generate -EFAULT if necessary.
Hand in: a patch to the 2.6.15 kernel source (as distributed on the course CD) which adds this system call. Note patch instructions below. (optional) - add a configuration option which enables or disables whether the system call is compiled into the kernel.
Until Linux 2.6, system calls were implemented on x86 processors with the int 0x80 instruction. (In 2.6, on newer CPUs the sysenter instruction is used - see here for details.)
int 0x80 jumps to a particular exception address - entry 0x80 - of 256, and the other entries available for software interrupts are unused. In the following exercise we implement a new "fast trap" into the kernel using int 0x81.
Start with the following files:
You will need to get ftrap.S to compile, which should be an exercise in adding include files and #defines; arch/i386/kernel/entry.S should provide a good example. Then you need a fast_trap function - if it just does a printk indicating it ran, that should be enough - and a user-space program to invoke the trap.
struct seq_operations and initialize it with start, show, next, and stop methods.
include/linux/seq_file.h:
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
int seq_printf(struct seq_file *, const char *, ...)
struct file_operations and a struct miscdevice
struct file_operations needs open, read, and release methods, and open and read can be no-ops. The prototypes from these functions (from include/linux/fs.h) are:
int (*open) (struct inode *, struct file *);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
int (*release) (struct inode *, struct file *);
struct miscdevice you need to set .minor = MISC_DYNAMIC_MINOR, .fops to the address of your file_operations structure, and .name = "sxtime".
Error codes - in (almost?) all cases, system calls return positive or zero values for success, and negative values for errors. For a full list of error codes, look at include/asm/errno.h.
Patches - the simplest way to generate a patch is to keep two copies of the kernel source tree - a pristine one and the one you are working on. To generate the patch we then run a recursive diff:
# ls
linux-2.6.15.pristine
linux-2.6.15
# diff -Naur linux-2.6.15.pristine linux-2.6.15 > changes.patch
#
You may want to investigate the use of the following diff option:
--exclude=pattern
When comparing directories, ignore files and subdirectories
whose basenames match pattern.
The file changes.patch - the patch file - will now show the changes in any files between the two versions; in addition (the -N flag) it will contain any new files in the modified version. To apply this patch file we use the patch command, along with the '-p' option to tell it to use the path names in the diff file:
# cp -r linux-2.6.15.pristine linux-2.6.15.new-copy
# cd linux-2.6.15.new-copy
# patch -p1 < ../changes.patch
(since the new directory wasn't named 'linux-2.6.15', we couldn't use -p0. Instead we use -p1, which trims off the first directory in every path, and we change directories so the modified paths will work.) Note also that you can reverse a patch by applying the -R flag; thus applying the patch in reverse to your working tree should cause it to match the pristine tree.
The sxtime() function. This is a hack which will only work for September 2006.
#include <linux/time.h>
int sxtime(char *buf, size_t size)
{
/* 1/1/70 was a Thursday. */
static char *days[] = {"Thu", "Fri", "Sat", "Sun", "Mon", "Tue", "Wed"};
int n = xtime.tv_sec - 4*3600; /* adjust for GMT->EDT */
int s = n % 60; n = n / 60;
int m = n % 60; n = n / 60;
int h = n % 24; n = n / 24;
int dow = n % 7;
int date = n - 13391; /* crude hack - works for 9/2006 */
return snprintf(buf, size, "%s Sep %d %02d:%02d:%02d 2006",
days[dow], date, h, m, s);
}
There is a very simple module skeleton elsewhere on this site, here.
After looking at that, you may want to refer to the Kernel Module Programming Guide:
In particular:
For the /proc file interface, look at this first (esp. the last para.)
then you can check the LMPG at:
To create and register a character device:
Note in particular any information on copying back and forth between kernel and user space.
note - if you follow the proceeding instructions exactly, you'll have to find out the device major number and create /dev/sxtime manually, or else do a lot of nonsense with class_device_create(). Use misc_register(), instead, as shown in this rather dated article, and everything will be done for you.
There is a description of how to modify system calls in the KMPG here:
Note that this describes "hooking" an existing call. We are going to add a syscall - most of the explanation from the KMPG is still applicable, but the steps are:
Send me a note if you try this section and are having trouble.