CS 332 w22 — Interrupts and System Calls

Table of Contents

1 Reading: Limited Direct Execution

Read Chapter 6 (p. 55–68) of the OSTEP book. It builds on the dual-mode execution reading from Wednesday and discusses how this switch from user mode to kernel mode actually occurs.

Important terms:

  • system call
  • trap
  • trap table
  • trap handler

Key questions to consider as you read:

  • Where does the CPU run after a trap?
  • What is the trap handler written in? C? Java?
  • What stack does it use?
  • Is the work the CPU had been doing before the trap lost forever?
  • If not, how does the CPU know how to resume that work?

2 Mode Transfer

  • When does the system go from user to kernel mode?
    • Interupts
    • Processor Exceptions
      • Cool example: to set a breakpoint, kernel replaces instruction in memory with special instruction that traps into the kernel. At the point, the kernel will restore the old instruction and transfer control to the debugger.
    • System calls (traps)
  • When does the system go from kernel to user mode?
    • After starting a new process
    • Resume after interrupt, exception, or trap
    • Context switch

3 Mode Transfer Mechanisms

  • Minimum features:
    • Limited entry into the kernel
    • Atomic changes to processor state
    • Transparent, restartable execution

3.1 Interrupt Vector Table

  • During boot, the system will set up an interrupt vector table the system will use to look up the handler (function) to call when a particular interrupt or trap occurs.

    • On x86, 0-31 are for processor exceptions (e.g., divide by zero)
    • 32-255 are for interrupts (timer, keyboard, etc.)
    • 64 is usually reserved for system call handler

    interruptVector.png

3.2 Kernel Stack

  • Where should the interrupted process's state be saved? What stack should the kernel code use?

    • Just use the user process stack? That's not protected memory, so probably don't want kernel data there
    • Solution: allocate two stacks per process, a user stack and a kernel stack

    kernelUserStacks.png

3.3 x86 Mode Transfer

  1. Mask (disable) interrupts (this delays any interrupts until they are enabled/unmasked—if interrupts are masked for too long they may be lost)
  2. Save key process state (stack pointer, processor state (eflags register), instruction pointer (%rip)) in temporary hardware registers
  3. Switch to the kernel stack
  4. Push saved values onto kernel stack
  5. Optionally save an error code
  6. Call the interrupt handler

beforeInterrupt.png

duringInterrupt.png

afterInterrupt.png

3.4 Implementing System Calls

syscallStub.png

  1. User program calls user stub in the normal way
  2. User stub sets up code for system call and executes trap instruction
  3. Hardware transfers control to kernel, using interrupt vector table to jump to the appropriate handler. The handler acts as a stub on the kernel side, copying and checking arguments and then calling the kernel implementation of the system call
  4. After the system call completes, reutrn to the handler
  5. Handler returns to user level at the next instruction in the user stub
  6. The stub returns to the original caller

3.4.1 osv System Calls

  • usyscall.h
  • usyscall.S
  • syscall-num.h
  • syscall.c

4 Signals

User processes can receive their own kind of user-level interrupts, delivered by the kernel. On UNIX-based systems, these are called signals. On Windows, they're asynchronous events. User processes will have handlers for various signals. There would be used from things like asynchronous I/O, user-level exception handling, and interprocess communication. For example, the kill command on Linux is used to send signals to active processes, such as telling a process to terminate.