NEXT UP previous
Next: Adding New Calls

System Call Mechanism

So, why am I telling you all this? Well, under Linux, system calls are implemented as one of the exception types which can be generated by executing an appropriate machine code instruction. One of the important side effects of generating an interrupt or an exception is that the system automatically gets switched from user mode into kernel mode to deal with it. This means that executing the system call exception instruction will automatically switch the system into kernel mode and arrange to execute an exception handler which knows how to deal with the call.

The actual instruction used by Linux to perform the system call exception is:

	int	$0x80

This uses interrupt/exception vector number 128 (80 hex) in order to pass control to the kernel.

In order that you do not need to do any machine code programming when you make a system call, the standard C library contains a short routine for each system call which does the machine code bit for you. In fact, the machine code bit is quite straightforward; all that happens is that any parameter values to be passed into the system call are loaded up into CPU registers and then the int 0x80 instruction is executed. The system call will then be run and any return value from the call will be returned in one of the CPU registers. The standard library routine takes this return value and arranges for it to be passed back to your code.

In order to make easy the task of executing a system call manually, Linux provides a set of pre-processor macros which can be used from within your own code. These macros take parameters which, when the macro is expanded, will tailor the expansion so that it becomes a specific function for calling a particular system call.

These macros all have names of the form:

	_syscallN(parameters)

where N is replaced by the number of parameters the system call will take, and parameters is replaced by a set of parameters which tailor the expansion for a particular system call. For example, in order to create a function to call the setuid() system call you would use the _syscall1() macro as follows:

	_syscall1(int, setuid, uid_t, uid)

The first and second parameters to any of the _syscallN() macros are the return type that the generated function will give (int here) and the name of the generated function itself (setuid here).

After that, for each parameter value that the system call takes, the associated _syscallN() macro has two extra parameters, which specify the type and the name of each system call parameter (uid_t and uid in the example).

One restriction on the data types that can be used as system call parameters is that they must not be more than 4 bytes in size because, when the int 0x80 instruction is executed to make the call, the values of the parameters are all stored in 32-bit CPU registers. Another limitation due to using CPU registers to pass the parameters is that there is a maximum number of parameters which can be passed into a system call. This limit is five, so that there are only six different _syscallN macros defined (_syscallO() to _syscall5()).

Once the expansion of one of the _syscallN() macros has been performed with an appropriate set of parameters for a particular system call, the result is a function with the name of that system call which can be run from user programs to execute that call.


NEXT UP previous
Next: Adding New Calls