title: Setting up interrupts in protected mode (x86)
body: <p>What is the process of setting up interrupts for protected mode?  </p>
  
  <p><a href="http://wiki.osdev.org/Interrupts" rel="nofollow">This</a> link says one should:</p>
  
  <blockquote>
    <ul>
    <li>Make space for the interrupt descriptor table  </li>
    <li>Tell the CPU where that space is (see GDT Tutorial: lidt works the very same way as lgdt)  </li>
    <li>Tell the PIC that you no longer want to use the BIOS defaults (see Programming the PIC chips)  </li>
    <li>Write a couple of ISR handlers (see Interrupt Service Routines) for both IRQs and exceptions  </li>
    <li>Put the addresses of the ISR handlers in the appropriate descriptors</li>
    <li>Enable all supported interrupts in the IRQ mask (of the PIC)</li>
    </ul>
  </blockquote>
  
  <p>The third step makes no sense to me (I looked at <a href="http://wiki.osdev.org/8259_PIC" rel="nofollow">this</a> link but there wasn't anything about telling the PIC anything) so I ignored it and completed the next two steps, only to be clueless once again when I reached the final step. However, from my understanding of interrupts, both of the steps I didn't understand relate to hardware interrupts from the PIC controller and shouldn't affect the interrupts raised by the PIT on IRQ 0. I therefore ignored this step as well.</p>
  
  <p>When I ran my code it compiled fine and even ran in a virtual machine, but the interrupt seemed to fire only once. I then realised that I wasn't sending EOI to the PIC, preventing it from raising any more interrupts. However, adding <code>mov al, 0x20</code> and <code>out 0x20, al</code> just before the <code>iret</code> instruction makes the virtual machine crash.</p>
  
  <p>Here's my IDT:</p>
  
  <pre><code>; idt
  idt_start :
  
      dw 0x00         ; The interrupt handler is located at absolute address 0x00
      dw CODE_SEG     ; CODE_SEG points to the GDT entry for code
      db 0x0          ; The unused byte
      db 0b11101001   ; 1110 Defines a 32 bit Interrupt gate, 0 is mandatory, privilege level = 0 (0b00), the last bit is one so that the CPU knows that the interrupt will be used
      dw 0x00         ; The higher part of the offset (0x00) is 0x00
  
  idt_end:
  
  idt_descriptor :
      dw idt_end - idt_start - 1 ; Size of our idt, always one less than the actual size
      dd idt_start ; Start address of our idt
  </code></pre>
  
  <p>Here's my interrupt handler (located at absolute location 0x00 in memory):</p>
  
  <pre><code>ISR_0:
      push eax
      add [0x300], byte 
      mov al, 0x20
      out 0x20, al
      pop eax
      iret    
      times 512-($-$$) db 0
  </code></pre>
  
  <p>This is the code I use to enter protected mode and load the GDT and IDT into memory:</p>
  
  <pre><code>[bits 16]
  
  switch_to_pm:
  
      cli
      lgdt [gdt_descriptor]
      lidt [idt_descriptor]
      mov eax, cr0
      or eax, 1
      mov cr0,eax
      jmp CODE_SEG:init_pm
  
  [bits 32]
  
  init_pm :
  
      mov ax, DATA_SEG
      mov ds, ax
      mov ss, ax
      mov es, ax
      mov fs, ax
      mov gs, ax
      mov ebp, 0x90000
      mov esp, ebp
      sti
      call BEGIN_PM
  </code></pre>
  
  <p>My main function (that checks the value of 0x300) is as follows:</p>
  
  <pre><code>void main() {
      char iii[15];
      int * aa = (int *)0x300;
      for (;;)
      {
          setCursor(0, 0);
          print(itoab(*aa, iii));
      }
  }
  </code></pre>
  
  <p>By the way, I have verified using a memory dump that everything is loaded at the correct address and everything is exactly where it is expected. For example, 0x300 is a free part of memory used simply to simplify my code.</p>