System Calls
System Calls are used to call a kernel service from user land. The goal is to be able to switch from user mode to kernel mode, with the associated privileges. Provided system calls depends on the nature of your kernel.
Available Methods
System Calls via Interrupts
The most common way to implement system calls is using a software interrupt. It is probably the most portable way to imlement system call. Linux traditionaly use interrupt 0x80 for this purposes.
To do this, you will have to create your interrupt handler in Assembly. This is because most, if not all, C compilers that support interrupts make the interrupt function of the form
PUBLIC IntHandler: PUSHAD ; Code POPAD IRETD
If you intend to return values to the user, usually done through EAX, this will not work. Instead, Assembly is the best way. Just call the system call, preferably written in C, as so:
PUBLIC IntHandler: CALL _CFunction ; assuming Pascal calling convention IRETD
DOS and other systems use the AX register to store the function code - AH for the service and AL for functions of the service, or AH for the functions if there are no services. For example, let's say you have read() and write(). The codes are 1 for read() and 2 for write() from the interrupt 0A9h (an arbitrary choice, possibly wrong). You can write
PUBLIC IntA9; CMP AH, 1 JNE IA9Write CALL _read JMP IA9Done IA9Write: CMP AH, 2 JNE IA9BadCode CALL _write JMP IA9Done IA9BadCode; MOV EAX, 0FFFFFFFFh IA9Done: IRETD
If you use the C calling convention, you would need different code.
Parameters are usually passed through registers such as EBX, ESI, etc.
System Calls via Sysenter/Sysexit (Intel)
On Intel CPU, starting from the Pentium II, a new instruction pair sysenter/sysexit has appeared. It allows a faster switch from user mode to kernel mode, by limiting the overhead of changing mode.
A similar instruction pair has been created by AMD: Syscall/Sysret. However the behaviour of these instructions are different from Intel's.
System Calls via Trap
Some OSes implement system calls by triggering a CPU Trap in a determined fashion such that they can recognize it as a system call. This solution is adopted on some hardware by Solaris, by L4, and probably others.
For example, L4 use a "LOCK NOP" instruction on x86. Since it is not permitted to perfrom a lock on the "NOP" instruction a trap is triggered. The problem with this approach is that there is no guarantee the "LOCK NOP" will have the same behavior on futur x86 CPU. They should probably have used the "UD2" instruction, since it is defined for this purposes.
System Calls via Call Gates (Intel)
The 80386 family of processors offer various call gates as part of the GDT. The call gate is a far pointer that can be called similar to calling a normal function. Very few operating systems use call gates.
Strategies Conlusion
The system call strategy depends on the platform. You may want to use different strategy depending on the architecture, and even switch strategy depending on the hardware performance.
On the user land side
While the developper can trigger manually the system call, it is probably a good idea to provide a library to encapsulate such a call. Therefore you wil be able to switch the system call technique without impacting the user applications.
See Also
Threads
External links
- http://en.wikipedia.org/wiki/System_call
- sysenter/sysexit, syscall/sysret details: http://www.sandpile.org/post/msgs/20003633.htm
- Solaris syscall implementation: http://blogs.sun.com/rab/entry/x86_syscall_primer
- L4 strategy: http://www.pagetable.com/?p=9
- Linux syscalls: http://manugarg.googlepages.com/systemcallinlinux2_6.html
- http://www.freebsd.org/doc/en_US.ISO8859-1/books/developers-handbook/x86-system-calls.html