Exceptions, MIPS-Style Reminder: MIPS CPU deals with exceptions. - - PDF document

exceptions mips style
SMART_READER_LITE
LIVE PREVIEW

Exceptions, MIPS-Style Reminder: MIPS CPU deals with exceptions. - - PDF document

CPSC-410/611 Operating Systems Exceptions, MIPS-Style Reminder: MIPS CPU deals with exceptions. Interrupts are just a special case of exceptions. The MIPS Architecture has no interrupt-vector table! All exceptions trigger


slide-1
SLIDE 1

CPSC-410/611 Operating Systems

1

Exceptions, MIPS-Style

  • Reminder:

– MIPS CPU deals with exceptions.

  • Interrupts are just a special case of exceptions.

– The MIPS Architecture has no interrupt-vector table!

  • All exceptions trigger a jump to the same location, and de-

multiplexing happens in the exception handler, after looking up the reason for the exception in the CAUSE register.

exception handler specific service routine exception

Exception Handling MIPS-Style (I): Data Structures

/*-----------------------------------------------------------------------*/ /* DATA STRUCTURES */ /*-----------------------------------------------------------------------*/ typedef enum {Int = 0, Mod = 1, TLBL = 2, TLBS = 3, AdEL = 4, AdES = 5, IBE = 6, DBE = 7, Syscall = 8, Bp = 9, RI = 10, CpU = 11, Ov = 12, TRAP = 13, VCEI = 14, FPE = 15, C2E = 16, Watch = 23, VCED = 31} EXCEPTION_CODE; typedef unsigned int reg_t; typedef struct xcptcontext { /* This is the exception context frame that is passed to the exception

  • handlers. It gets filled in by the low-level exception handler in

"machine.S". An assembler version of this structure can be found at the bottom of "machine.H".*/ reg_t sr; /* Status Register */ reg_t cr; /* Cause Register */ reg_t epc; /* PC at time of exception. */ reg_t vaddr; reg_t regs[32]; /* Copy of all general purpose registers */ reg_t mdlo; /* HI/LO registers (used for memory management) */ reg_t mdhi; reg_t count; /* Timer registers */ reg_t compare; struct xcptcontext * prev; /* To link exceptions. (unused for now) */ unsigned xclass; /* Priority class of this exception. (unused for now). */ } EXCEPTION_CONTEXT;

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

slide-2
SLIDE 2

CPSC-410/611 Operating Systems

2

Exception Handling MIPS-Style (II): Set-up Frame

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

LEAF(xcptlow_handler) .set noreorder .set noat /* Note: exceptions do not save and restore registers k0 and k1. *

  • n entry, k1 = exception class.

*/ /* save exception class in memory */ la k0, class sw k1, 0(k0) # had better not trap! move k0, zero # now boot exception will abort. /* allocate exception stack frame (on 8-byte boundary) */ subu k1, sp, XCP_SIZE srl k1, 3 /* shift right/left -> alligned on boundary */ sll k1, 3

Exception Handling MIPS-Style (III): Save Registers

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

/* save enough registers to get by */ sr AT, XCP_AT(k1) sr v0, XCP_V0(k1) sr v1, XCP_V1(k1) sr a0, XCP_A0(k1) sr a1, XCP_A1(k1) sr a2, XCP_A2(k1) sr a3, XCP_A3(k1) sr sp, XCP_SP(k1) sr ra, XCP_RA(k1) /* get coprocessor 0 exception state */ mfc0 a0, CPU0_CR mfc0 a1, CPU0_SR mfc0 a2, CPU0_VADDR mfc0 a3, CPU0_EPC /* we can safely use AT now */ .set at /* switch to using sp to point at exception frame */ move sp, k1 /* we skip saving of watchpoint registers */ /* stash exception class */ lw v0, class /* nothing sensible to store for k0/k1, store zero */ sr zero, XCP_K0(sp) sr zero, XCP_K1(sp)

slide-3
SLIDE 3

CPSC-410/611 Operating Systems

3

Exception Handling MIPS-Style (IV): Save More Registers

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

/* we have finished with the uninterruptible code. * (using k0/k1, and saving exception state), so * we can permit nested exceptions ; however, we cannot * permit device interrupts until the interrupt handler * does its prioritization and sets SR_IMASK. */ la k0, xcptlow_handler # restore rom boot exception hook and v0, a1, ~(SR_IMASK|SR_EXL|SR_KSU_MASK) mtc0 v0, CPU0_SR .set reorder /* we are now interruptible: dump all remaining state * into the exception stack frame. */ /* coprocessor exception state */ sr a0, XCP_CR(sp) sr a1, XCP_SR(sp) sr a2, XCP_VADDR(sp) sr a3, XCP_EPC(sp) /* timer data */ mfc0 a0, CPU0_COUNT mfc0 a1, CPU0_COMPARE sr a0, XCP_COUNT(sp) sr a1, XCP_COMPARE(sp) /* mdhi and mdlo */ mfhi v0 mflo v1 sr v0, XCP_MDHI(sp) sr v1, XCP_MDLO(sp)

