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"
27 #include "ke/module.h"
29 #include "sys/syscall.h"
30 #include "mm/memory.h"
34 static IDTEntry idt
[256];
35 extern uint32_t kernel_directory
[1024];
37 static void keSetIDTEntry(int intno
, void (*handler
)(void), int dpl
)
41 entry
.offset_low
= (uint32_t)handler
& 0x0000FFFF;
42 entry
.offset_high
= (uint32_t)handler
>> 16;
44 entry
.type
= 0x8e + ((dpl
& 0x3) << 5);
48 static void keStopCPU(KeCPU
*cpu
, uint8_t intno
)
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
);
59 static void keDummy(KeCPU
*cpu
, uint8_t intno
)
61 KeThread
*newthread
= keGetSchedulableThread(0);
64 cpu
->currentthread
= newthread
;
68 keLockSpinlock(&cpu
->idlethread
->active
);
69 cpu
->currentthread
= cpu
->idlethread
;
72 static void keReloadPagedir(KeCPU
*cpu
, uint8_t intno
)
75 if (cpu
->currentthread
)
77 if (!cpu
->currentthread
->process
)
79 asm volatile("mov %%eax, %%cr3" :: "a" ((uintptr_t)kernel_directory
- MM_KERNEL_BASE
));
87 memset(idt
, 0, sizeof(IDTEntry
) * 256);
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);
165 desc
.size
= 256 * sizeof(IDTEntry
) - 1;
166 desc
.base
= (uint32_t)idt
;
168 asm("lidt %0"::"m"(desc
));
170 // Install standard handlers
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)
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) {
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);
204 int status = keResolveAddress(isf->eip, &function, &offset);
207 kePrint("in function %s+%x\n", function, offset);
211 kePrint("Unknown function.\n");
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);
227 // Print register info
228 if (isf->intno == 14) {
230 asm("mov %%cr2, %0":"=r"(cr2));
231 if (current_thread && (cr2 < current_thread->userstack + 0x400000) && (cr2 > current_thread->userstack))
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);
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);
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);
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);
265 /*inline void keSyscall(void)
267 IntStackFrame *isf = (IntStackFrame*)current_thread->kernelstack;
268 sysSyscall(¤t_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;
279 cpu
->level
= KE_LEVEL_HIGH
;
281 oldthread
= cpu
->currentthread
;
285 oldthread
->kernelstack
= (uintptr_t)isf
;
288 oldthread
->userframe
= oldthread
->kernelstack
;
292 if (isf
->intno
< 0x20) {
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);
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
);
316 else if (irq_handler
[isf
->intno
- 0x20])
318 irq_handler
[isf
->intno
- 0x20](cpu
, isf
->intno
- 0x20);
322 if (isf
->intno
!= 0x27)
323 kePrint("Interrupt (%d) without handler (cpu: %d)!\n", isf
->intno
- 0x20, keAPICGetCPU());
326 if (isf
->intno
< 0x30) {
328 if (isf
->intno
>= 0x28) {
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
;
348 tss
[keAPICGetCPU()].esp0
= cpu
->currentthread
->kernelstack
+ 17 * 4;
350 tss
[keAPICGetCPU()].esp0
= cpu
->currentthread
->kernelstack
+ 19 * 4;
353 cpu
->level
= KE_LEVEL_NORMAL
;
355 if (oldthread
&& (oldthread
!= cpu
->currentthread
))
357 keUnlockSpinlock(&oldthread
->active
);
360 return (void*)cpu
->currentthread
->kernelstack
;
365 cpu
->level
= KE_LEVEL_NORMAL
;
367 if (oldthread
&& (oldthread
!= cpu
->currentthread
))
369 keUnlockSpinlock(&oldthread
->active
);
375 void keRegisterIRQ(uint32_t irqno
, void (*handler
)(KeCPU
*, uint8_t))
377 irq_handler
[irqno
] = handler
;
378 if (irqno
>= 0x10) return;
383 outb(0x21, inb(0x21) & ~(0x1 << irqno
));
387 outb(0xa1, inb(0xa1) & ~(0x1 << (irqno
- 8)));
394 outb(0x21, inb(0x21) | (0x1 << irqno
));
398 outb(0xa1, inb(0xa1) | (0x1 << irqno
));