Project #5: Trap Handlers

Submit: Turn in your dispatch.c and testcases.c source files using the turnin command on morbius.mscsnet.mu.edu or one of the other Systems Lab machines.

Work should be completed in pairs. Be certain to include both names in the comment block at the top of all submitted source code files. It would be courteous to confirm with your partner when submitting the assignment. You may modify any files in the operating system, but only changes to dispatch.c and testcases.c will be graded for this assignment.

It's a Trap!

Preparation

First, make a copy of your Project 4 directory:
    cp -R xinu-hw4 xinu-hw5
Then, untar the new project files on top of it:
    tar xvzf ~brylow/os/Projects/xinu-hw5.tgz

New files:

system/start.S   Updated O/S start with exception handlers in place.
system/interrupt.S   RISC-V assembly code for managing exceptions -- calls dispatch().
system/xtrap.c   Default Xinu Trap Handler catches exceptions.
system/dispatch.c   Dispatcher for interrupts and exceptions, called from interrupt.S.
system/syscall_dispatch.c   A simple system call interface, plus stubs for several simple user and kernel syscall components. You must call this from dispatch().
include/syscall.h   New header with syscall definitions, structures and prototypes.

The dispatch() currently function defaults to treating the ecall (environment call) instruction as a generic, show-stopping hardware exception. You must add the intelligence to recognize when the exception is caused by a deliberate System Call from a "user" process in to the "kernel", and collect the system state information necessary for syscall_dispatch() to do its work.

To begin, we'll start with just five simple syscalls:

It's important to understand the various privilege levels a RISC-V processor can be in. Different privilege levels dictate which control and status registers can be accessed. RISC-V has three different privilege levels (listed from highest to lowest privilege).

  1. Machine mode (M-Mode) - Allows unfettered access to all control and status level registers. Any program running in M-Mode has virtually no restrictions. On our RISC-V boards, only U-Boot runs in M-Mode.
  2. Supervisor mode (S-Mode) - Allows the program to modify any supervisor-level control and status registers. S-Mode is designed for running a kernel. In our implementation, only the main processes will run in S-Mode. All other processes will run in U-Mode.
  3. User mode (U-Mode) - A process running here cannot modify any of the hardware or the control and status registers. It must execute a system call so a higher privilege mode can do that action on its behalf.
A process cannot simply change it's own privilege level. That would circumvent security completely! Instead it must make a system call using the ecall instruction. Once an ecall instruction is executed, the processor automatically elevates to the next higher privilege level and runs that privilege's trap handler. Once that mode is done servicing the trap, it executes an mret or sret (depending on the mode) instruction to return to the privilege mode it was previously in and continue where it left off.

Once you believe your've finished your trap handler, you will need to make modifications to ctxsw.S and create.c files. In ctxsw.S, you need remove the jalr line and replace it with

	ld t0, PREG_PC*8(**REGISTER THAT HOLDS newregs ADDRESS**)
	beq t0, ra, switch
	li t4, SSTATUS_S_MODE
	csrc sstatus, t4
	csrw sepc, t0

	sret
switch:
	ret
	
This section of code switches from S-Mode to U-Mode if the process is running the first time. All other times, the process must have got to ctxsw from a trap, thus we will let the trap handler switch modes when it returns. Since kill() is a kernel mode function (which should not be directly called by user processes), you must change the kill(currpid); line in create.c to user_kill();

Our current simple embedded O/S does not yet provide memory protection. As a result, our system call interface will only provide the first of required components for protecting the O/S from user processes. Your user processes will still be able to call most arbitrary internal kernel functions without going through the system call interface, and read or write data from other processes or the O/S itself. Since ctxsw has a special instruction (sret) that can only be run from S-Mode, only processes running in S-Mode (like the init process) can run ctxsw. If you get an Illegal Instruction exception, that means you're calling functions from a mode that you don't have the privilege to call.

As we add more features to our O/S in weeks to come, we will create the memory virtualization abstractions that will prevent user code from accessing O/S functions and data without going through an approved user_* system call function. For now, we're building system calls even though all of our processes are still executing at the "kernel" privilege level, with unrestricted view of all memory.

 

Testing

The default test cases provided with the tarball exercise each one of our starting system calls at least once. Judicious use of additional debugging kprintf() calls will be essential for debugging your system call interface as you build it. Be certain to comment out these debugging statements when you turn in your code each night, lest TA-Bot find your code unworthy.

Once you have the basics working, consider filling in some of the other system call stubs left for future expansion, or write a version of user_printf() that processes all of the format string in the user process, but relies on the user_putc() syscall for requesting that the O/S output each resulting character.

This project can be completed in fewer than a dozen lines of code, but the technical details of the system call can be quite complex and hard to keep straight. It is very unlikely that random code snippets from the Internet will help to solve this one -- it is essential that you understand the data structures and mechanisms involved, and reason through an adequate design to solve the problem.

Admiral Gial Ackbar

[back]

[Revised 2023 Feb 22 02:42 DWB]