Exception Handling MIPS-Style (V)

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

/* Save all the other general registers. * We save zero, s0-s7 and s8 as well, as instruction emulators (e.g. FP * operations) and debuggers rely on all registers stored together in * well-defined structure. */ sr zero, XCP_ZERO(sp) sr t0, XCP_T0(sp) … sr t7, XCP_T7(sp) sr s0, XCP_S0(sp) … sr s7, XCP_S7(sp) sr t8, XCP_T8(sp) sr t9, XCP_T9(sp) sr gp, XCP_GP(sp) sr s8, XCP_S8(sp) /* I don't know what the following does. [rb] */ /* load our _gp pointer */ la gp, _gp

slide-4
SLIDE 4

CPSC-410/611 Operating Systems

4

Exception Handling MIPS-Style (VI)

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

LEAF(_xcptcall) /* on entry: a0 == &xcp */ subu sp, 24 sr ra, 16(sp) /* punt out to _xcpt_deliver */ jal _xcpt_deliver lr ra, 16(sp) addu sp, 24 beqz ra, xcptrest j ra END(_xcptcall) extern "C" int _xcpt_deliver(struct xcptcontext * _xcp) { /* This function gets called by the low-level exception handler. */ ExceptionDispatcher::dispatch(_xcp); return 0; } /* end of _xcpt_deliver */ /* and call the C exception handler */ move a0, sp # arg1 = &xcp subu sp, 16 # (arg save area) move ra, zero # fake return address b _xcptcall /* This strange call to _xcptcall with zero return address is to * help exception-aware debuggers to trace back over the exception event. * We are basically interposing a bogus stackframe (with a zero return * address) between the C exception handler and the actual machine * exception. */ xcptrest: .set noat add AT, sp, 16 /* at points to exception frame */

Exception Handling MIPS-Style (VII): Restore Registers

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

xcptrestother: /* restore all state */ /* restore most general registers */ lr t0, XCP_T0(AT) … lr t7, XCP_T7(AT) lr s0, XCP_S0(AT) … lr s7, XCP_S7(AT) lr t8, XCP_T8(AT) lr t9, XCP_T9(AT) lr gp, XCP_GP(AT) lr s8, XCP_S8(AT) /* mdhi and mdlo */ lr v0, XCP_MDHI(AT) lr v1, XCP_MDLO(AT) mthi v0 mtlo v1 /* remaining general registers */ lr a0, XCP_A0(AT) lr a1, XCP_A1(AT) lr a2, XCP_A2(AT) lr a3, XCP_A3(AT) lr ra, XCP_RA(AT) /* restore the exception-time status register, which has the * side effect of disabling interrupts. */ .set noreorder lr v0, XCP_SR(AT)

slide-5
SLIDE 5

CPSC-410/611 Operating Systems

5

Exception Handling MIPS-Style (VIII): Return

xcptlow_handler set up exception frame

  • n stack

save enough registers to get by save rest of registers call C exception handler restore registers return from exception

/* in the following we do some magic address pipeline effects when updating the control register. */ #clear SR_IMASK before setting SR_EXL (nasty window) li v1, ~(SR_IMASK|SR_EXL) and v1, v0 mtc0 v1, CPU0_SR

  • r

v0, SR_EXL nop lr v1, XCP_V1(AT) mtc0 v0, CPU0_SR lr v0, XCP_V0(AT) lr sp, XCP_SP(AT) /* we are not uninterruptible and can use k1 safely */ lr k1, XCP_EPC(AT) lr AT, XCP_AT(AT) mtc0 k1, CPU0_EPC nop nop eret nop .set reorder .set at END(xcptlow_handler)

Initialize MIPS Low-Level Exception Handler

