census logo
[bootcensus] / src / intr_asm.S
1 # pcboot - bootable PC demo/game kernel
2 # Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
3
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
8
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY, without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13
14 # You should have received a copy of the GNU General Public License
15 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17         .data
18         .align 4
19         .short 0
20 idtr_desc:
21 lim:    .short 0
22 addr:   .long 0
23
24         .text
25 /* void set_idt(uint32_t addr, uint16_t limit) */
26         .global set_idt
27 set_idt:
28         mov 4(%esp), %eax
29         mov %eax, addr
30         mov 8(%esp), %ax
31         mov %ax, lim
32         lidt (idtr_desc)
33         ret
34
35 /* int get_intr_flag() */
36         .global get_intr_flag
37 get_intr_flag:
38         pushf
39         popl %eax
40         # bit 9 of eflags is IF
41         shr $9, %eax
42         and $1, %eax
43         ret
44
45 /* void set_intr_flag(int onoff) */
46         .global set_intr_flag
47 set_intr_flag:
48         cmpl $0, 4(%esp)
49         jz 0f
50         sti
51         ret
52 0:      cli
53         ret
54
55 /* interrupt entry with error code macro
56  * this macro generates an interrupt entry point for the
57  * exceptions which include error codes in the stack frame
58  */
59         .macro ientry_err n name
60         .globl intr_entry_\name
61 intr_entry_\name:
62         pushl $\n
63         jmp intr_entry_common
64         .endm
65
66 /* interrupt entry without error code macro
67  * this macro generates an interrupt entry point for the interrupts
68  * and exceptions which do not include error codes in the stack frame
69  * it pushes a dummy error code (0), to make the stack frame identical
70  */
71         .macro ientry_noerr n name
72         .globl intr_entry_\name
73 intr_entry_\name:
74         pushl $0
75         pushl $\n
76         jmp intr_entry_common
77         .endm
78
79 /* common code used by all entry points. calls dispatch_intr()
80  * defined in intr.c
81  */
82         .extern dispatch_intr
83 intr_entry_common:
84         /* save general purpose registers */
85         pusha
86         call dispatch_intr
87 intr_ret_local:
88         /* restore general purpose registers */
89         popa
90         /* remove error code and intr num from stack */
91         add $8, %esp
92         iret
93
94 /* special case for the timer interrupt, to avoid all the overhead of
95  * going through the C interrupt dispatcher 250 times each second
96  */
97         .extern nticks
98         .global intr_entry_fast_timer
99 intr_entry_fast_timer:
100         incl nticks
101         # signal end of interrupt
102         push %eax
103         mov $0x20, %al
104         out %al, $0x20
105         pop %eax
106         iret
107
108 /* special case for IRQ 7 and IRQ 15, to catch spurious interrupts */
109         .set PIC1_CMD, 0x20
110         .set PIC2_CMD, 0xa0
111         .set OCW2_EOI, 0x20
112         .set OCW3_ISR, 0x0b
113
114         .extern intr_entry_irq7
115         .global irq7_entry_check_spurious
116 irq7_entry_check_spurious:
117         push %eax
118         mov $OCW3_ISR, %al
119         out %al, $PIC1_CMD
120         in $PIC1_CMD, %al
121         and $0x80, %al
122         pop %eax
123         jnz intr_entry_irq7
124         iret
125
126         .extern intr_entry_irq15
127         .global irq15_entry_check_spurious
128 irq15_entry_check_spurious:
129         push %eax
130         mov $OCW3_ISR, %al
131         out %al, $PIC2_CMD
132         in $PIC2_CMD, %al
133         and $0x80, %al
134         jnz 0f
135         # it was spurious, send EOI to master PIC and iret
136         mov $OCW2_EOI, %al
137         out %al, $PIC1_CMD
138         pop %eax
139         iret
140 0:      pop %eax
141         jmp intr_entry_irq15
142
143
144 /* XXX not necessary for now, just leaving it in in case it's useful
145  * down the road.
146  *
147  * intr_ret is called by context_switch to return from the kernel
148  * to userspace. The argument is a properly formed intr_frame
149  * structure with the saved context of the new task.
150  *
151  * First thing to do is remove the return address pointing back
152  * to context_switch, which then leaves us with a proper interrupt
153  * stack frame, so we can jump right in the middle of the regular
154  * interrupt return code above.
155  */
156         .global intr_ret
157 intr_ret:
158         add $4, %esp
159         jmp intr_ret_local
160
161 /* by including interrupts.h with ASM defined, the macros above
162  * are expanded to generate all required interrupt entry points
163  */
164 #define ASM
165 #include <intrtab.h>