Adding a System Call to the Kernel

CS 325

*** Note that all relative paths below are relative to the root of your kernel
source tree. ***

First, we add a new system call number.  Edit include/asm-x86/unistd_32.h
Following the line:

   #define __NR_inotify_init1      332

Add a similar line:

   #define __NR_lab_sysc1          333

Save the file.  Now, we have to add an entry to the syscall table.  Edit
arch/x86/kernel/syscall_table_32.S.  At the end of the file, following the
line:

   .long sys_inotify_init1

add:

   .long sys_lab_sysc1

Note that what you just added is the 333rd entry in the syscall table,
matching the #define you added to unistd_32.h previously.  This is not a
coincidence.

Save the file.  Now, we need to implement our syscall function,
sys_lab_sysc1().  Create the file:

   kernel/lab_syscalls.c

Copy ALL the #include preprocessor directives from kernel/timer.c into
kernel/lab_syscalls.c.

At the end of the file, add your sycall function, sys_lab_sysc1().  (Note
that this name exactly matches the entry we added to the syscall table.
This is EXTREMELY important.)  This function should take one int parameter
and should have a return type of:

   asmlinkage int

The body of this function should use printk() to log the value of the
function's single parameter into the system log file.  (printk() behaves
similarly to printf().  Refer to the documentation for printf in Section
3 of Linux man pages.)  The function should return an integer value of 0.
Save the file.

Now, we need to edit kernel/Makefile to ensure that our source file gets
compiled into the kernel.  At the beginning of the Makefile, there is a
list of kernel object files corresponding to the kernel source files to be
compiled into the kernel.  This list is labeled obj-y.  At the end of this
list, on the same line as the other object files, add an object entry
corresponding to the source file you just created.  (Object files have a
filename extension of ".o" .)

Now, you need to write and compile a userland C program to exercise your
system call.  (I'd suggest creating a UserLandTests directory immediately
under the root of your kernel source tree to hold these programs.)
Something like the following should do the trick:

   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   #include <sys/syscall.h>
   
   #define __NR_lab_sysc1          333
   
   int main(int argc, char *argv[])
   {
     int val;
   
     if (argc != 2)
       {
         printf("One integer argument expected!!!\n");
         return 1;
       }
   
     val = atoi(argv[1]);
   
     /* Call syscall 333, the syscall we added to the kernel. */

     printf("syscall returns: %d.\n", syscall(__NR_lab_sysc1, val));
   
     return 0;
   }

Once your finish writing the program, compile it.

Return to the root of your kernel tree and build a new kernel:

   make -j 3 O=/home/kdev/build

If that goes well, install the new kernel and module files:

   sudo make O=/home/kdev/build modules_install install

Reboot.  At the GRUB screen, select your new kernel.  Open one shell and
use it to dynamically view the end of the system log file:

   sudo tail -f /var/log/messages

Run your userland test program in another shell.  The integer value you
enter should appear in the log file, and the system call should return a
value of 0.

If that suceeded, then you are now a kernel programmer!

It would probably be wise to commit to your Subversion repository the
changes you made.  From the root of your kernel source tree run this
command to see what file have been changed:

svn status

Use this command to add individual files or directories to your local
working copy of the repository:

svn add

Use this command to commit your changes to the remote repository, creating a new
revision there:

svn ci



Thomas P. Kelliher 2012-02-16
Tom Kelliher