LEAF(_xcptlow_init) /* disable all interrupts */ mfc0 t4, CPU0_SR and t4, ~SR_IE mtc0 t4, CPU0_SR XCPTCOPY(0x180, _xcptlowstart, _xcptlowend) lw t0, _ram_based beqz t0, 1f /* using RAM-based handlers, so switch off boot exceptions */ and t4, ~SR_BEV mtc0 t4, CPU0_SR 1: la k0, xcptlow_handler j ra END(_xcptlow_init) /* Macro to copy exception handler to unchached low memory */ #define XCPTCOPY(offs, start, end) \ li t0, KSEG1_BASE+offs ; \ la t1, start ; \ la t2, end ; \ 1: lw t3, 0(t1) ; \ addu t1, 4 ; \ sw t3, 0(t0) ; \ addu t0, 4 ; \ bne t1, t2, 1b .text .set noat .set noreorder _xcptlowstart: la k1, xcptlow_handler j k1 _xcptlowend: .set reorder .set at

slide-6
SLIDE 6

CPSC-410/611 Operating Systems

6

High-Level Exception Handling

extern "C" int _xcpt_deliver(struct xcptcontext * _xcp) { /* This function gets called by the low-level exception handler. */ ExceptionDispatcher::dispatch(_xcp); return 0; } /* end of _xcpt_deliver */

ExceptionDispatcher

Default ExceptionHandler Memory ExceptionHandler

InterruptDispatcher

Default InterruptHandler Clock InterruptHandler

ExceptionDispatcher ExceptionHandler InterruptHandler

High-Level Exception Handling

extern "C" int _xcpt_deliver(struct xcptcontext * _xcp) { /* This function gets called by the low-level exception handler. */ ExceptionDispatcher::dispatch(_xcp); return 0; } /* end of _xcpt_deliver */

ExceptionDispatcher

Default ExceptionHandler Memory ExceptionHandler

InterruptDispatcher

Default InterruptHandler Clock InterruptHandler

ExceptionDispatcher ExceptionHandler InterruptHandler

int ExceptionDispatcher::dispatch(EXCEPTION_CONTEXT * _xcp) { /* -- RETRIEVE EXCEPTION CODE */ int xcp_code; xcp_code = (_xcp->cr & CR_EXCCODE) >> 2; Console::putstr("EXCEPTION DISPATCHER: xcp_code = "); Console::putint((int)xcp_code); Console::putstr("\n"); assert(xcp_code >= 0 && xcp_code < EXCEPTION_TABLE_SIZE); /* -- HAS A HANDLER BEEN REGISTERED FOR THIS CODE? */ ExceptionHandler * handler = handler_table[xcp_code]; /* -- IF SO, CALL THE HANDLER; OTHERWISE, CALL DEFAULT HANDLER. */ if (handler) { handler->handle_exception(_xcp); return 0; } else { /* --- NO DEFAULT HANDLER HAS BEEN REGISTERED. SIMPLY RETURN AN ERROR. */ Console::putstr("NO DEFAULT EXCEPTION HANDLER REGISTERED\n"); return -1; } }

slide-7
SLIDE 7

CPSC-410/611 Operating Systems

7

High-Level Exception Handling

extern "C" int _xcpt_deliver(struct xcptcontext * _xcp) { /* This function gets called by the low-level exception handler. */ ExceptionDispatcher::dispatch(_xcp); return 0; } /* end of _xcpt_deliver */

ExceptionDispatcher

Default ExceptionHandler Memory ExceptionHandler

InterruptDispatcher

Default InterruptHandler Clock InterruptHandler

ExceptionDispatcher ExceptionHandler InterruptHandler

int InterruptDispatcher::handle_exception(EXCEPTION_CONTEXT * _xcp) { /* -- THE EXCEPTION IS IN RESPONSE TO AN INTERRUPT. */ /* --- DETERMINE THE PENDING INTERRUPTS */ int interrupt_no = (_xcp->cr & CR_IP) >> 8; Console::putstr("InterruptDispatcher::handle_exception : interrupt_stat = "); Console::putint(interrupt_no); Console::putstr("\n"); /* --- DISPATCH THE INTERRUPT WITH THE HIGHEST NUMBER */ for (int i = 7 + MAX_INTERRUPTS; i > 7; i--) { if (_xcp->cr & (1 << i)) { Console::putstr("Interrupt No "); Console::putint(i-8); Console::putstr(" set.\n"); ExceptionHandler * interrupt_handler = interrupt_dispatch_table[i-8]; if (interrupt_handler) { Console::putstr("calling IDT->handle\n"); interrupt_handler->handle_exception(_xcp); } else { if (default_interrupt_handler) { default_interrupt_handler->handle_exception(_xcp); } else { /* ---- THERE IS NO HANDLER FOR THIS INTERRUPT */ Console::putstr("UNCAUGHT INTERRUPT\n"); } } } } } /* InterruptDispatcher::handle_exception */