Let's use the
fork system call as an example. For convinience, let's assume
$OS161_SRC is your os161 source root directory.
How is a system call defined?
Take a look at
$OS161_SRC/user/lib/libc/arch/mips/syscalls-mips.S. We can see
that a macro called
SYSCALL(sym, num) is defined. Basically, this macro does
a very simple thing: fill
SYS_##sym and jump to the common code at
__syscall. Two points to note here:
SYS_##symis a little compiler trick.
##symwill be replaced by the actual name of
sym. In our case (
SYSCALL(fork, SYS_fork)), here
SYS_##symwill be replaced by
SYS_fork. See this gcc document if you want know more details about it.
The second argument of the macro,
num, is unused here.
__syscall, the first instruction is the MIPS syscall instruction.
We'll discuss the details of this instruction later.
After this, we check
$a3 value to see if the syscall is successful and store
the error number (
errno if not.
$OS161_SRC/build/user/lib/libc/syscall.S is generated according to
$OS161_SRC/user/lib/libc/arch/mips/syscall-mips.S during compiling, and this
file is the actual file that be compiled and linked to user library. We can
see that besides the
SYSCALL macro and the
__syscall code, declarations of
all the syscalls are added here. So when we call
fork in user program, we
actually called the assembly functions defined in this file.
How a system call get called?
syscall instruction will cause a software interruption. (See
MIPS syscall function). After this instruction, the hardware
will automatically turn off interrupts, then jump to the code located at
$OS161_SRC/kern/arch/mips/locore/exception-mips1.S, we can
mips_general_handler is the code that defined at
The assembly code here do a lot of stuff that we don't need to care. All we
need to know that they will save a trapframe on current thread's kernel stack
$OS161_SRC/kern/arch/mips/locore/trap.c. Then if this
trap (or interruption) is caused by
$OS161_SRC/kern/arch/mips/syscall/syscall.c to handle. Then
we go to our familiar
syscall function, we dispatch the syscall according to
the call number, then collect the results and return. If every thing is OK, we
go back to
mips_trap, then to the assembly code
common_exception and then
go back to user mode.
How to add a system call
To add a system call, a typical flow would be:
- Add a case branch in the syscall function:
case SYS_fork: err = sys_fork(&retval, tf); break;
Add a new header file in
$OS161_SRC/kern/include/kern, declare your
Include your header file in
$OS161_SRC/kern/include/syscall.hso that the compiler can find the definition of
Add a new c file in
$OS161_SRC/kern/syscall, implement your
Add your c file's full path to
$OS161_SRC/kern/conf/conf.kernso that your c file will be compiled. See
runprogram.centries in that file for examples.
$OS161_SRC/kern/conf, reconfigure the kernel:
$ ./config ASST3