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).