Adding a Custom System Call to Ubuntu Linux in [C]
REQUIRES:
Compiling a [C] program in Linux
Today we are going to add a custom “Hello World” system call to Ubuntu 9.04 Linux using the kernel version: 2.6.28-11.
First things first, we need to figure out how to get the source and build a custom kernel. Instructions for how to do this can be found in my previous post:
Compiling a UBUNTU Jaunty Jackalope Kernel
Ok, now that we know how to compile a shiny new custom kernel, we need to create our system call:
/* adding helloworld system call */
#include <linux/linkage.h>
asmlinkage int sys_helloworld() {
printk(KERN_EMERG "Hello World!/n");
return 0;
}
Now, I opted to add this to /usr/src/linux/kernel/sys.c . However, you can always create your own file and add it to the kernel’s makefile. If you decide to go down this route you are also going to need to #include <linux/kernel.h>
to the code above; the file kernel/sys.c already includes that package.
Lets explain what’s going on here a little shall we?
asmlinkage: thats there to indicate the code is written in ‘C’ as oppose to C++
printk: is used to print out kernel log messages. These messages are stored in /var/log/syslog .
KERN_EMERG: is used for logging emergency messages; these usually happen before a crash. The Kernel has 8 different types of log levels, a few others are- KERN_DEBUG, KERN_ALERT, KERN_ERR
Alright, now that we have our system call we need to let the kernel know its there and can be used.
To do this we will have to modify a few files.
Modify /usr/src/linux/arch/x86/include/asm/unistd_32.h and add, or unisted_64.h
#define __NR_helloworld 333
to the list of system call numbers. This is the system calls unique identification number.
Modify /usr/src/linux/arch/x86/include/asm/syscalls.h and add:
/* X86_32 only */
/* kernel/sys.c */
asmlinkage int sys_helloworld();
under the “/* X86_32 only */ ” comment. This registers the system call.
Modify /usr/src/linux/arch/x86/kernel/syscall_table_32.h and add:
.long sys_helloworld /* 333 */
to the bottom of the list. This also registers the system call.
Alright, now build your new modified kernel..this is going to take a while…
…
OK, SO 2 hours later…Install the new kernel and reboot.
Now we have to build a little c-program to use that shiny new system call right? *How Exciting!*
#include <sys/syscall.h>
#include <unistd.h>
#include <stdio.h>
#define __NR_helloworld 333 /* or whatever you set it in unistd.h */
int helloworld() {
return (int) syscall(__NR_helloworld);
};
main () {
printf("The return code from the helloworld system call is %d/n", helloworld());
}
Compile it and lets see what happens!
Output [Command Line]:
lee@isis:~$ ./a.out
The return code from the helloworld system call is 0
Output [/var/log/syslog ]:
May 14 23:19:02 isis kernel: [48397.527522] Hello World!
Exactly what we expected. Our program returned ‘0′ from the system call execution AND we have the output in the logs. YAY!
[NOTE]: Now, you may have issues with flushing the buffer at this step so you may have to trigger an event on the system like reset your wifi connection to actually see the print out in the log. However, having the newline at the end of the message is supposed to guarantee the flush.
Congratulations you just made your very own system call in your very own custom kernel. Mom would be so proud, if only she knew what a kernel or a system call was!
Enjoy! =)