Adding a system call to Linux

These are *old* notes (2010 or so). I remember doing this, and it was interesting enough that I thought I should post it. It may be easier now.

I experimented with the following on CentOS 5.1 running on an i686 machine.

Firstly, I visited http://www.kernel.org/pub/linux/kernel/v2.6/ and explored available kernel source codes and decided to download 2.6.18.8. gcc was already installed on my system, so I skipped that step.

In the terminal…

#cd /usr/src
#tar -xjvf linux-2.6.18.8.tar.bz2

The source code was uncompressed into the directory /usr/src/linux-2.6.18.8. I used the configuration of my current kernel as a basis of my new kernel. So, I copied the existing configuration to /usr/src/linux-2.6.18.8 by…

#cd /usr/src/linux-2.6.18.8
#make clean && make mrproper
#cp /boot/config-`uname -r` ./.config

I also could have used…

#cp /boot/config-2.6.18-53.el5 ./.config

…instead of the last command.

I chose to use menuconfig out of three possibilities: menuconfig, xconfig, gconfig

#make menuconfig

…which brought up the kernel configuration menu. I selected the option “Load an Alternate Configuration File”, typed “.config” and confirmed this (this is the .config file we copied from our current kernel’s configuration file).
Then I selected “General setup”, “Local version – append to kernel release”, respectively and typed “-blm334” which would be appended to the end of my newly created kernel. Then I exited by saving this new kernel configuration.

Next was modifying the source code to add the system call “helloworld”.
I opened the file /usr/src/linux-2.6.18.8/include/asm-i386/unistd.h and added the line:

"#define __NR_helloworld 318"

Additionally, I incremented the number of system calls. I changed

"#define NR_syscalls 318" as "#define NR_syscalls 319"

I opened the file /usr/src/linux-2.6.18.8/arch/i386/kernel/syscall_table.S and appended the line:

" .long sys_helloworld"

Then I needed to choose a place for my system call source code. Although it was not reasonable, since fs/ includes the calls about the file system, I chose to insert it into /usr/src/linux-2.6.18.8/fs/.

I created a file “helloworld.c” and inside it, I wrote:

#include 
#include 

asmlinkage int sys_helloworld() {
  printk( KERN_EMERG "hello world!" );
  return 1;
} 

There was just one thing left before compiling the new kernel, modifying the Makefile, at which I got stuck indeed. I appended “helloworld.o” to the obj-y list so that it was finally:

obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
ioprio.o pnode.o drop_caches.o splice.o sync.o helloworld.o

I returned to the terminal, inside the directory /usr/src/linux-2.6.18.8

#make
#make modules
#make modules_install
#make install

…which built the kernel, built the kernel modules, installed the kernel modules and installed the kernel, respectively. After hours of waiting for the compilation process, and relatively short installation process, I had the files

-rw-r--r-- 1 root root 64551 Nov 12 09:46 config-2.6.18-53.el5
drwxr-xr-x 2 root root 4096 Mar 21 00:32 grub
-rw------- 1 root root 2410234 Mar 20 22:30 initrd-2.6.18-53.el5.img
-rw------- 1 root root 2343918 Mar 21 00:23 initrd-2.6.18.8-blm334.img
-rw-r--r-- 1 root root 80032 Nov 23 01:24 message
-rw-r--r-- 1 root root 87586 Nov 12 09:46 symvers-2.6.18-53.el5.gz
lrwxrwxrwx 1 root root 32 Mar 21 00:21 System.map -> /boot/System.map-2.6.18.8-blm334
-rw-r--r-- 1 root root 903969 Nov 12 09:46 System.map-2.6.18-53.el5
-rw-r--r-- 1 root root 862365 Mar 21 00:21 System.map-2.6.18.8-blm334
lrwxrwxrwx 1 root root 29 Mar 21 00:21 vmlinuz -> /boot/vmlinuz-2.6.18.8-blm334
-rw-r--r-- 1 root root 1791540 Nov 12 09:46 vmlinuz-2.6.18-53.el5
-rw-r--r-- 1 root root 1610994 Mar 21 00:21 vmlinuz-2.6.18.8-blm334

under /boot/

So, the files to boot the newly created kernel were ready. I was supposed to modify the content of the file /boot/grub/grub.conf. However, when I opened it I realized that it was automatically modified for me. The lines added were:

title CentOS (2.6.18.8-blm334)
root (hd0,1)
kernel /boot/vmlinuz-2.6.18.8-blm334 ro root=LABEL=/ rhgb quiet
initrd /boot/initrd-2.6.18.8-blm334.img

I rebooted the system

#reboot

And selected to boot my newly created kernel from the booting menu. When the system was up, I checked it by

#uname -r
2.6.18.8-blm334

Finally, I wrote a test program to see whether my system call was working properly. Inside hello.c:

#include 
#include 
#include 
#include 
#define __NR_helloworld 318

int main()
{
printf( "%d\n", syscall( __NR_helloworld ) );

return 0;
} 

And I compiled it

#cd /root/Desktop
#gcc -o hello.o hello.c
#./.hello.o

Inside /var/log/messages was

Mar 21 01:41:36 localhost kernel: hello world!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.