stdlibc: ~several fixes
[meinos.git] / kernel2 / interrupt.c
blobd0d2f82ca2706e81b7a536733f2eb3ddeff684ba
1 /*
2 meinOS - A unix-like x86 microkernel operating system
3 Copyright (C) 2008 Janosch Gräf <janosch.graef@gmx.net>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include <sys/types.h>
20 #include <interrupt.h>
21 #include <stdint.h>
22 #include <kprint.h>
23 #include <vga.h>
24 #include <cpu.h>
25 #include <pic.h>
26 #include <lapic.h>
27 #include <syscall.h>
28 #include <memuser.h>
29 #include <llist.h>
30 #include <signal.h>
31 #include <memmap.h>
32 #include <procm.h>
33 #include <elf.h>
35 #define STACKTRACE
37 /**
38 * Initializes Interrupts
39 * @return 0=Success; -1=Failure
41 int interrupt_init() {
42 size_t i;
43 interrupt_enabled = 0;
44 interrupt_sleep = llist_create();
45 for (i=0;i<16;i++) interrupt_irq[i] = llist_create();
46 if (syscall_create(SYSCALL_IRQ_HANDLER,interrupt_irq_reghandler,2)==-1) return -1;
47 if (syscall_create(SYSCALL_IRQ_SLEEP,interrupt_irq_sleep,1)==-1) return -1;
48 if (syscall_create(SYSCALL_TIME_SLEEP,interrupt_time_sleep,1)==-1) return -1;
49 if (syscall_create(SYSCALL_TIME_USLEEP,interrupt_time_usleep,1)==-1) return -1;
50 if (syscall_create(SYSCALL_TIME_GETTICKS,interrupt_time_getticks,0)==-1) return -1;
51 return 0;
54 /**
55 * Interrupt handler
56 * @param interrupt Interrupt number
58 void interrupt_handler(unsigned int interrupt,uint32_t *stack) {
59 asm("mov %%ss,%0; mov %0,%%ds"::"r"(0));
60 cpu_t *cpu = cpu_this;
62 uint32_t errorcode = 0;
63 interrupt_save_stack(stack,&errorcode);
65 // Exceptions
66 if (interrupt<0x20 && interrupt!=0x0F) interrupt_exception_handler(interrupt,errorcode);
68 // IRQs
69 if (interrupt>0x1F && interrupt<0x30) interrupt_irq_handler(interrupt-0x20);
70 if (!cpu->uselapic && interrupt==0x30) interrupt_irq_handler(0);
72 // LAPIC
73 if (cpu->uselapic && interrupt>0x2F && interrupt<0x37 && interrupt==0x0F) interrupt_lapic_handler(interrupt);
75 asm("mov %%es,%0; mov %0,%%ds"::"r"(0));
77 if (proc_current==NULL) proc_shedule();
80 /**
81 * Timer (PIC or LAPIC)
83 void interrupt_timer() {
84 cpu_t *cpu = cpu_this;
85 cpu->ticks++;
86 interrupt_time_check(cpu->interval*1000);
87 proc_shedule();
90 /**
91 * LAPIC interrupt handler
92 * @param interrupt Interrupt
94 void interrupt_lapic_handler(unsigned int interrupt) {
95 lapic_eoi();
96 if (interrupt==0x30) interrupt_timer();
99 /**
100 * IRQ handler
101 * @param irq IRQ
103 void interrupt_irq_handler(unsigned int irq) {
104 pic_eoi(irq);
105 if (irq==0) interrupt_timer();
106 else interrupt_irq_check(irq);
110 * Exception handler
111 * @param exception Exception number
113 void interrupt_exception_handler(unsigned int exception,uint32_t errcode) {
114 char *exceptions[] = {
115 "Divide Error",
116 "Debug Exception",
117 "Intel reserved",
118 "Breakpoint",
119 "Overflow",
120 "Bounds Check",
121 "Invalid Opcode",
122 "Coprocessor Not Available",
123 "Double Fault",
124 "Coprocessor Segment Overrun",
125 "Invalid TSS",
126 "Segment Not Present",
127 "Stack Exception",
128 "General Protection Fault",
129 "Page Fault",
130 "Intel reserved",
131 "Coprocessor Error"
134 uint32_t cr2;
135 asm("mov %%cr2,%0":"=a"(cr2));
136 errcode &= 0xFFFF;
138 if (exception==INTERRUPT_EXCEPTION_PAGE_FAULT) {
139 if (memuser_pagefault((void*)cr2)==0) return;
141 vga_text_cursor.color = VGA_TEXT_COLOR_RED_BLACK;
142 kprintf(" **EXCEPTION[0x%x]: %s from %s (by EIP)\n",exception,exception<0x10?exceptions[exception]:"Unknown",*interrupt_curregs.eip<USERDATA_ADDRESS?"Kernel":"Userland");
143 if (proc_current!=NULL) kprintf("Process: #%d %s\n",proc_current->pid,proc_current->name);
144 else kprintf("Process: none\n");
145 vga_text_cursor.color = VGA_TEXT_COLOR_DEFAULT;
146 kprintf("EAX: 0x%x\tEBX: 0x%x\tECX: 0x%x\tEDX: 0x%x\n",*interrupt_curregs.eax,*interrupt_curregs.ebx,*interrupt_curregs.ecx,*interrupt_curregs.edx);
147 kprintf("EIP: 0x%x\tEFL: 0x%x\tEBP: 0x%x\tESP: 0x%x\n",*interrupt_curregs.eip,*interrupt_curregs.efl,*interrupt_curregs.ebp,*interrupt_curregs.esp);
148 kprintf("EDI: 0x%x\tESI: 0x%x\n",*interrupt_curregs.edi,*interrupt_curregs.esi);
149 kprintf("CS: 0x%x\tDS: 0x%x\tES: 0x%x\tFS: 0x%x\n",*interrupt_curregs.cs,*interrupt_curregs.ds,*interrupt_curregs.es,*interrupt_curregs.fs);
150 kprintf("GS: 0x%x\tSS: 0x%x\n",interrupt_curregs.gs,interrupt_curregs.ss);
151 if (exception==INTERRUPT_EXCEPTION_PAGE_FAULT) {
152 kprintf("Pagefault at: 0x%x\n",cr2);
153 kprintf("%s by %s from %s\n",(errcode&1)?"Rights violation":"Accessing a not present page",(errcode&8)?"instruction fetch":((errcode&2)?"writing":"reading"),(errcode&4)?proc_current->name:"Kernel");
155 else if (errcode!=0) {
156 kprintf("%s error in %s at index 0x%x\n",(errcode&1)?"External":"Internal",(errcode&2)?"IDT":((errcode&4)?"LDT":"GDT"),(errcode&0xFFF8)>>3);
159 #ifdef STACKTRACE
160 if (*interrupt_curregs.esp>=0x4000000 && *interrupt_curregs.esp<0x40001000) {
161 int *i;
162 kprintf("Stack:\n");
163 for (i=(int*)*interrupt_curregs.esp;i<(int*)0x40001000;i++) kprintf("0x%x:\t0x%x\n",i,*i);
165 #endif
167 cpu_halt();
169 if (exception==INTERRUPT_EXCEPTION_PAGE_FAULT) kill(proc_current,SIGSEGV);
170 else if (exception==INTERRUPT_EXCEPTION_INVALID_OPCODE) kill(proc_current,SIGILL);
171 else kill(proc_current,SIGKILL);
173 /// @todo just change process
174 proc_idle();
178 * Enables/Disables interrupts
179 * @param enable Whether to enable or disable interrupts
181 void interrupt_enable(int enable) {
182 interrupt_enabled = enable;
183 if (enable) asm("sti");
184 else asm("cli");
188 * Registers an IRQ handler (Syscall)
189 * @param irq IRQ
190 * @param func Function
192 int interrupt_irq_reghandler(unsigned int irq,void *func) {
193 if (irq<16) {
194 interrupt_irq_t *new = malloc(sizeof(interrupt_irq_t));
195 new->func = func;
196 new->proc = proc_current;
197 new->type = IRQ_HANDLER;
198 llist_push(interrupt_irq[irq],new);
199 return 0;
201 else return -1;
205 * Sleeps until an IRQ is fired (Syscall)
206 * @param irq IRQ
208 int interrupt_irq_sleep(unsigned int irq) {
209 if (irq<16) {
210 interrupt_irq_t *new = malloc(sizeof(interrupt_irq_t));
211 new->proc = proc_current;
212 new->type = IRQ_SLEEP;
213 llist_push(interrupt_irq[irq],new);
214 return 0;
216 else return -1;
220 * Checks for IRQ events
221 * @param irq IRQ
223 void interrupt_irq_check(unsigned int irq) {
224 interrupt_irq_t *irqo;
225 size_t i;
226 for (i=0;(irqo = llist_get(interrupt_irq[irq],i));i++) {
227 if (irqo->type==IRQ_SLEEP) {
228 proc_wake(irqo->proc);
229 free(irqo);
230 llist_remove(interrupt_irq[irq],i);
231 i--;
233 else proc_call(irqo->proc,irqo->func,1,irq);
238 * Sleeps until an time elapsed (Syscall)
239 * @param sec Seconds
241 int interrupt_time_sleep(unsigned int sec) {
242 interrupt_sleep_t *new = malloc(sizeof(interrupt_sleep_t));
243 new->type = TIME_SLEEP;
244 new->usec = sec*1000000;
245 new->proc = proc_current;
246 llist_push(interrupt_sleep,new);
247 proc_sleep(proc_current);
248 return 0;
252 * Sleeps until an time elapsed (Syscall)
253 * @param sec Microseconds
255 int interrupt_time_usleep(unsigned int usec) {
256 interrupt_sleep_t *new = malloc(sizeof(interrupt_sleep_t));
257 new->type = TIME_SLEEP;
258 new->usec = usec;
259 new->proc = proc_current;
260 llist_push(interrupt_sleep,new);
261 proc_sleep(proc_current);
262 return 0;
266 * Checks for ending sleeps
267 * @param usec Time since last check
269 void interrupt_time_check(unsigned int usec) {
270 interrupt_sleep_t *sleep;
271 size_t i;
272 for (i=0;(sleep = llist_get(interrupt_sleep,i));i++) {
273 if (sleep->usec<=usec) {
274 if (sleep->type==TIME_SLEEP) proc_wake(sleep->proc);
275 llist_remove(interrupt_sleep,i);
276 i--;
278 else sleep->usec -= usec;
283 * Gets number of ticks since boot
284 * @return Number of ticks
286 clock_t interrupt_time_getticks() {
287 return cpu_this->ticks;
290 uint32_t *interrupt_save_stack(uint32_t *stack,uint32_t *errorcode) {
291 interrupt_curregs.edi = stack++;
292 interrupt_curregs.esi = stack++;
293 interrupt_curregs.ebp = stack++;
294 stack++; // esp
295 interrupt_curregs.ebx = stack++;
296 interrupt_curregs.edx = stack++;
297 interrupt_curregs.ecx = stack++;
298 interrupt_curregs.eax = stack++;
299 interrupt_curregs.ds = stack++;
300 interrupt_curregs.es = stack++;
301 interrupt_curregs.fs = stack++;
302 interrupt_curregs.gs = stack++;
303 if (errorcode!=NULL) *errorcode = *stack++; // error code
304 else stack++;
305 interrupt_curregs.eip = stack++;
306 interrupt_curregs.cs = stack++;
307 interrupt_curregs.efl = stack++;
308 interrupt_curregs.esp = stack++;
309 interrupt_curregs.ss = stack++;
310 vm86_curregs.es = stack++;
311 vm86_curregs.ds = stack++;
312 vm86_curregs.fs = stack++;
313 vm86_curregs.gs = stack++;
315 /*kprintf("Stack: 0x%x\n",stack);
316 kprintf("EDI: 0x%x\n",*interrupt_curregs.edi);
317 kprintf("ESI: 0x%x\n",*interrupt_curregs.esi);
318 kprintf("EBP: 0x%x\n",*interrupt_curregs.ebp);
319 kprintf("EBX: 0x%x\n",*interrupt_curregs.ebx);
320 kprintf("EDX: 0x%x\n",*interrupt_curregs.edx);
321 kprintf("ECX: 0x%x\n",*interrupt_curregs.ecx);
322 kprintf("EAX: 0x%x\n",*interrupt_curregs.eax);
323 kprintf("ERR: 0x%x\n",*errorcode);
324 kprintf("EIP: 0x%x\n",*interrupt_curregs.eip);
325 kprintf("CS: 0x%x\n",*interrupt_curregs.cs);
326 kprintf("EFL: 0x%x\n",*interrupt_curregs.efl);
327 kprintf("ESP: 0x%x\n",*interrupt_curregs.esp);
328 kprintf("DS: 0x%x\n",*interrupt_curregs.ds);
329 kprintf("ES: 0x%x\n",*interrupt_curregs.es);
330 kprintf("FS: 0x%x\n",*interrupt_curregs.fs);
331 kprintf("GS: 0x%x\n",*interrupt_curregs.gs);
332 kprintf("SS: 0x%x\n",*interrupt_curregs.ss);*/
334 return stack;