6.828 2005 lecture 7: x86 interrupts and exceptions required reading: Intel 386 manual, Chapter 5 (Interrupt and Exception Handling) topic: interrupts and exceptions interrupts: external event, not related to program exception: caused by some program instruction x86 handles them almost identically goal: suspend current execution user or kernel JOS turns of interrupts in kernel, but still can take exceptions switch to a handler in the kernel read device input / kill program / fix page fault / execute syscall resume execution overall things to be done, by CPU or kernel 1. raise priv level 2. switch to kern address space 3. save state (regs, eflags) 4. set up kernel stack 5. jump to kern entry point 6. discover the cause 7. ... 8. restore state 9. switch address space 10. decrease privs 11. resume device interrupts 16 interrupt lines two 8259A PIC chips PIC presents interrupts one at a time PIC chooses highest-pri interrupt PIC tells CPU a vector index CPU can ignore interrupts IF bit in EFLAGS STI enables, CLI disables IF also changed by interrupt gate and IRET interrupts always deferred until instruction boundary software exceptions divl %ebx, %eax if eax is zero, divide by zero exception movl %ebx, (%eax) if eax is not a valid pointer, page fault int 0x30 intentional, a JOS system call how does the kernel know the cause of the interrupt/exception? the IDT: interrupt descriptor table just like pdp 11/40 vectors every cause has a well-known vector number 0: divide by zero 3: breakpoint 11: segment not present 13: general protection 14: page fault 32-255: for external interrupts and INT n instruction IDT structure IDTR register: linear address of IDT base lidt instruction IDT descriptors: 8 bytes each segment selector -- index into GDT 32-bit offset -- entry point within segment DPL -- for INT n, CPL must be <= DPL an IDT descriptor is an "interrupt gate" DPT of code segment specifies CPL of handler stack switch if handler would cause a decrease in CPL (i.e. DPL < CPL), switch stacks to a known correct stack task state segment contains an ESP and SS for each x86 priv level LTR seg# loads task register with a segment selector GDT must map that segment to a task structure task structure has space to save all registers, seg regs, efalgs, cr3 but JOS does not use x86 task-switch machinery however it MUST use the ss0 / esp0 in task structure so what are all the x86 interrupt steps? 1. look at IDT entry 2. if INT n, check CPL <= DPL 3. save ESP and SS 4. SS:ESP = task structure's SS0:ESP0 5. push saved SS 6. push saved ESP 7. push EFLAGS 8. push CS 9. push EIP 10. CS:EIP = gate's CS:EIP 11. push error code 12. CPL = code segment's DPL 13. disable interrupts You can get at the info on the stack with struct Trapframe. If the interrupt was from kernel space, doesn't push SS:ESP. What about saving the other registers? Why must h/w save EFLAGS? Why not save w/ s/w? Why must h/w switch stack? Why not switch w/ s/w? Why no stack switch from kernel->kernel? Why no address space change? i.e. no cr3 change? Why is kernel data/instructions now accessible? why did the pdp 11/40 have to switch seg regs? What has to happen on a return from interrupt? IRET expects an EIP, a CS, and an EFLAGS on the stack and an ESP and SS if CPL != CS(RPL) what should happen after a return? what instruction to execute? device interrupt: proceed to next instruction INT n: proceed to next instruction fault: re-start same instruction Are all faulting instructions re-startable? for example, after a page fault, and o/s reads the page from disk? pop %eax push %eax pusha why might INT n be secure? no way to *just* set CPL = 0 all or nothing w/ INT user program can't create its own GDT or IDT entries lidt and lgdt are privileged instructions GDT and IDT not mapped r/w for user INT n can only call approved interrupt gate DPT=0 protects other vectors program doesn't get to choose entry point (offset) return state (CPL) is in protected memory (kernel stack) Extra information for page faults JOS needs to know which page, and what the problem was error code on stack, w/ cause bits page not present access was read vs write access was user vs kernel cr2 register contains linear address that faulted