Interrupt/Exception handling on the x86

Required reading: Chapter 5 (Interrupt and Exception handling)


Sources of Exceptions/Interrupts 
 - hardware interrupts
       +----------+        +--------+
       |      INTR|--------|  PIC   |---16 wires to devices
       |       NMI|---     | 8259A  |
       |   CPU    |        +--------+
       |          | 
       +----------+
   - NMI -- non-maskable -- signals hard failure
   - INTR maskable -- eflags IF (one bit!!)
      - IF 0 -- interrupts masked -- ie. ignored
      - IF 1 -- interrupts "unmasked" -- ie. not ignored
 - software exception
   - ex. movl %ebx, (%eax)
   - ex. divl %eax,%eax
   - ex. "int $VECTOR" -- aka. programmed interrupt
   - see insn set reference for each insn's possible expection
 - Every exception/interrupt is given a number: it's VECTOR

PIC details
  - mapping IRQ0-15 => into which vector
    - vector = IRQ # + 
  - vector is signaled over the INTR line

IDT (pg 5-11)
 - table of entries (8 byte)
 - lidt - tells CPU where in memory the table resides
 - 32 for processor exceptions
 - any of the remaining 16 for hardware interrupts
 - rest are for software interrupts  (e.g., int $0x50)

IDT entry (pg 5-13)
 - 8 bytes
 - CS:EIP -- entry point of handler routine
 - P   -- 1 bit  -- Does entry holds valid info?
 - DPL -- 2 bits -- 0 for exception and external interrupts, 3 for software interrupts
 - Type -- 4 bits -- task, trap, or interrupt gate
 - Crazy format like GDT entries (recall SEG() macro)
 - Interrupts gates -- clear IF bit of %eflags
 - Trap gates -- don't change eflags
 - Both
     - clear TF, VM, RF, NT flags
 - setgate (idt[IRQ_OFFSET + 0],
            GD_KT,             /* istrap */
	    &_clock_interrupt,
            0);                /* DPL */

TSS
 - purpose: hardware supported multi-tasking => we don't use
 - as a data structure:
   - lots of irrelevant fields
     - GS, FS, DS, SS, CS, ES
     - EDI, ESI, EBP, ESP, EBX, EDX, ECX, EAX, EFLAGS, CR3
     - SS0:ESP0, SS1:ESP1, SS2:ESP2 <-- recving calls from lower privileged level 
   - relevant to this class:
     - only SS0:ESP0 -- stack that is switched to when a
       interrupt/exeception happens in user mode.
 - Resides in memory, must tell the CPU where:
   - TSS descriptor goes in the GDT
   - ltr (GD_TSS)

Exception Entry Mechanism
 - pg 5-16
 - Like a procedure call (arguments on the stack)

 - USER => KERNEL
   - stack layout
          value                       reason pushed
        - old SS                    [ switching
        - old ESP                           stacks]
        - old EFLAGS               [ clearing bits ]
        - old CS                   [ switch to
        - old EIP                      entry point ]
        - error code (optional)    [ extra info ]
   - new state
        - SS:ESP <=  TSS ss0:esp0
        - CS:EIP <= IDT[vector].segment :  IDT[vector].offset
        - EFLAGS <= EFLAGS with bits cleared
                   - Class OS: kernel runs with device interrupts disabled
                   - interrupt gate

 - KERNEL => KERNEL
   - stack layout
          value                       reason pushed
        - old EFLAGS               [ clearing bits ]
        - old CS                   [ switch to
        - old EIP                      entry point ]
        - error code (optional)    [ extra info ]
   - new state
        - SS:ESP **** unchanged!!
        - CS:EIP <= IDT[vector].segment :  IDT[vector].offset
        - EFLAGS <= EFLAGS with bits cleared

   - why switch stacks (USER => KERNEL)? 
       => stack may be the cause of the fault 
       => triple faults cause CPU reset

  - Motivation: save on stack if the registers themselves are changed
    - notice: Kernel=>Kernel fault doesn't save SS:ESP 
      why?  because there is no stack switch (i.e., SS:ESP are not
      overwritten)

   - mention now or later??
     - mode (user => kernel): CS -- bottom 2 bits are CPL

Exception Return Mechanism
 - iret -- top of stack should be old EIP
 - closer look at old EIP / Exception Types 
   - traps  - old EIP -- points past instruction causing exception
     - brkpt (i.e., int $3)
   - faults - old EIP -- points to instruction causing exception
     - page faults     
   - aborts - old EIP -- not certain -- serious problems - CPU is confused

Comparison to PDP11/40
 - DEVICE INTERRUPTS
   - x86: maskable by IF bit of EFLAGS; (and by the PIC)
   - pdp: multiple priority levels
 - DISPATCHING
   - x86: IDT, which resides any where in memory
   - pdp: dispatch table at fixed physical address
 - DISPATCH ENTRY FORMAT
   - x86: IDT entry -- contain CS:EIP
   - pdp: trap;br7+0. -- entry point and new PSW  
 - MODE SWITCH
   - x86: low two bits of CS hold CPL (11 -- kernel, 00 -- user)
   - pdp: kernel vs user specified in PSW
 - ADDRESSING SWITCH
   - x86: no switch
          paging is not changed because %cr3 is not reloaded
          However, more of the VA space is accessible--notably the KERNEL only VA regions
         (this ignores segmentation since our convention is to disable segmentation for the lab OS)
   - pdp: complete switch
          kernel mode -- implicitely selects new set of segementation registers
 - STACK SWITCH
   - x86: new stack is: TSS ss0:esp0
   - pdp: kernel mode -- implicitely uses kernel sp register