]> pd.if.org Git - zos/blob - interrupt.c
add a readme with a public domain note
[zos] / interrupt.c
1 #include <stdint.h>
2 #include <stddef.h>
3
4 #include <string.h>
5
6 #include "kernel.h"
7 #include "interrupt.h"
8 #include "cpu.h"
9
10 #include "pic.h"
11
12 #include <process.h>
13
14 struct idt_entry {
15         uint16_t handler_low;
16         uint16_t selector;
17         uint8_t ist;
18         uint8_t flags;
19         uint16_t handler_high;
20         uint32_t handler_highest;
21         uint32_t reserved1;
22 } __attribute__((packed));
23
24 /* in idt.s */
25 void set_idt_entry(struct idt_entry *entry, uintptr_t handler, uint16_t selector,
26               uint8_t flags, uint8_t ist);
27 void load_idt(struct idt_entry *table, size_t length);
28
29 #define NUM_KNOWN_EXCEPTIONS 20
30
31 const char *exception_names[] = {
32         "Divide by zero",              /* 0, 0x0 */
33         "Debug",                       /* 1, 0x1 */
34         "Non maskable interrupt",      /* 2, 0x2 */
35         "Breakpoint",                  /* 3, 0x3 */
36         "Into detected overflow",      /* 4, 0x4 */
37         "Out of bounds",               /* 5, 0x5 */
38         "Invalid opcode",              /* 6, 0x6 */
39         "No coprocessor",              /* 7, 0x7 */
40         "Double fault",                /* 8, 0x8 */
41         "Coprocessor segment overrun", /* 9, 0x9 */
42         "Bad TSS",                     /* 10, 0xA */
43         "Segment not present",         /* 11, 0xB */
44         "Stack fault",                 /* 12, 0xC */
45         "General protection fault",    /* 13, 0xD */
46         "Page fault",                  /* 14, 0xE */
47         "Unknown interrupt",           /* 15, 0xF */
48         "Coprocessor fault",           /* 16, 0x10 */
49         "Alignment check",             /* 17, 0x11 */
50         "Machine check",               /* 18, 0x12 */
51         "SIMD Floating-Point",         /* 19, 0x13 */
52 };
53
54 #define NUM_INTERRUPTS 256
55
56 static struct idt_entry interrupt_table[NUM_INTERRUPTS];
57 static struct interrupt_handler *handlers[NUM_INTERRUPTS];
58
59 /* index is the interrupt number */
60 void interrupt_add_handler(unsigned int index, struct interrupt_handler *handler) {
61         struct interrupt_handler *h;
62         int enabled;
63
64         /* assert(index < NUM_INTERRUPTS); */
65         klog(0,"registering handler %llx\n", (uint64_t)handler->handler);
66         handler->next = NULL;
67         handler->prev = NULL;
68
69         enabled = interrupts_set(0);
70
71         h = handlers[index];
72
73         if (h) {
74                 while (h->next) {
75                         h = h->next;
76                 }
77
78                 /* TODO assembly xor eax,eax; lock cmpxchg [rdi], rsi */
79                 h->next = handler;
80                 handler->prev = h;
81         } else {
82                 handlers[index] = handler;
83         }
84         interrupts_set(enabled);
85 }
86
87 void interrupt_remove_handler(unsigned int index, struct interrupt_handler *handler) {
88         /* assert(index < NUM_INTERRUPTS); */
89         int was_enabled = interrupts_set(0);
90
91         if (handler->prev) {
92                 handler->prev->next = handler->next;
93         } else {
94                 handlers[index] = handler->next;
95         }
96
97         if (handler->next) {
98                 handler->next->prev = handler->prev;
99         }
100
101         interrupts_set(was_enabled);
102 }
103
104
105 #define IDTFLAGS(type, rpl) ( (1 << 7) | type << 0 | rpl << 5 )
106 static void set_table_entry(unsigned int num, void (*handler)(void), int user,
107                 int trap) {
108         uint8_t ist = 0, type, rpl;
109
110         rpl = user ? 3 : 0;
111
112         /* TODO what is the actual difference between these */
113         /* an interrupt clears the interrupt flag, a trap leaves it alone
114          * thus a trap could be further interrupted
115          */
116         type = trap ? 0xF : 0xE;
117
118         /* 0x10 == kernel code segment */
119         set_idt_entry(&interrupt_table[num], (uintptr_t)handler, 0x10, IDTFLAGS(type,rpl), ist);
120 }
121
122 void init_interrupts() {
123         int i;
124
125         /* Initialize the pic and remap the IRQ table */
126         pic_init();
127         pic.reprogram();
128
129         /* Initialize the interrupt table entries to the null interrupt handler. */
130         memset(&interrupt_table, 0, sizeof interrupt_table);
131         for (i = 0; i < NUM_INTERRUPTS; i++) {
132                 set_table_entry(i, interrupt_handler_null, 0, 0);
133         }
134
135         /* cpu internal handlers */
136         set_table_entry(0, isr0, 0, 0);
137         set_table_entry(1, isr1, 0, 0);
138         set_table_entry(2, isr2, 0, 0);
139         set_table_entry(3, isr3, 0, 0);
140         set_table_entry(4, isr4, 0, 0);
141         set_table_entry(5, isr5, 0, 0);
142         set_table_entry(6, isr6, 0, 0);
143         set_table_entry(7, isr7, 0, 0);
144         set_table_entry(8, isr8, 0, 0);
145         set_table_entry(9, isr9, 0, 0);
146         set_table_entry(10, isr10, 0, 0);
147         set_table_entry(11, isr11, 0, 0);
148         set_table_entry(12, isr12, 0, 0);
149         set_table_entry(13, isr13, 0, 0);
150         set_table_entry(14, isr14, 0, 0);
151         set_table_entry(15, isr15, 0, 0);
152         set_table_entry(16, isr16, 0, 0);
153         set_table_entry(17, isr17, 0, 0);
154         set_table_entry(18, isr18, 0, 0);
155         set_table_entry(19, isr19, 0, 0);
156         set_table_entry(20, isr20, 0, 0);
157         set_table_entry(21, isr21, 0, 0);
158         set_table_entry(22, isr22, 0, 0);
159         set_table_entry(23, isr23, 0, 0);
160         set_table_entry(24, isr24, 0, 0);
161         set_table_entry(25, isr25, 0, 0);
162         set_table_entry(26, isr26, 0, 0);
163         set_table_entry(27, isr27, 0, 0);
164         set_table_entry(28, isr28, 0, 0);
165         set_table_entry(29, isr29, 0, 0);
166         set_table_entry(30, isr30, 0, 0);
167         set_table_entry(31, isr31, 0, 0);
168
169         /* hardware interrupts from the pic */
170         set_table_entry(32, irq0, 0, 0);
171         set_table_entry(33, irq1, 0, 0);
172         set_table_entry(34, irq2, 0, 0);
173         set_table_entry(35, irq3, 0, 0);
174         set_table_entry(36, irq4, 0, 0);
175         set_table_entry(37, irq5, 0, 0);
176         set_table_entry(38, irq6, 0, 0);
177         set_table_entry(39, irq7, 0, 0);
178         set_table_entry(40, irq8, 0, 0);
179         set_table_entry(41, irq9, 0, 0);
180         set_table_entry(42, irq10, 0, 0);
181         set_table_entry(43, irq11, 0, 0);
182         set_table_entry(44, irq12, 0, 0);
183         set_table_entry(45, irq13, 0, 0);
184         set_table_entry(46, irq14, 0, 0);
185         set_table_entry(47, irq15, 0, 0);
186
187         /* software interrupt, could be used to force a schedule */
188         set_table_entry(128, isr128, 1, 0);
189         set_table_entry(129, interrupt_handler_null, 0, 1);
190
191         load_idt(interrupt_table, NUM_INTERRUPTS);
192         enable_interrupts();
193         printk("interrupts enabled\n");
194 }
195
196 const char *exceptionstr(int i) {
197         if (i < NUM_KNOWN_EXCEPTIONS) {
198                 return exception_names[i];
199         }
200         return "Unknown";
201 }
202
203 void interrupt_handler(struct interrupt_context *intctx) {
204         int crash;
205         int in_kernel;
206         struct interrupt_handler *h;
207
208         unsigned int int_no = intctx->int_no;
209
210         /* Ignore spurious IRQ 7 and 15 */
211         if ( int_no == IRQ7 && !(pic.readisr() & (1 << 7)) )
212                 return;
213         if ( int_no == IRQ15 && !(pic.readisr() & (1 << 15)) ) {
214                 pic.mastereoi();
215                 return;
216         }
217
218         in_kernel = (intctx->cs & 0x3) == 0;
219         crash = int_no < 32 && int_no != 7; /* I think 7 and 9 can't happen */
220
221         if (crash && in_kernel) {
222                 panic("kernel crash '%s' int %u, rip %llx, cr2 %llx, error %llx, rflags %llx\n",
223                                 exceptionstr(intctx->int_no),
224                                 intctx->int_no, intctx->rip, intctx->cr2, intctx->err_code,
225                                 intctx->rflags);
226         }
227         if (crash && !in_kernel) {
228                 panic("user mode crash: interrupt %u\n", int_no);
229         }
230
231         /* run registered handlers */
232         for (h = handlers[int_no]; h; h = h->next ) {
233                 h->handler(intctx, h->context);
234         }
235
236         /* Send an end of interrupt signal to the PICs if we got an IRQ */
237         if (int_no >= IRQ0 && int_no <= IRQ15) {
238                 pic.eoi(int_no - IRQ0);
239         }
240
241         if (need_schedule()) {
242                 do_schedule();
243         }
244 }
245
246 int interrupts_set(int is_enabled) {
247         int wasenabled = interrupts_enabled();
248         if (is_enabled) {
249                 enable_interrupts();
250         } else {
251                 disable_interrupts();
252         }
253         return wasenabled;
254 }