- Fixed memory management.
[planlOS.git] / system / kernel / ke / interrupts.c
blob91d5fb3c80cc9e485586ecd93ebd1149078d2523
1 /*
2 Copyright (C) 2008 Mathias Gottschlag
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in the
6 Software without restriction, including without limitation the rights to use,
7 copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
8 Software, and to permit persons to whom the Software is furnished to do so,
9 subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
16 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
17 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
18 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
19 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 #include "ke/interrupts.h"
23 #include "ke/debug.h"
24 #include "ke/ports.h"
25 #include "ke/gdt.h"
26 #include "ke/apic.h"
27 #include "ke/module.h"
28 #include "ke/panic.h"
29 #include "sys/syscall.h"
30 #include "mm/memory.h"
32 #include <string.h>
34 static IDTEntry idt[256];
35 extern uint32_t kernel_directory[1024];
37 static void keSetIDTEntry(int intno, void (*handler)(void), int dpl)
39 IDTEntry entry;
40 entry.zero = 0;
41 entry.offset_low = (uint32_t)handler & 0x0000FFFF;
42 entry.offset_high = (uint32_t)handler >> 16;
43 entry.selector = 0x8;
44 entry.type = 0x8e + ((dpl & 0x3) << 5);
45 idt[intno] = entry;
48 static void keStopCPU(KeCPU *cpu, uint8_t intno)
50 asm("hlt");
52 static void keDummy(KeCPU *cpu, uint8_t intno);
53 static void keStopThread(KeCPU *cpu, uint8_t intno)
55 if (!cpu->currentthread) return;
56 keDestroyThread(cpu->currentthread);
57 keDummy(cpu, intno);
59 static void keDummy(KeCPU *cpu, uint8_t intno)
61 KeThread *newthread = keGetSchedulableThread(0);
62 if (newthread)
64 cpu->currentthread = newthread;
66 else
68 keLockSpinlock(&cpu->idlethread->active);
69 cpu->currentthread = cpu->idlethread;
72 static void keReloadPagedir(KeCPU *cpu, uint8_t intno)
74 kePrint("[1]");
75 if (cpu->currentthread)
77 if (!cpu->currentthread->process)
79 asm volatile("mov %%eax, %%cr3" :: "a" ((uintptr_t)kernel_directory - MM_KERNEL_BASE));
82 kePrint("[2]");
85 void keInitPIC(void)
87 memset(idt, 0, sizeof(IDTEntry) * 256);
89 // Remap PIC
90 outb(0x20, 0x11);
91 outb(0xa0, 0x11);
92 outb(0x21, 0x20);
93 outb(0xa1, 0x28);
94 outb(0x21, 0x04);
95 outb(0xa1, 0x02);
96 outb(0x21, 0x01);
97 outb(0xa1, 0x01);
98 outb(0x21, 0xfb);
99 outb(0xa1, 0xff);
101 // Fill IDT
102 keSetIDTEntry(0x00, keInt00, 0);
103 keSetIDTEntry(0x01, keInt01, 0);
104 keSetIDTEntry(0x02, keInt02, 0);
105 keSetIDTEntry(0x03, keInt03, 0);
106 keSetIDTEntry(0x04, keInt04, 0);
107 keSetIDTEntry(0x05, keInt05, 0);
108 keSetIDTEntry(0x06, keInt06, 0);
109 keSetIDTEntry(0x07, keInt07, 0);
110 keSetIDTEntry(0x08, keInt08, 0);
111 keSetIDTEntry(0x09, keInt09, 0);
112 keSetIDTEntry(0x0a, keInt0a, 0);
113 keSetIDTEntry(0x0b, keInt0b, 0);
114 keSetIDTEntry(0x0c, keInt0c, 0);
115 keSetIDTEntry(0x0d, keInt0d, 0);
116 keSetIDTEntry(0x0e, keInt0e, 0);
117 keSetIDTEntry(0x0f, keInt0f, 0);
118 keSetIDTEntry(0x10, keInt10, 0);
119 keSetIDTEntry(0x11, keInt11, 0);
120 keSetIDTEntry(0x12, keInt12, 0);
121 keSetIDTEntry(0x13, keInt13, 0);
122 keSetIDTEntry(0x14, keInt14, 0);
123 keSetIDTEntry(0x15, keInt15, 0);
124 keSetIDTEntry(0x16, keInt16, 0);
125 keSetIDTEntry(0x17, keInt17, 0);
126 keSetIDTEntry(0x18, keInt18, 0);
127 keSetIDTEntry(0x19, keInt19, 0);
128 keSetIDTEntry(0x1a, keInt1a, 0);
129 keSetIDTEntry(0x1b, keInt1b, 0);
130 keSetIDTEntry(0x1c, keInt1c, 0);
131 keSetIDTEntry(0x1d, keInt1d, 0);
132 keSetIDTEntry(0x1e, keInt1e, 0);
133 keSetIDTEntry(0x1f, keInt1f, 0);
135 keSetIDTEntry(0x20, keInt20, 0);
136 keSetIDTEntry(0x21, keInt21, 0);
137 keSetIDTEntry(0x22, keInt22, 0);
138 keSetIDTEntry(0x23, keInt23, 0);
139 keSetIDTEntry(0x24, keInt24, 0);
140 keSetIDTEntry(0x25, keInt25, 0);
141 keSetIDTEntry(0x26, keInt26, 0);
142 keSetIDTEntry(0x27, keInt27, 0);
143 keSetIDTEntry(0x28, keInt28, 0);
144 keSetIDTEntry(0x29, keInt29, 0);
145 keSetIDTEntry(0x2a, keInt2a, 0);
146 keSetIDTEntry(0x2b, keInt2b, 0);
147 keSetIDTEntry(0x2c, keInt2c, 0);
148 keSetIDTEntry(0x2d, keInt2d, 0);
149 keSetIDTEntry(0x2e, keInt2e, 0);
150 keSetIDTEntry(0x2f, keInt2f, 0);
152 keSetIDTEntry(0x30, keInt30, 0);
153 keSetIDTEntry(0x31, keInt31, 0);
154 keSetIDTEntry(0x32, keInt32, 0);
155 keSetIDTEntry(0x33, keInt33, 0);
156 keSetIDTEntry(0x34, keInt34, 0);
157 keSetIDTEntry(0x35, keInt35, 0);
158 keSetIDTEntry(0x36, keInt36, 0);
159 keSetIDTEntry(0x37, keInt37, 0);
161 keSetIDTEntry(0x80, keInt80, 3);
163 // Enable IDT
164 IDTDescriptor desc;
165 desc.size = 256 * sizeof(IDTEntry) - 1;
166 desc.base = (uint32_t)idt;
168 asm("lidt %0"::"m"(desc));
170 // Install standard handlers
171 // 0x31 = Crash-IPI
172 keRegisterIRQ(0x11, keStopCPU);
173 // 0x32 = Dummy interrupt (used to schedule out of a thread)
174 keRegisterIRQ(0x12, keDummy);
175 // 0x33 = Stop current thread
176 keRegisterIRQ(0x13, keStopThread);
177 // 0x34 = Reload page directory
178 keRegisterIRQ(0x14, keReloadPagedir);
181 void keInitPIC2(void)
183 // Enable IDT
184 IDTDescriptor desc;
185 desc.size = 256 * sizeof(IDTEntry) - 1;
186 desc.base = (uint32_t)idt;
188 asm("lidt %0"::"m"(desc));
191 void keExceptionHandler(IntStackFrame *isf)
193 //kePrint("\nStack frame: %x\n", isf);
194 /*if (isf->cs == 0x8)
196 /*// TODO: Don't kill kernel on non-critical exceptions
197 // Print register info
198 if (isf->intno == 14) {
199 uint32_t cr2;
200 asm("mov %%cr2, %0":"=r"(cr2));
201 kePrint("\nPanic:\nCPU %d\nPage fault at %x, error code: %x\n\n", keAPICGetCPU(), cr2, isf->error);
202 char *function = 0;
203 uint32_t offset = 0;
204 int status = keResolveAddress(isf->eip, &function, &offset);
205 if (!status)
207 kePrint("in function %s+%x\n", function, offset);
209 else
211 kePrint("Unknown function.\n");
213 } else {
214 kePrint("\n\nPanic:\nException %d, error code: %x\n\n", isf->intno, isf->error);
216 kePrint("eax: %x\tebx: %x\tecx: %x\tedx: %x\n", isf->eax, isf->ebx, isf->ecx, isf->edx);
217 kePrint("ds: %x\tes: %x\tfs: %x\tgs: %x\n", isf->ds, isf->es, isf->fs, isf->gs);
218 kePrint("ss: %x\tesp: %x\tcs: %x\teip: %x\n", isf->ss, isf->esp, isf->cs, isf->eip);
219 kePrint("eflags: %x\n", isf->eflags);
220 asm("cli");
221 asm("hlt");
222 while(1);*/
223 kePanic(isf, 0);
225 else
227 // Print register info
228 if (isf->intno == 14) {
229 uint32_t cr2;
230 asm("mov %%cr2, %0":"=r"(cr2));
231 if (current_thread && (cr2 < current_thread->userstack + 0x400000) && (cr2 > current_thread->userstack))
233 // Just grow stack
234 uint32_t *page_dir = (uint32_t*)halFindContinuousPages(kernel_directory, 1, 0xE0000000, 0xFFFFFFFF);
235 halMapPage(kernel_directory, (uint32_t)page_dir, ((X86Task*)current_thread->thread.task)->pagedir, 0x3);
236 uintptr_t userstack_phys = halAllocPhysPage();
237 halMapPage(page_dir, cr2 & ~0xFFF, userstack_phys, 0x7);
238 halMapPage(kernel_directory, (uint32_t)page_dir, 0, 0x0);
239 return;
241 kePrint("\nProcess killed:\nPage fault at %x, error code: %x\n\n", cr2, isf->error);
242 if (current_thread && current_thread->thread.task)
244 kePrint("Task: %d, thread: %d\n\n", current_thread->thread.task->id, current_thread->thread.id);
246 } else {
247 kePrint("\n\nProcess killed:\nException %d, error code: %x\n\n", isf->intno, isf->error);
249 kePrint("eax: %x\tebx: %x\tecx: %x\tedx: %x\n", isf->eax, isf->ebx, isf->ecx, isf->edx);
250 kePrint("ds: %x\tes: %x\tfs: %x\tgs: %x\n", isf->ds, isf->es, isf->fs, isf->gs);
251 kePrint("ss: %x\tesp: %x\tcs: %x\teip: %x\n", isf->ss, isf->esp, isf->cs, isf->eip);
252 kePrint("eflags: %x\n", isf->eflags);
253 // Kill task
254 Task *task = current_thread->thread.task;
255 while (task->threadcount > 0)
257 Thread *thread0 = task->threads[0];
258 sysRemoveThread(thread0);
259 halDestroyThread(thread0);
261 halDestroyTask(task);
262 }*/
265 /*inline void keSyscall(void)
267 IntStackFrame *isf = (IntStackFrame*)current_thread->kernelstack;
268 sysSyscall(&current_thread->thread, isf->eax, &isf->ebx, &isf->ecx, &isf->edx, &isf->esi, &isf->edi);
271 void (*irq_handler[128])(KeCPU*, uint8_t);
273 void *keIntHandler(IntStackFrame *isf)
275 KeCPU *cpu = keGetCurrentCPU();
276 KeThread *oldthread = 0;
277 if (cpu)
279 cpu->level = KE_LEVEL_HIGH;
280 cpu->interrupt = 1;
281 oldthread = cpu->currentthread;
284 if (isf->intno < 0x20) {
285 // Exception
286 keExceptionHandler(isf);
287 /*} else if (isf->intno >= 0x80) {
288 if (isf->intno == 0x80) {
289 if (cpu && (isf->cs != 0x8)) {
290 sysSyscall(cpu->currentthread, isf->eax, &isf->ebx, &isf->ecx, &isf->edx, &isf->esi, &isf->edi);
291 } else {
292 // TODO: Panic
295 } else {
296 KeThread *oldthread = cpu->currentthread;
297 if (cpu && cpu->currentthread)
299 cpu->currentthread->kernelstack = (uintptr_t)isf;
301 // Call handler
302 if (isf->intno == 0x80)
304 if (cpu && (isf->cs != 0x8))
306 sysSyscall(cpu->currentthread, isf->eax, &isf->ebx, &isf->ecx, &isf->edx, &isf->esi, &isf->edi);
308 else
310 // TODO: Panic
313 else if (irq_handler[isf->intno - 0x20])
315 irq_handler[isf->intno - 0x20](cpu, isf->intno - 0x20);
317 else
319 if (isf->intno != 0x27)
320 kePrint("Interrupt (%d) without handler (cpu: %d)!\n", isf->intno - 0x20, keAPICGetCPU());
323 if (isf->intno < 0x30) {
324 // Send EOI
325 if (isf->intno >= 0x28) {
326 outb(0xA0, 0x20);
328 outb(0x20, 0x20);
330 if (oldthread)
332 // Kernel stack variable might have been overwritten by now
333 oldthread->kernelstack = (uintptr_t)isf;
335 if (cpu && cpu->currentthread)
337 if (cpu->currentthread->process)
339 uintptr_t pagedir = cpu->currentthread->process->memory.phys_addr;
340 asm volatile("mov %%eax, %%cr3\n" :: "a" (pagedir));
342 //kePrint("CPU %d\n", cpu->id);
343 isf = (void*)cpu->currentthread->kernelstack;
344 if (isf->cs == 0x8)
345 tss[keAPICGetCPU()].esp0 = cpu->currentthread->kernelstack + 17 * 4;
346 else
347 tss[keAPICGetCPU()].esp0 = cpu->currentthread->kernelstack + 19 * 4;
348 if (cpu)
350 cpu->level = KE_LEVEL_NORMAL;
351 cpu->interrupt = 0;
352 if (oldthread && (oldthread != cpu->currentthread))
354 keUnlockSpinlock(&oldthread->active);
357 return (void*)cpu->currentthread->kernelstack;
360 if (cpu)
362 cpu->level = KE_LEVEL_NORMAL;
363 cpu->interrupt = 0;
364 if (oldthread && (oldthread != cpu->currentthread))
366 keUnlockSpinlock(&oldthread->active);
369 return isf;
372 void keRegisterIRQ(uint32_t irqno, void (*handler)(KeCPU*, uint8_t))
374 irq_handler[irqno] = handler;
375 if (irqno >= 0x10) return;
376 if (handler)
378 if (irqno < 8)
380 outb(0x21, inb(0x21) & ~(0x1 << irqno));
382 else
384 outb(0xa1, inb(0xa1) & ~(0x1 << (irqno - 8)));
387 else
389 if (irqno < 8)
391 outb(0x21, inb(0x21) | (0x1 << irqno));
393 else
395 outb(0xa1, inb(0xa1) | (0x1 << irqno));