In this post I would like to take you through a sequence of steps in creating your own system call in three exercises.
Exercise1: editing the kernel source so as to add new system call.
Exercies2: Compiling the modified kernel source to generate a new kernel image
Exercise3: creating an application (user space program) to access you’re newly created system call.
Exercise1
System call: Basically system calls are kernel space routines used by application to invoke kernel devices. System calls provide the interface between a process and operating system.
To edit the kernel download the source code from www.kernel.org and unzip it as follows,
$ tar xvf linux-2.6.32.tar.gz
xvf options used with tar.
(Linux-2.6.32.tar.gz is the name of the zipped folder downloaded)
Generally source is placed at the following path /usr/lib, this is a convention followed. So copy the unzipped folder to /usr/lib path.
Note: iam explaining the following steps assuming that you are at the following path /usr/src/linux-headers-2.6.32 that is in the source folder.
Check your current path using the command pwd
$ pwd
/usr/lib/linux-2.6.32
$ ls (displays the contents of source folder as shown in the below screen shot.)
Step1: Assign unique id for the new system call.
To do so open the file at the path /usr/lib/linux-2.6.32/arch/x86/include/asm/unistd-32.h and add your system call. This file contains the list of system calls each with a unique id (some thing like a count value or serial no)
Note: i am adding system call to X86 architecture as most of the desktops are with x86
Go to the end of this file and see the last system call, and if its id is say 336 then add your system call with id 336+1 that is 337 and increment the macro NR_syscalls by one, if it is 337 then make it 337+1 that is 338 . NR_syscalls hold the count of total no of system calls, as you have added one hence that has to be incremented right.
$ vim arch/x86/include/asm/unistd_32.h
Add this to file: #define __NR_mycall 337
Modify this : #define NR_syscalls 338
*save the above changes to file.
Step2: Declare system call routine prototype.
To do so open the file at the path /usr/lib/linux-2.6.32/arch/x86/include/asm/syscall.h
Note: in this file you find separate sections/ segments for 32-bit, 64-bit and a common segment for 32 & 64-bit machines. I am adding routine for new system call in the '32 & 64 bit segment' as this call can be invoked on both the machines.
$ vim arch/x86/include/asm/syscall.h
Add: asmlinkage int sys_mycall(void);
- asmlinkage is a GNU standard.
- int return type of the syscall.
- “sys” its a prefix, convention followed for system calls.
- mycall is the name of our new system call.
*save the above changes to file.
Step3: store system call address in syscall table data structure.
To do so open the file at the path /usr/lib/linux-2.6.32/arch/x86/kernel/syscall_table_32.s
This is one of the assembly sources and add this below line of code at the end of the file and even see to it that it is at the appropriate position 337.
$ vim arch/x86/kernel/syscall_table_32.s
Add: .long sys_mycall
- .long is the instruction to assembler
Step4: implement syscall routine, that is functionality to be achieved by our new system call.
To do so we go into one of the branches (directories) of the source code. Usually the system calls related to network are implemented in the /net directory and memory management calls are implemented in /mm directory and so on. I suggest to implement our new system call functionality in /kernel branch (directory) in existing sys.c file as a beginner.
Go to end of the file and add the following code, here our new system call prints the name of the application that invokes it. Here i am using a MACRO current (kernel space global pointer, I will discuss on it in further posts)
$ cd kernel
$ pwd ( to confirm the path )
/usr/lib/linux-2.6.32/kernel
$ vim sys.c
Add:
asmlinkage int sys_mycall(void)
{
printk(“New sys call invoked by %s app\n”, current->comm);
}
Note: functionality should be achieved using kernel frame work only. Prink is provided in the kernel frame work as you known by the time.
Note: here we implemented the functionality in the existing .c file to make you understand procedure in a simple way, where in we can do the same by creating our own branch in the kernel source directory, here we have to create a Makefile for our .c file and even need to make changes in the Makefile of source directory.
*save the above changes to file.