UnnamedOS
isr_asm.S
1 isr_common:
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
9  push %es
10  push %fs
11  push %gs
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)
19  mov %ax, %ds
20  mov %ax, %es
21  mov %ax, %fs
22  mov %ax, %gs
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.
29  pop %ds
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.
35 
36 // These ISR stubs push an error code (if necessary) and the interrupt vector before jumping into the common ISR handler:
37 .macro isr_intr nr
38 .global isr_intr_\nr
39 isr_intr_\nr:
40  push $0 // no error code
41  push $\nr // interrupt vector
42  jmp isr_common
43 .endm
44 
45 .macro isr_intr_with_error nr
46 .global isr_intr_\nr
47 isr_intr_\nr:
48  // error code is already on the stack
49  push $\nr // interrupt vector
50  jmp isr_common
51 .endm
52 
53 isr_intr 0x00 // 00-1F: Exceptions
54 isr_intr 0x01
55 isr_intr 0x02
56 isr_intr 0x03
57 isr_intr 0x04
58 isr_intr 0x05
59 isr_intr 0x06
60 isr_intr 0x07
61 isr_intr_with_error 0x08
62 isr_intr 0x09
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
68 isr_intr 0x0F
69 isr_intr 0x10
70 isr_intr_with_error 0x11
71 isr_intr 0x12
72 isr_intr 0x13
73 isr_intr 0x14
74 isr_intr 0x15
75 isr_intr 0x16
76 isr_intr 0x17
77 isr_intr 0x18
78 isr_intr 0x19
79 isr_intr 0x1A
80 isr_intr 0x1B
81 isr_intr 0x1C
82 isr_intr 0x1D
83 isr_intr 0x1E
84 isr_intr 0x1F
85 isr_intr 0x20 // 20-27: IRQ0-7 (PIC1) (see pic.c)
86 isr_intr 0x21
87 isr_intr 0x22
88 isr_intr 0x23
89 isr_intr 0x24
90 isr_intr 0x25
91 isr_intr 0x26
92 isr_intr 0x27
93 isr_intr 0x28 // 28-2F: IRQ8-15 (PIC2)
94 isr_intr 0x29
95 isr_intr 0x2A
96 isr_intr 0x2B
97 isr_intr 0x2C
98 isr_intr 0x2D
99 isr_intr 0x2E
100 isr_intr 0x2F
101 isr_intr 0x30 // 30: syscall