- Implemented execp*.
[planlOS.git] / system / kernel / ke / interrupts.c
blobac83416b60e1c64dc21ef60d3a50dd3ddfafad3e
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;
283 if (oldthread)
285 oldthread->kernelstack = (uintptr_t)isf;
286 if (isf->cs == 0x1b)
288 oldthread->userframe = oldthread->kernelstack;
292 if (isf->intno < 0x20) {
293 // Exception
294 keExceptionHandler(isf);
295 /*} else if (isf->intno >= 0x80) {
296 if (isf->intno == 0x80) {
297 if (cpu && (isf->cs != 0x8)) {
298 sysSyscall(cpu->currentthread, isf->eax, &isf->ebx, &isf->ecx, &isf->edx, &isf->esi, &isf->edi);
299 } else {
300 // TODO: Panic
303 } else {
304 // Call handler
305 if (isf->intno == 0x80)
307 if (cpu && (isf->cs != 0x8))
309 sysSyscall(cpu->currentthread, isf->eax, &isf->ebx, &isf->ecx, &isf->edx, &isf->esi, &isf->edi);
311 else
313 // TODO: Panic
316 else if (irq_handler[isf->intno - 0x20])
318 irq_handler[isf->intno - 0x20](cpu, isf->intno - 0x20);
320 else
322 if (isf->intno != 0x27)
323 kePrint("Interrupt (%d) without handler (cpu: %d)!\n", isf->intno - 0x20, keAPICGetCPU());
326 if (isf->intno < 0x30) {
327 // Send EOI
328 if (isf->intno >= 0x28) {
329 outb(0xA0, 0x20);
331 outb(0x20, 0x20);
333 if (oldthread)
335 // Kernel stack variable might have been overwritten by now
336 oldthread->kernelstack = (uintptr_t)isf;
338 if (cpu && cpu->currentthread)
340 if (cpu->currentthread->process)
342 uintptr_t pagedir = cpu->currentthread->process->memory.phys_addr;
343 asm volatile("mov %%eax, %%cr3\n" :: "a" (pagedir));
345 //kePrint("CPU %d\n", cpu->id);
346 isf = (void*)cpu->currentthread->kernelstack;
347 if (isf->cs == 0x8)
348 tss[keAPICGetCPU()].esp0 = cpu->currentthread->kernelstack + 17 * 4;
349 else
350 tss[keAPICGetCPU()].esp0 = cpu->currentthread->kernelstack + 19 * 4;
351 if (cpu)
353 cpu->level = KE_LEVEL_NORMAL;
354 cpu->interrupt = 0;
355 if (oldthread && (oldthread != cpu->currentthread))
357 keUnlockSpinlock(&oldthread->active);
360 return (void*)cpu->currentthread->kernelstack;
363 if (cpu)
365 cpu->level = KE_LEVEL_NORMAL;
366 cpu->interrupt = 0;
367 if (oldthread && (oldthread != cpu->currentthread))
369 keUnlockSpinlock(&oldthread->active);
372 return isf;
375 void keRegisterIRQ(uint32_t irqno, void (*handler)(KeCPU*, uint8_t))
377 irq_handler[irqno] = handler;
378 if (irqno >= 0x10) return;
379 if (handler)
381 if (irqno < 8)
383 outb(0x21, inb(0x21) & ~(0x1 << irqno));
385 else
387 outb(0xa1, inb(0xa1) & ~(0x1 << (irqno - 8)));
390 else
392 if (irqno < 8)
394 outb(0x21, inb(0x21) | (0x1 << irqno));
396 else
398 outb(0xa1, inb(0xa1) | (0x1 << irqno));