How to Implement a System Call in FreeBSD

1. Disclaimer
No one (including the author) takes the responsibility for what might happen if you follow the instructions in this document. Use this information at your own risk.

2. Feedback
This document is always under construction. Suggestions for improvement are always welcome. Please send feedback to Saurabh Mathur at
msaurabh@www.princeton.edu

3. About system calls
TBD

4. Steps involved in impelementing a new system call in FreeBSD
Finally, we get to the point. There are three main source and header files that are associated with system calls. These are :
a) /usr/src/sys/kern/init_sysent.c
This file contains a table sysent , each entry of which stores two things : 1. the number of parameters to the system call and 2. the function that implements the system call.
b) /usr/src/sys/kern/syscalls.c
This file contains the table of names of all the system calls.
c) /usr/src/sys/sys/syscalls.h
This is the header file that contains the #defines for all system call numbers. For example getpid() has a system call number 20 that is defined as : #define SYS_getpid 20

Luckily you don't have to edit any of these files yourself to implement a new system call. The process of setting up the correct prototypes, #defines, etc is automated which will becme clear shortly. Let us take up a contrived example of implementing a fictitious and potentially useless system call : int syshello(char *) that simply returns the string "hello" in the buffer supplied.
1. Edit /usr/src/sys/kern/syscalls.master to add an entry for hello. There are multiple types of system calls:
a) STD : always included in the kernel b) COMPAT : included if COMPAT is #defined c) LIBCOMPAT : included if COMPAT is #defined and placed in syscalls.h c) OBSOL : obsolete, and is not included in the kernel. d) UNIMPL : not implemented yet and only a placeholder is provided for the system call. Each entry in the file has the following format:

systemcall_ number type namespace { systemcall_prototype } syscall_name argument_struct_name return_type

syscall_name, argument_struct_name and return value if not specified are defaulted to systemcall_prototype, 'systemcall_name'_args and int respectively if not supplied. When adding a new system call, always add it to the end of the syscalls.master file. Bump the last sytem call's number and assign it to syshello. For example's sake, let us assign number 338 to syshello. The entry for syshello in syscalls.master should look like this:

338 STD BSD { int syshello(char *buf); }


Here, the name of the system call is syshello, the argument name is syshello_args and the return type is int.
2. Run "makesyscalls.sh syscalls.master" in /usr/src/sys/kern directory. This will generate init_sysent.c, syscalls.c and syscalls.h files for you.
3. Now that you have everything in place, the only thing left is to implement the system call. It is a good idea to create a new file to implement the new system call. Basically your philosophy in kernel hacking should be : "Dont touch any existing code unless you really have to" . Believe me, it carries a lot of wisdom.Let us name our implementation file sys_hello.c. Every system call is passed two parameters : 1. pointer to struct proc and 2. pointer to the user defined system call argumet structure, which in our case is : syshello_args. The structure syshello_args should be defined by the implementor of the system call and should contain all the arguments to the system call. In our case it should have a pointer to char.
struct syshello_args
{
char *buf;
};

The system call itself should be implemented like this:
int syshello(p, uap)
struct proc* p; struct syshello_args uap;
{
sprintf(uap->buf,"Hello");
/* fill the buffer with Hello */
p->p_retval[0] = 0;
/* set the return value of the system call*/
return 0;
}
4.
Modify the Makefile to include sys_hello.c,etc and recompile the kernel.
5. Boot the new kernel and viola, we are all set. You would ofcourse, do more meaningful stuff within your system call implementation. To invoke your new system call from a user program, just use another systemcall, syscall (more info can be obtained via the man pages of syscall).