cdae52ae2e1c23c453fa6c68c7b306e28737b12b
[com32] / src / intr_s.asm
1 ; pcboot - bootable PC demo/game kernel
2 ; Copyright (C) 2018-2023  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         section .data
18         align 4
19         dw 0
20 idtr_desc:
21 lim:    dw 0
22 addr:   dd 0
23
24         section .text
25 ; void set_idt(uint32_t addr, uint16_t limit)
26         global set_idt
27 set_idt:
28         mov eax, [esp + 4]
29         mov [addr], eax
30         mov ax, [esp + 8]
31         mov [lim], ax
32         lidt [idtr_desc]
33         ret
34
35 ; int get_intr_flag()
36         global get_intr_flag
37 get_intr_flag:
38         pushf
39         pop eax
40         ; bit 9 of eflags is IF
41         shr eax, 9
42         and eax, 1
43         ret
44
45 ; void set_intr_flag(int onoff)
46         global set_intr_flag
47 set_intr_flag:
48         cmp dword [esp + 4], 0
49         jz .off
50         sti
51         ret
52 .off:   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 %macro ientry_err 2
59         global intr_entry_%2
60 intr_entry_%2:
61         push dword %1
62         jmp intr_entry_common
63 %endmacro
64
65 ; interrupt entry without error code macro
66 ; this macro generates an interrupt entry point for the interrupts
67 ; and exceptions which do not include error codes in the stack frame
68 ; it pushes a dummy error code (0), to make the stack frame identical
69 %macro ientry_noerr 2
70         global intr_entry_%2
71 intr_entry_%2:
72         push dword 0
73         push dword %1
74         jmp intr_entry_common
75 %endmacro
76
77 ; common code used by all entry points. calls dispatch_intr()
78 ; defined in intr.c
79         extern dispatch_intr
80 intr_entry_common:
81         ; save general purpose registers
82         pusha
83         call dispatch_intr
84 intr_ret_local:
85         ; restore general purpose registers
86         popa
87         ; remove error code and intr num from stack
88         add esp, 8
89         iret
90
91 ; special case for the timer interrupt, to avoid all the overhead of
92 ; going through the C interrupt dispatcher 250 times each second
93         extern nticks
94         global intr_entry_fast_timer
95 intr_entry_fast_timer:
96         inc dword [nticks]
97         ; signal end of interrupt
98         push eax
99         mov al, 20h
100         out 20h, al
101         pop eax
102         iret
103
104 ; special case for IRQ 7 and IRQ 15, to catch spurious interrupts
105 PIC1_CMD equ 0x20
106 PIC2_CMD equ 0xa0
107 OCW2_EOI equ 0x20
108 OCW3_ISR equ 0x0b
109
110         global irq7_entry_check_spurious
111 irq7_entry_check_spurious:
112         push eax
113         mov al, OCW3_ISR
114         out PIC1_CMD, al
115         in al, PIC1_CMD
116         and al, 80h
117         pop eax
118         jnz intr_entry_irq7
119         iret
120
121         global irq15_entry_check_spurious
122 irq15_entry_check_spurious:
123         push eax
124         mov al, OCW3_ISR
125         out PIC2_CMD, al
126         in al, PIC2_CMD
127         and al, 80h
128         jnz .legit
129         ; it was spurious, send EOI to master PIC and iret
130         mov al, OCW2_EOI
131         out PIC1_CMD, al
132         pop eax
133         iret
134 .legit: pop eax
135         jmp intr_entry_irq15
136
137
138 ; XXX not necessary for now, just leaving it in in case it's useful
139 ; down the road.
140 ;
141 ; intr_ret is called by context_switch to return from the kernel
142 ; to userspace. The argument is a properly formed intr_frame
143 ; structure with the saved context of the new task.
144 ;
145 ; First thing to do is remove the return address pointing back
146 ; to context_switch, which then leaves us with a proper interrupt
147 ; stack frame, so we can jump right in the middle of the regular
148 ; interrupt return code above.
149         global intr_ret
150 intr_ret:
151         add esp, $4
152         jmp intr_ret_local
153
154 ; by including interrupts.h with ASM defined, the macros above
155 ; are expanded to generate all required interrupt entry points
156 %define INTR_ENTRY_EC(n, name)          ientry_err n, name
157 %define INTR_ENTRY_NOEC(n, name)        ientry_noerr n, name
158
159 %include 'intrtab.h'
160
161 ; vi:set ts=8 sts=8 sw=8 ft=nasm: