CS3210 Design Operating Systems

Taesoo Kim





Interrupt and Exception

Taesoo Kim

Administrivia

About Quiz 2

Q&A

What happens when the processor doesn’t know how to handle the exception?

Are Synchronous Interrupts possible, or are they all asynchronous?

Agenda

Summary: Exception level / Execution states

Execution states of AArch32/64

Changing execution levels (target mode)

Example: invoking a system call

Today topic: exception handling (in Arm)

Example: actions/events causing an exception

Note on definition (x86)

-> Interrupt in x86: a control transfer mechanism

Interrupt routing (RPi3)

Handling synchronous exceptions

Handling synchronous exceptions

Example: invoking a system call (workflow)

Example: invoking a system call (in kernel)

#[no_mangle]
pub extern "C" fn handle_exception(info: Info, esr: u32, 
                                   tf: &mut TrapFrame) {
    match info.kind {
        Kind::Synchronous => {
            let syndrome = Syndrome::from(esr);
            match syndrome {
                Syndrome::Brk(_) => { ... }
                Syndrome::Svc(n) => {
                    handle_syscall(n, tf);
                    return;
                }
                ...
        },
        ...
    }
}

Example: invoking a system call (in kernel)

// (ref: D1.10.4)
pub enum Syndrome {
    Unknown,
    SimdFp,
    IllegalExecutionState,
    Svc(u16),
    Hvc(u16),
    Smc(u16),
    InstructionAbort { kind: Fault, level: u8 },
    PCAlignmentFault,
    DataAbort { kind: Fault, level: u8 },
    SpAlignmentFault,
    Breakpoint,
    Step,
    Watchpoint,
    Brk(u16),
    Other(u32),
    ...
}

Synchronous exception in other exception levels

Exception handling steps

  1. PSTATE → SPSR_ELn (where n is the exception level where the exception is taken)
  2. PC → ELR_ELn
  3. PSTATE is updated for an exception handler (i.e., PC and SP)

Nested exception handling steps

Exception vector table

Exception vector table

pub enum Kind {
    Synchronous = 0,
    Irq = 1,
    Fiq = 2,
    SError = 3,
}

Exception vector table

pub enum Source {
    CurrentSpEl0 = 0,
    CurrentSpElx = 1,
    LowerAArch64 = 2,
    LowerAArch32 = 3,
}

Exception vector table

.align 11
.global vectors
vectors:
    HANDLER 0, 0
    HANDLER 0, 1
    HANDLER 0, 2
    HANDLER 0, 3
    ...
    HANDLER 3, 3

Exception vector table (vector.s)

.macro HANDLER source, kind
    .align 7
    stp     lr, xzr, [SP, #-16]!
    stp     x28, x29, [SP, #-16]!
    
    mov     x29, \source
    movk    x29, \kind, LSL #16
    bl      context_save
    
    ldp     x28, x29, [SP], #16
    ldp     lr, xzr, [SP], #16
    eret
.endm

Returning from an exception (reverse)

Processor state (PSTATE)

Controlling interrupts

MSR DAIFSet, #Imm4  // Used to set any or all of DAIF to 1
MSR DAIFClr, #Imm4  // Used to clear any or all of DAIF to 0
/// Enable (unmask) IRQ interrupts
pub fn enable_irq_interrupt() {
    unsafe {
        asm!("msr DAIFClr, 0b0010" :::: "volatile");
    }
}
/// Disable (mask) FIQ interrupt
pub fn disable_fiq_interrupt() {
    unsafe { 
        asm!("msr DAIFSet, 0b0001" :::: "volatile");
    }
}

Interrupt handling

Nested interrupt handling (same EL)

Interrupt handling routines

#[no_mangle]
pub extern "C" fn handle_exception( ... ) {
    match info.kind {
        Kind::Synchronous => {
            let syndrome = Syndrome::from(esr);
            match syndrome {
                Syndrome::Brk(_) => { ... }
                Syndrome::Svc(n) => { ... }
        }
        Kind::Irq => {
            let ic = Controller::new();
            for v in Interrupt::iter() {
                if ic.is_pending(v) {
                    crate::IRQ.invoke(v, tf);
                }
            }
        }
        ...
}

Summary: Exception/interrupt

References