On Tue Jun 14, 2005 at 13:20:25 -0400, Andrew Davenport wrote:
Regardless of the mechanism used, an IPC must be sent from the l4 u-kernel to the linux server, so the linux server can deal with the "fake intterupt" (a system call). I am using V2, so, according to previous discussion, the interrupt parameters and other data are pushed into a data structure that the l4 thread (eg the linux server) can get them after receiving the notification IPC (eg with COOKIE_1, COOKIE_2). There must be an IPC regardless of the mechnanism, is this correct? Furthermore, where is this sent in l4 and where is it handled in l4linux ?
Yes, eventually an IPC is sent in both cases. But in the idt case this IPC to the linux server is generated by user land, the kernel itself has nothing to do with generating the IPC. I thought we were talking about kernel internals.
Ok, let's concentrate on one case, l4linux 2.6, exc. IPC.
Linux program executes:
mov $20, %eax int $0x80
An exception is generated and execution is continued in the kernel at vec0d_gen_prot in entry-ia32-ux.S. There we push some things on the stack and call the trap_handler. The handler is thread-ia32-ux.cpp:thread_handle_trap() which calls thread::handle_slow_trap(). handle_slow_trap() in the same file now goes through the possible things that can happen (instruction emulation etc) and eventually comes to the
// send exception IPC if requested if (snd_exception(ts)) goto success;
lines. This path is taken in our case.
When the exception handler (same as the pager) of the faulting thread accepts exception IPC we go on in Thread::exception(). Thread::exception() is the function where the send and receive IPCs to the exception handler are set up. Also noteworthy, the utcb_handler for the faulting thread is modified to copy the trap state instead of the utcb itself. Finally, we come to do_send() where the IPC is sent to the handler. The faulting thread now sleeps waiting for do_send() to come back. When the Linux server has received the message it goes on to do_receive() waiting for a reply from the Linux server.
So, now the Linux server wakes up and receives the exception IPC. It also finds the trap state of the faulting thread in its utcb. By looking at the trap number (==13) and the error code (==0x402) it figures out that the Linux program wanted to execute an 'int80'. By looking at eax it knows that sys_getpid is requested which is then called via the syscall-table. Coming back from the syscall, the return value is stored in the eax field of the utcb and the instruction pointer in the utcb is increased by 2 to point after the 'int80'. Then the exception reply IPC is sent. The Linux server now waits for the next request. All this code is in the dispatch.c file in the L4Linux tree.
Now the kernel wakes up again from its do_receive(). The contents of the utcb are copied to the trap state structure of the faulting thread. The utcb handler is reset. That's it in Thread::exception(). We now come back to handle_slow_trap() where we jump to 'success' because we have handled the exception. We come back to the entry.S code where we clear up the stack and finally 'iret' out to userland again.
The Linux user program now continues its execution after the 'int80', and eax is now whatever the PID of the Linux program is.
I hope this makes it more clear what happens when a Linux program executes an int 80.
Adam