Skip to content

February 25, 2009

5

How to create a system call for FreeBSD kernel

by Joe Kuan

FreeBSDThis is a short note on how to create a system call for FreeBSD.  First of all, assume that you already have a kernel function that you would like to call. Let gives a more complicate example than just hello world.

int kfoobar(int inBufSz, char *inBuffer, int *outBufSz, char *outBuffer);

Basically, the kfoobar function takes inBuffer with size inBufSz and outputs the result into the pre-allocated outBuffer. The outBufSz is a value-return parameter. 

The system call protocol for kfoobar is simply a wrapper: 

int syscall_kfoobar(int inBufSz, char *inBuffer, int *outBufSz, char *outBuffer);

Do the following steps to create a system call:

Step 1: Edit /usr/src/sys/kern/syscalls.master file with the system call protocol. The file itself is well explained. In this case, following code is added. The value 456 is the system call id and also an incremental value from previous system call, don’t assign your own value.

456  AUE_NULL  MSTD  { int syscall_kfoobar(
                                    unsigned int inBufSz,
                                    char *inBuffer, 
                                    unsigned int *outBufSz,
                                    char *outBuffer); }

Note that for FreeBSD 6.X, it is MSTD, and STD for FreeBSD 7.X.

Step 2: run ‘make sysent‘ in /usr/src/sys/kern directory, it will do the rest of creating system call protocol for you. You should see the following output:

mv -f init_sysent.c init_sysent.c.bak
mv -f syscalls.c syscalls.c.bak
mv -f ../sys/syscall.h ../sys/syscall.h.bak
mv -f ../sys/syscall.mk ../sys/syscall.mk.bak
mv -f ../sys/sysproto.h ../sys/sysproto.h.bak

sh makesyscalls.sh syscalls.master

Eg in /usr/src/sys/sysproto.h, you should see the following code generated
struct syscall_kfoobar_args {
     char inBufSz_l_[PADL(unsigned int)]; ....
     .....
};
....
int    syscall_kfoobar(struct thread *, struct syscall_kfoobar_args *);

Step 3: Implement the syscall_kfoobar function. Here is a reference of the psuedo code. Make sure you use copyin and copyout functions to transport data between kernel and user space.

#ifndef _SYS_SYSPROTO_H_
struct syscall_kfoobar_args {
  unsigned int inBufSz;
  char *inBuffer;
  unsigned int *outBufSz;
  char *outBuffer;
};
#endif

MALLOC_DECLARE(M_FOOBAR)
int syscall_kfoobar(struct thread *td, struct syscall_kfoobar_args *uap) {
char *kInBuf = (char *) malloc (sizeof(char) * uap->inBufSz, M_FOOBAR,
                                                                  M_NOWAIT | M_ZERO);
    char *kOutBuf = (char *) malloc (sizeof(char) * 1024);
    unsigned int kOutBufSz = 1024;
    copyin(uap->inBufSz, kInBuf, uap->inBufSz); 
    int rc = kfoobar(inBufSz, inBuffer, &kOutBufSz, kOutBuf);
    int outBufSz = (kOutBufSz > uap->outBufSz) ? uap->outBufSz : kOutBufSz;
    copyout(kOutBuf, uap->outBuffer, outBufSz);
    *(uap->outBufSz) = outBufSz;
    free(kInBuf, M_FOOBAR);
    free(kOutBuf, M_FOOBAR);
    return rc;
}

You may want to add some error checking code on the size to avoid excessive memory allocation.

Step 4: Compile the kernel and install the new image.

User space system call

In the user space, you have to issue the system call with the number because it is not built into C library. The

char inBuff[1024], outBuff[1024];
unsigned int inLen = 1024, outLen = 1024;
int rc;

rc = __syscall(456, inLen, inBuff, &outLen, outBuff);

I work for iTrinegy and here are my other FreeBSD blogs

Advertisements
5 Comments Post a comment
  1. Feb 25 2009

    Very technically deep and informative, great post!

    Reply
  2. SONU
    Feb 27 2012

    In step 3 :: where I have to implement this function. In which folder and file????

    Reply
    • Joe Kuan
      Feb 27 2012

      Sorry, it was quite a while ago I did this and I have handed over the project to someone else. So I don’t have the code with me to lookup. However, from my vague memory, first I think you need to get your kernel build from source working. (Look for FreeBSD compile kernel documentation).

      Then (I think) u just simply by add the implementation file into where is most appropriate to your need. For instance, we specialised in networking, ‘/usr/src/sys/net/foobar.c’ contains the syscall implementation with other code.

      Once you have added the file into the kernel source, u need to tell the build system the location of the new file. Edits ‘/usr/src/sys/conf/files’ file and adds the line something like that

      net/foobar.c

      Then rebuild the kernel again

      Reply
  3. SONU
    Feb 27 2012

    I am adding simple “Hello World” system call. If you have the code post here….

    thanx for the reply

    Reply
  4. Plaristote
    Sep 24 2012

    I think it’s not /usr/src/sys/sysproto.h, but /usr/src/sys/sys/sysproto.h, isn’t it ?
    Also, thanks for the article. It’s impressive how easy it is to do such things in the BSD kernel.

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: