This is a simple HOWTO that shows how to add a "Hello World" system call to the 2.6 revisions of the linux kernel. The reader is expected to know how to compile and configure their kernel and know a little bit about programming.
This HOWTO was last updated for version 2.6.28.2. If you are using a later or earlier version of the kernel, things will be slightly different. Also, if you are working with an architecture other than intel x86, you will have to do some extra work in your specific arch folder.
Before you begin, make sure that you have a fresh copy of the kernel sources. Hereafter, let $linux stand for the directory in which you have stored the kernel sources.
We will create a new system call, called hello_world, and we will assign it a new, unused system call number. The steps in doing so are outlined below:
As mentioned in the introduction, these are specific to intel 32bit x86. It should be relatively straightforward to make the right changes for your architecture. We simply need to add the name to the syscall table and a reference to the index needs to be placed in unistd:
At this point you can put your syscall inside of some other source file or put it in a file just for itself. Assuming you do the latter, your hello_world.c file should look like this:
/** * hello_world.c - The hello world system call, the best system call ever. **/ #include <linux/syscalls.h> asmlinkage long sys_hello_world() { printk("Hello World!\n"); return 0; }
If you choose to group your system call with sys_read or another system call, you can just append the above function definition to the appropriate file.
This is optional, and you only need to do it if you want to make a clean, organized, and separate modification to the kernel. If you chose to group your new syscall as previously described, your code should compile and you should be fine.
Again, we have some options here. One is to place hello_world.c in a folder we know will be compiled and to add hello_world.o to the makefile:
obj-y := hello_world.o
You should just be able to find the obj-y line and tack it on to the end. If you are confused about the syntax, you can look at other makefiles in the other directories.
If you want to place hello_world.c in a seperate folder (e.g. hello_world), you simply need to add that folder to the Kernel Makefile, and create a blank makefile in the new folder with the line as shown above.
To edit the kernel makefile, you would find:
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
And change it to:
core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ hello_world/
Compile, install, and boot to the modified kernel. You can test your new system call by using a simple driver program:
/** * hello_world_driver.c - The driver to the most awesome system call ever. **/ #include <unistd.h> #include <syscall.h> long hello_world(); int main() { hello_world(); return 0; } long hello_world() { return syscall(__NR_hello_world); }In order to get this to compile, two things must be done, first we have to make the kernel headers and install them to a location we choose and then we have to compile with a special gcc option. To make and install the headers, run make headers_check and then make INSTALL_HDR_PATH=../linux-headers headers_install in $linux. This will place the headers in $linux/../linux-headers/include.
All you have to do now is compile your driver program using the -I gcc option like so:
-I/usr/src/linux-headers/include/
Assuming your $linux is /usr/src/linux. This is necessary to make gcc include the new unistd header, but you could potentially install those headers into the default include spot (not recommended).
You may find older documentation discussing the use of the _syscallN(..) macros (where N is 0-6). Older versions of the kernel used the _syscallN(..) macros for user applications to interface with system calls. In the most recent versions of the kernel this macro based interface has been deprecated and replaced with the syscall(..) interface. The above driver program illustrates the use of this new interface.
You can check that the system call is working by examining the output of printk by using either dmesg or tail -f /var/log/messages
See Richard Carback.