Wednesday, February 08, 2006

Adding system call to UML - Different instructions

Adding a System Call to UML

This document describes how to add a system call to User-mode Linux. The original version was written by Alexandros Karypidis. The version presented here is slightly modified to handle 2.6 kernels, specifically this is based on the 2.6.10 kernel. Furthermore, we use output from diff to show what to change.

Further information can be found here:

Define the entry point

The first thing you need to do is modify the file unistd.h in include/asm/arch. In this file, you need to add a line providing an id for your system call. Locate the bunch of lines of the form #define __NR_somename, and add a new entry for your system call. Further, you should increment the total number of available system calls as defined by NR_syscalls.

Download: diff.unistd.h
--- old/include/asm-i386/unistd.h 2005-01-10 09:08:18.000000000 +0100
+++ new/include/asm-i386/unistd.h 2005-03-03 14:33:25.366255000 +0100
@@ -294,8 +294,9 @@
#define __NR_add_key 286
#define __NR_request_key 287
#define __NR_keyctl 288
+#define __NR_somename 289

-#define NR_syscalls 289
+#define NR_syscalls 290

/*
* user-visible error numbers are in the range -1 - -128: see

Next, you must add and entry refering to your call in the system calls table. To do this, modify sys_call_table.c file in arch/um/kernel and edit the following lines:

--- old/arch/um/kernel/sys_call_table.c 2005-01-10 09:08:18.000000000 +0100
+++ new/arch/um/kernel/sys_call_table.c 2005-03-03 14:21:00.580270000 +0100
@@ -19,7 +19,7 @@
#define NFSSERVCTL sys_ni_syscall
#endif

-#define LAST_GENERIC_SYSCALL __NR_vserver
+#define LAST_GENERIC_SYSCALL __NR_somename

#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL
#define LAST_SYSCALL LAST_GENERIC_SYSCALL
@@ -51,8 +51,12 @@
extern syscall_handler_t old_select;
extern syscall_handler_t sys_modify_ldt;
extern syscall_handler_t sys_rt_sigsuspend;
+extern syscall_handler_t sys_somename;

syscall_handler_t *sys_call_table[] = {
+ /* The following line ensures that we do not get any problems with */
+ /* undefined system calls. */
+ [ 0 ... LAST_GENERIC_SYSCALL ] = (syscall_handler_t *) sys_ni_syscall,
[ __NR_restart_syscall ] = (syscall_handler_t *) sys_restart_syscall,
[ __NR_exit ] (syscall_handler_t *) sys_exit,
[ __NR_fork ] (syscall_handler_t *) sys_fork,
@@ -306,6 +310,7 @@
[ __NR_utimes ] (syscall_handler_t *) sys_utimes,
[ __NR_fadvise64_64 ] (syscall_handler_t *) sys_fadvise64_64,
[ __NR_vserver ] (syscall_handler_t *) sys_ni_syscall,
+ [ __NR_somename ] (syscall_handler_t *) sys_somename,

ARCH_SYSCALLS
[ LAST_SYSCALL + 1 ... NR_syscalls ] =

LAST_GENERIC_SYSCALL must be changed such that your new system call's id is considered to be within the allowable range.

Next, we add a declaration for your system call in the area where all the other system calls are defined.

The line with [ 0 ... LAST_GENERIC_SYSCALL ] = (syscall_handler_t *) sys_ni_syscall, ensures that system calls which are in the normal kernel, but not in User-mode Linux are defined as not implemented. At least the 2.6.10 kernel are missing more than 10 system calls, and without this change, the kernel could segfault if one of the missing system calls were used.

The last change adds your system call to the system call table, such that it can be called from user space.

Having done all these, an attempt to compile the kernel should fail during linking, as the sys_somename function must now be implemented.

Implementation code

First of all, create a header file somename.h for your system call and place it in arch/um/include as shown here:

Download: somename.h
/*
* somename.h
*/

#ifndef __UML_SOMENAME_H__
#define __UML_SOMENAME_H__

extern int sys_somename(int flag);

#endif

Then, write out the implementation somename.c of your system call in arch/um/kernel as shown here:

Download: somename.c
/*
* somename.c
*/

#include "linux/kernel.h"
#include "linux/unistd.h"

asmlinkage
int sys_somename(int flag) {
printk("Hello from somename! flag=%d.\n", flag);
return 0;
}

Finally, modify the respective Makefile in arch/um/kernel and add somename.o to the list of build targets.

Download: diff.Makefile
--- old/arch/um/kernel/Makefile 2005-01-10 09:08:18.000000000 +0100
+++ new/arch/um/kernel/Makefile 2005-02-09 15:59:14.185985000 +0100
@@ -9,13 +9,13 @@
obj-y = checksum.o config.o exec_kern.o exitcode.o frame_kern.o frame.o helper.o init_task.o irq.o irq_user.o ksyms.o main.o mem.o mem_user.o physmem.o process.o process_kern.o ptrace.o reboot.o resource.o sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o - um_arch.o umid.o user_util.o
+ um_arch.o umid.o user_util.o somename.o

obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o
obj-$(CONFIG_GPROF) += gprof_syms.o
obj-$(CONFIG_GCOV) += gmon_syms.o
obj-$(CONFIG_TTY_LOG) += tty_log.o

Creating a stub for your system call

The listing below shows a program which uses the _syscall macro to create a stub for the system call. It then proceeds to call the stub function. When compiling, be sure to specify the -I option so that gcc will look at the modified version of unistd.h. In the example, the preprocessor looks for the file in asm/arch/unistd.h, so if the UML code is in the directory /uml-code you should compile with -I/uml-code/include.

Download: test_somename.c
/*
* test_somename.c
*
* Note: should be compiled with:
* gcc -I path.to.kernel.tree/linux-2.6.10/include -o test_somename test_somename.c
*/

#include
#include
#include "asm/arch/unistd.h"

_syscall1(int, somename, int, flag);

int main(int argc, char** argv) {
printf("Calling...\n");
somename(1);
}

0 Comments:

Post a Comment

<< Home