Adding a new system call to the Linux kernel
Note: Please use the class discussion board (you can find
it on the class blackboard page) as a
communication and Q&A tool. Should you still need to send an
e-mail inquiry, address it to the TAs and cc the instructor.
Though adding system calls to the kernel should not be your first
choice to expand the kernel's functionality in the real world
(applications and developers expect a certain set of calls), for the
purpose of this class it will be a rather common habit. Below we
describe how to add a new system call to the Linux kernel v3.18.77 from
the kernel repository. For information on the underlying mechanisms, refer here,
as well as in the suggested class resources and of course, any internet
search engine.
We will be adding a system call named cs2456_test
which takes an integer as an argument and prints it out along
with a greeting.
Adding a new system call - the
Linux-kernel side
|
- cd linux-3.18.77
- Change your current working directory to the kernel directory.
From now on we assume you are in the kernel directory
- mkdir cs2456
- Make a new directory to host your new system call. We will call
this directory cs2456/
- vi cs2456/cs2456_test.c
- Open
a new file and add your system call there. As described, ours will be
called cs2456_test, it will
take a single argument (int) and print it along with a simple
greeting:
#include <linux/kernel.h>
asmlinkage long
sys_cs2456_test(int arg0)
{
printk(" Hello World !");
printk("--syscall arg
%d", arg0);
return((long) arg0);
}
Save your file under cs2456/
- Function printk is the kernel's analogue of
printf
- Due
to space limitations we have jmacs
in the virtual disk image but not emacs - it is Joe's editor with emacs
key-bindings and should be familiar for emacs users.
- vi cs2456/Makefile
- Open
a new Makefile to inform the kernel how to compile your new file(s).
You only need to define how the single file you created is turned into an
object file, so in this simple case
#Makefile start
obj-y := cs2456_test.o
#Makefile end
Save your file under cs2456/
- vi Makefile
- Open
the topmost Makefile and inform it of the new directory. The Makefile
will descend into it and recursively build whatever it can. To do so,
find the line where core-y is
defined (~610) and add your new directory to it:
core-y
+= kernel/ mm/ fs/ ipc/ security/ crypto/ block/ cs2456/
Save the Makefile where it was.
- vi
arch/x86/kernel/syscall_table_32.S
- Edit (with vi or any editor of your preference)
syscall_table_32.S to add a new system call function pointer. Go to the
last line and add the line
.long
sys_cs2456_test
/* 181 */
By this line you add the pointer to your function in the system-calls
table; this is system call number 181 for x86 processors.
- vi
include/asm-x86/unistd_32.h
- Edit unistd_32.h
to add your new system call number. Find where the rest of the
system call numbers are, go to the last one and add the line
#define
__NR_cs2456_test 181
Now you have defined how your system call function pointer can be referenced
from the system calls table.
Adding a new system call - the
user-level side
|
Since all the libraries we have are unaware of our new system call, in
order to test it we need to provide the user with a library call to
trigger the syscall. Boot your GNU/Linux distribution (Debian in QDGL's
case), login as a simple user and follow the procedure below.
- mkdir cs2456
- Make a new directory to host your new library call. We will
call this directory cs2456/
- cd cs2456
- Move to the new directory
- vi cs2456_test.c
- Open
a new file and add your library call declaration there.
#include <stdio.h>
#include <linux/unistd.h>
#include <sys/syscall.h>
#define _CS2456_TEST_ 327
int main(int argc, char *argv[])
{
printf("\nDiving to kernel level\n\n");
syscall(_CS2456_TEST_ , 2456);
printf("\nRising to user level\n\n");
return 0;
}
Save your file.
- gcc cs2456_test.c - o cs2456_test
- Compile
your user level syscall interface
Testing your new system call
|
- Boot your new kernel
- /usr/bin/qemu -m 64M -L ./qemu/share/qemu/ -hda hda.img
-nographic -append "root=/dev/hda1" -kernel
linux-3.18.77/arch/x86/boot/bzImage
- You should be able to verify
that this is a new kernel by checking its revision ( ex. uname -a )
- Go the directory where you stored your library interface to the
syscall and execute the test you wrote
- Your system call should now work if you try it :
- The example above printed the following output to our virtual machine:
Diving to kernel
level
[ 76.703723] Hello World !--syscall arg
2456
Rising to user level
- If you try the same system
call in the kernel that does not support it (like the default Debian
kernel), you would just see the user level printouts:
- Diving to kernel
level
Rising to user level