22-10-2012, 11:28 AM
System calls, exceptions, and interrupts
System calls,.pdf (Size: 149.04 KB / Downloads: 148)
An operating system must handle system calls, exceptions, and interrupts. With a
system call a user program can ask for an operating system service, as we saw at the
end of the last chapter. Exceptions are illegal program actions that generate an interrupt.
Examples of illegal programs actions include divide by zero, attempt to access
memory outside segment bounds, and so on. Interrupts are generated by hardware devices
that need attention of the operating system. For example, a clock chip may generate
an interrupt every 100 msec to allow the kernel to implement time sharing. As
another example, when the disk has read a block from disk, it generates an interrupt to
alert the operating system that the block is ready to be retrieved.
In all three cases, the operating system design must range for the following to
happen. The system must save user state for future transparent resume. The system
must be set up for continued execution in the kernel. The system must chose a place
for the kernel to start executing. The kernel must be able to retrieve information about
the event, including arguments. It must all be done securely; the system must maintain
isolation of user processes and the kernel.
To achieve this goal the operating system must be aware of the details of how the
hardware handles system calls, exceptions, and interrupts. In most processors these
three events are handled by a single hardware mechanism. For example, on the x86, a
program invokes a system call by generating an interrupt using the int instruction.
Similarly, exceptions generate an interrupt too. Thus, if the operating system has a
plan for interrupt handling, then the operating system can handle system calls and exceptions
too.
Code: The first system call
The last chapter ended with initcode.S invoke a system call. Let’s look at that
again (6712). Remember from Chapter 2 that the process pushed the arguments for an
exec call on the process’s stack, and system call number in %eax. The system call
numbers match the entries in the syscalls array, a table of function pointers (2850). We
need to arrange that the int instruction switches the processor from user space to
kernel space, that the kernel invokes the right kernel function (i.e., sys_exec), and
that the kernel can retrieve the arguments for sys_exec. The next few subsections describes
how xv6 arranges this for system calls, and then we will discover that we can
reuse the same code for interrupts and exceptions.
Code: Assembly trap handlers
Xv6 must set up the x86 hardware to do something sensible on encountering an
int instruction, which the hardware views as an interrupt, initiated by a program.
The x86 allows for 256 different interrupts. Interrupts 0-31 are defined for software
exceptions, like divide errors or attempts to access invalid memory addresses. Xv6
maps the 32 hardware interrupts to the range 32-63 and uses interrupt 64 as the system
call interrupt.
On the x86, interrupt handlers are defined in the interrupt descriptor table (IDT).
The IDT has 256 entries, each giving the %cs and %eip to be used when handling the
corresponding interrupt.
Tvinit (2566), called from main, sets up the 256 entries in the table idt. Interrupt
i is handled by the %eip vectors[i]. Each entry point is different, because the x86
provides does not provide the trap number to the interrupt handler. Using 256 different
handlers is the only way to distinguish the 256 cases.
Code: System calls
For system calls, trap invokes syscall (2874). Syscall loads the system call
number from the trap frame, which contains the saved %eax, and indexes into the system
call tables. For the first system call, %eax contains the value 9, and syscall will
invoke the 9th entry of the system call table, which corresponds to invoking sys_exec.
Syscall records the return value of the system call function in %eax. When the
trap returns to user space, it will load the values from cp->tf into the machine registers.
Thus, when exec returns, it will return the value that the system call handler returned
(2880). System calls conventionally return negative numbers to indicate errors,
positive numbers for success. If the system call number is invalid, syscall prints an
error and returns –1.