2 // At this place, the CPU has already pushed EFLAGS, CS and EIP to the stack and, if we were in userspace
3 // before getting interrupted, the user SS and the user stack ESP. In userspace, after saving SS and ESP
4 // the CPU loads the kernel SS and kernel ESP from the TSS (which is prepared by the scheduler).
5 // So we change from the user stack to a kernel stack used only for handling interrupts.
6 // Additionally, in the ISR stubs we pushed an error code and the interrupt vector. Now we save the remaining registers:
7 pusha // save all general purpose registers
8 push %ds // and the segment registers (except SS) onto the stack
12 push %esp // push ESP again so we can freely switch stacks by returning the new ESP from isr_handle_interrupt
13 // Put the interrupt handling code in a defined state where we can access all kernel data, this is only necessary
14 // when coming from userspace because DS, ES, FS and GS might hold a RING3 selector.
15 // SS does not need to be altered because (a) we were in RING0 before and SS has already the right selector
16 // or (b) we were in RING3 before and SS was set to RING0 from the TSS. (CS does not need to be changed
17 // either, it already holds the RING0 code selector because we told the CPU so in the IDT.)
18 mov $0x0010, %ax // 0x0010 is the RING0 data segment (see gdt_asm.S)
23 call isr_handle_interrupt // jump to C
24 mov %eax, %esp // here a kernel stack switch (possibly) happens if we want to switch tasks, we need to ensure that
25 // the new kernel stack pops off the right registers below! (Note that we are still in RING0!)
26 pop %gs // pop everything neatly from the stack. If we want to return to userspace, these
27 pop %fs // segment registers hold the appropriate RING3 selectors. SS is again taken care
28 pop %es // of by the CPU when doing the iret.
30 popa // this pops everything pusha pushed (except ESP!)
31 add $8, %esp // pop interrupt and error code
32 iret // return from interrupt, takes care of popping EFLAGS, CS and EIP. Also pops SS and ESP
33 // if we want to return to userspace, in that case the user stack switch happens here.
34 // If we are switching into a VM86 task ES, DS, FS and GS are popped as well.
36 // These ISR stubs push an error code (if necessary) and the interrupt vector before jumping into the common ISR handler:
40 push $0 // no error code
41 push $\nr // interrupt vector
45 .macro isr_intr_with_error nr
48 // error code is already on the stack
49 push $\nr // interrupt vector
53 isr_intr 0x00 // 00-1F: Exceptions
61 isr_intr_with_error 0x08
63 isr_intr_with_error 0x0A
64 isr_intr_with_error 0x0B
65 isr_intr_with_error 0x0C
66 isr_intr_with_error 0x0D
67 isr_intr_with_error 0x0E
70 isr_intr_with_error 0x11
85 isr_intr 0x20 // 20-27: IRQ0-7 (PIC1) (see pic.c)
93 isr_intr 0x28 // 28-2F: IRQ8-15 (PIC2)
101 isr_intr 0x30 // 30: syscall