2
votes

I need to add an own system call to the Raspbian Linux Kernel. Now I am stuck after searching for about 2 days to find a solution.

To add a system call, I am basically following the general outline (http://elinux.org/RPi_Kernel_Compilation) using the kernel sources from the following git repo:

git://github.com/raspberrypi/tools.git

I have installed a cross-compile environment using crosstool-ng (http://www.kitware.com/blog/home/post/426).

All these above works. I am able to compile and deploy a new kernel. I am furthermore able to cross-compile for the Raspbian.

I am trying to add a 'hello world' system call. The function resides in its own implementation files (kernel/helloworld.?) and are implemented as:

helloworld.c:

#include <linux/linkage.h>
#include <linux/kernel.h>
#include <linux/random.h>
#include "helloworld.h"

asmlinkage long sys_helloworld(){
  printk (KERN_EMERG "hello world!");
  return get_random_int()*4;
}

helloworld.h:

#ifndef HELLO_WORLD_H
#define HELLO_WORLD_H
asmlinkage long sys_helloworld(void);
#endif

The Makefile is extended accordingly.

I am now stuck in the error message

AS      arch/arm/kernel/entry-common.o
arch/arm/kernel/entry-common.S: Assembler messages:
arch/arm/kernel/entry-common.S:104: Error: __NR_syscalls is not equal to the size of the syscall table
make[1]: *** [arch/arm/kernel/entry-common.o] Error 1

By following the advice in Writing a new system call, I added the following:

  • arch/arm/kernel/calls.S

    CALL(sys_helloworld)
    
  • arch/arm/include/uapi/asm/unistd.h

    #define __NR_helloworld                 (__NR_SYSCALL_BASE+380)
    
  • include/uapi/asm-generic/unistd.h

    #define __NR_helloworld 274
    __SYSCALL(__NR_helloworld, sys_helloworld)
    
    #define __NR_syscalls 275
    
  • arch/x86/syscalls/syscall_32.tbl

    351     i386    helloworld              sys_helloworld
    

I am now stuck in solving the error.

When removing the line in calls.S, the kernel compiles fine; though I can't invoke the system call. When adding the line stated above, I am getting the mentioned error.

For reference: The client-code for testing the system call is:

#include <linux/unistd.h>
#include <stdio.h>
#include <sys/syscall.h>

int main (int argc, char* argv[])
{
    int i=atoi(argv[1]);
    int j=-1;
    printf("invocing kernel function %i\n", i);
    j=syscall(i); /* 350 is our system calls offset number */
    printf("invoked. Return is %i. Bye.\n", j);

    return 0;
}

All other system calls (e.g., 1 == sys_exit) work fine.

Any ideas what I am missing? E.g., I don't fully get how to implement rasens answer.

1
98% of the time, adding a new syscall is the wrong way to attack whatever problem you have unless it's for learning purposes.tangrs
I am about to directly control hardware devices by interacting with system busses / proprietary hardware - I won't say that my way is perfectly wrong ... :-/user3270939
No, that's definitely the wrong way about it. Usually, if you need to control devices from userspace, you write a kernel driver that implements character device files + ioctl calls. If it's for controlling device attributes, then the sysfs framework is used. Edit: besides, when you use character device files, you get locking for free from the kernel so only one process has control of your device at any one time.tangrs
OK ... then let me just wait until all requirements are set up ... Thanks for now and for the hints!user3270939

1 Answers

5
votes

_NR_syscalls defined in arch/arm/include/asm/unistd.h file this value will always be __NR_last_syscall+1. Hence in your case _NR_syscalls should be modified to 381, but this change will also give the same error because of padding in syscall table. Hence define it to 384. This slove the compilation error. Below changes are not necessary:

include/uapi/asm-generic/unistd.h

#define __NR_helloworld 274
__SYSCALL(__NR_helloworld, sys_helloworld)

#define __NR_syscalls 275

arch/x86/syscalls/syscall_32.tbl

351     i386    helloworld              sys_helloworld