This document is a tutorial explaining how the eXpOS kernel must manage the kernel stack during system calls. The document is specific to the implementation of eXpOS on the XSM machine.
Since the user program has control over the transfer to the system call module, it is expected to save its register context (in the user stack) before the system call and restore the context after returing from the system call. The application program must also pass the parameters to the system call through the user stack. The return value of the system call is also passed back to the application through the user stack. For the calling conventions followed in eXpOS, see ABI. If the application program is written in ExpL, then the ExpL compiler will generate code for saving and restoring the context and pushing arguments into the user stack (if you are writing directly in assembly language, then your code must explicitly contain the code to do these).
The system call module must be designed so as to access these arguments from the user stack of the process, do the processing required and store the return value into the appropriate location in the user stack before returning to the user mode. The system call module must also change the stack to its kernel stack upon entry and switch back to the user stack at the time of return.
a. Push the registers in use to the stack
b. Push the system call number into the stack
c. Push the arguments
d. Push an empty space for the return value
e. Invoke the INT machine instruction corresponding to the system call
Pseudo code
.... // Code to push registers
PUSH System_Call_Number // Push system call number
PUSH Argument_1 // Push the arguments to the stack
PUSH Argument_2
PUSH Argument_3
PUSH R0 // Push an empty space for return value
INT number // Invoke the corresponding INT
instruction
a. Extract the system call number and the arguments from the user stack.
b. Set the MODE field in process table entry of the process to the system call number.
c. Switch from the user stack to the kernel stack.
d. Identify the system call using the system call number and transfer control to the system call code
Pseudo code
...
syscallNumber <- address_translate(UserSP - 5);
Argument_1 <- address_translate(UserSP - 4);
Argument_2 <- address_translate(UserSP - 3);
Argument_3 <- address_translate(UserSP - 2);
// Switching the stack
UPTR <- UserSP
SP <- User Area Page Number * 512 - 1
...
a. Store the return value in the user stack
b. Set the stack pointer (SP) to top of the user stack
c. Set the MODE field in process table entry of the current process to 0.
d. Return to the user program using the IRET machine instruction
Pseudo code
....
// store the return value in the
space alloted in the user stack
Address_RetVal <- address_translate(UPTR - 1);
[Address_RetVal] <- return value
// move the value of User Stack
Pointer TO SP
MOV SP, UPTR
// return to the user program
IRET
a. Save the return value
b. Pop off the arguments and the system call number from the stack
c. Restore the register context and resume execution.
Pseudo code
....
POP R0 // Pop and save the return
value
POP Argument_3
POP Argument_2
POP Argument_1 // Pop and discard the
arguments
POP System_Call_Number // Pop and discard the
system call number
.... // Code to restore the
register context and
resume execution