System calls A system call is name of kernel function that is exported for user by user-space programs. A call to a kernel function is processed differently from an ordinary function call. A kernel function is called indirectly through a trap table. Thus if you write your own kernel function you will create a new entry in the trap table for your new function. If you want any user-space program to call your program you will have to provide a system call stub function (that contains a trap instruction). You can also use system_call( ) and avoid system call stub. System calls Linkage A system stub call in a user program causes an interrupt to be raised and the CPU switches to supervisor mode and begins to execute a specific location in the kernel. What would happen is that the CPU ends up executing function system_call( ) the argument to this function is an offset to the sys_call_table (defined in arch/i386/kernel/entry.S). In version 2.2.12 source code, the table is defined as follows: .data ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_call) .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork) … … // 0 // 1 // 2 Entry 1 contains address of the exit() function (the kernel function sys_exit), 2 is for fork(), and so on. Under normal process, the system_call() function saves the context of the calling function. For example if you wrote a program ‘CallFork.exe’, and that program has call to the fork() function say at line 27. Then system_call() would save the state of CallFork.exe till line 26, generally the information stored is the value of all the variables and the address of the line from where the call was made (line 27 in this case). After finishing the execution of fork(), in this case, the original state of CallFork() would be restored and the code will start executing from the next line. You should keep one thing in mind that is that the compiler does not checks for correct number of arguments or type of arguments. It simply retrieves the address of the function from the system call table and executes the function. The kernel assumes that all the arguments are correct, so it’s responsibility your responsibility to make sure you pass the correct arguments. Defining a system call number When you want to add your own system call you will have to add an entry to system_call_table for your function. To do it you would simply edit the arch/i386/kernel/entry.S file, as follows. .data ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_call) .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork) … … .long SYMBOL_NAME(sys_ni_call) .long SYMBOL_NAME(sys_my_new_call) // 0 // 1 // 2 // 190 // 191 .endr This would allow an interrupt with argument 191 to invoke a new kernel function, sys_my_new_call(). Make sure that you make a copy of the file before editing it, as you are making changes to the kernel code. You would also need superuser permission to do the copy operation. This new system call can be invoked by function syscall(), this function takes the system call table entry number and arguments as parameter and then traps (creates an interrupt) the kernel. If you want an ordinary C program to be able to call the new system call, you need to generate a system stub call. You can accomplish this by first editing include/asm/unistd.h file, as follows. #define __NR _exit #define __NR _fork #define __NR _read #define __NR _open … … #define __NR _vfork #define __NR _my_new_call 1 2 3 4 190 191 After you have edited the table you can now generate a system call stub. Generating a system call stub For creating system call stubs you would use Linux macros. You can use this macro to create stubs with zero or five parameters in kernel version 2.2 (six parameters in 2.4 ) . Consider the following example _syscall2(type, name, type1, arg1, type2, arg2); will create a stub with two parameters. type is the return type of the stub, type1 is type of arg1 and so on. These macros are defined in include/linux/uninstd.h (which includes the file include/asm/unistd.h). To create a stub with three parameters you would use _syscall3(..), and for three parameters use _syscall4(…).To create a stub with two arguments this you would write a code similar to the following code. #include … <linux/unistd.h> // Generate system call for int foo(char *baz,double bar) _syscall2(int,foo,char *,baz, double, bar); … As discussed earlier, you can use system_call(), defined in arch/i386/entry.S, to call a kernel function without generating a stub. For example if the index in sys_call_table for foo() is 193, then you call your foo() function like this: #include <sys/syscall.h> … syscall(193,&baz_arg,bar_arg); … Kernel Function Organization A kernel function is an ordinary C function compiled to execute in supervisor mode with the rest of the kernel. Other than it’s header, it requires no particular organization, since it can perform any task that it’s author chooses. Consider a simple kernel function: asmlinkage void sys_foo(void){ // Write a value to the console } Suppose a sys_foo() is a real kernel function. If a user program calls it by using system_call(), then sys_call_table[NR_foo] will have an entry for it (index value) , it will also have the entry point address for the function in memory. Entry point address is the address where the function starts in the memory. Entry point address tells the CPU where the function starts in the memory so that CPU can start reading and executing the function form that location.