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>
38 * Initializes Interrupts
39 * @return 0=Success; -1=Failure
41 int interrupt_init() {
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;
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
);
66 if (interrupt
<0x20 && interrupt
!=0x0F) interrupt_exception_handler(interrupt
,errorcode
);
69 if (interrupt
>0x1F && interrupt
<0x30) interrupt_irq_handler(interrupt
-0x20);
70 if (!cpu
->uselapic
&& interrupt
==0x30) interrupt_irq_handler(0);
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();
81 * Timer (PIC or LAPIC)
83 void interrupt_timer() {
84 cpu_t
*cpu
= cpu_this
;
86 interrupt_time_check(cpu
->interval
*1000);
91 * LAPIC interrupt handler
92 * @param interrupt Interrupt
94 void interrupt_lapic_handler(unsigned int interrupt
) {
96 if (interrupt
==0x30) interrupt_timer();
103 void interrupt_irq_handler(unsigned int irq
) {
105 if (irq
==0) interrupt_timer();
106 else interrupt_irq_check(irq
);
111 * @param exception Exception number
113 void interrupt_exception_handler(unsigned int exception
,uint32_t errcode
) {
114 char *exceptions
[] = {
122 "Coprocessor Not Available",
124 "Coprocessor Segment Overrun",
126 "Segment Not Present",
128 "General Protection Fault",
135 asm("mov %%cr2,%0":"=a"(cr2
));
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);
160 if (*interrupt_curregs
.esp
>=0x4000000 && *interrupt_curregs
.esp
<0x40001000) {
163 for (i
=(int*)*interrupt_curregs
.esp
;i
<(int*)0x40001000;i
++) kprintf("0x%x:\t0x%x\n",i
,*i
);
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
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");
188 * Registers an IRQ handler (Syscall)
190 * @param func Function
192 int interrupt_irq_reghandler(unsigned int irq
,void *func
) {
194 interrupt_irq_t
*new = malloc(sizeof(interrupt_irq_t
));
196 new->proc
= proc_current
;
197 new->type
= IRQ_HANDLER
;
198 llist_push(interrupt_irq
[irq
],new);
205 * Sleeps until an IRQ is fired (Syscall)
208 int interrupt_irq_sleep(unsigned int irq
) {
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);
220 * Checks for IRQ events
223 void interrupt_irq_check(unsigned int irq
) {
224 interrupt_irq_t
*irqo
;
226 for (i
=0;(irqo
= llist_get(interrupt_irq
[irq
],i
));i
++) {
227 if (irqo
->type
==IRQ_SLEEP
) {
228 proc_wake(irqo
->proc
);
230 llist_remove(interrupt_irq
[irq
],i
);
233 else proc_call(irqo
->proc
,irqo
->func
,1,irq
);
238 * Sleeps until an time elapsed (Syscall)
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
);
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
;
259 new->proc
= proc_current
;
260 llist_push(interrupt_sleep
,new);
261 proc_sleep(proc_current
);
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
;
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
);
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
++;
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
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);*/