kern
diff src/intr.c @ 55:88a6c4e192f9
Fixed most important task switching bugs.
Now it seems that I can switch in and out of user space reliably.
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 15 Aug 2011 04:03:39 +0300 |
parents | fa65b4f45366 |
children |
line diff
1.1 --- a/src/intr.c Sun Aug 14 16:57:23 2011 +0300 1.2 +++ b/src/intr.c Mon Aug 15 04:03:39 2011 +0300 1.3 @@ -4,6 +4,7 @@ 1.4 #include "segm.h" 1.5 #include "asmops.h" 1.6 #include "panic.h" 1.7 +#include "syscall.h" 1.8 1.9 /* IDT gate descriptor bits */ 1.10 #define GATE_TASK (5 << 8) 1.11 @@ -49,6 +50,7 @@ 1.12 static intr_func_t intr_func[256]; 1.13 1.14 static struct intr_frame *cur_intr_frame; 1.15 +static int eoi_pending; 1.16 1.17 1.18 void init_intr(void) 1.19 @@ -74,6 +76,7 @@ 1.20 * setting up the maping of IRQs [0, 15] to interrupts [32, 47] 1.21 */ 1.22 init_pic(IRQ_OFFSET); 1.23 + eoi_pending = 0; 1.24 } 1.25 1.26 /* retrieve the current interrupt frame. 1.27 @@ -98,6 +101,10 @@ 1.28 { 1.29 cur_intr_frame = &frm; 1.30 1.31 + if(IS_IRQ(frm.inum)) { 1.32 + eoi_pending = frm.inum; 1.33 + } 1.34 + 1.35 if(intr_func[frm.inum]) { 1.36 intr_func[frm.inum](frm.inum); 1.37 } else { 1.38 @@ -107,8 +114,9 @@ 1.39 printf("unhandled interrupt %d\n", frm.inum); 1.40 } 1.41 1.42 - if(IS_IRQ(frm.inum)) { 1.43 - end_of_irq(INTR_TO_IRQ(frm.inum)); 1.44 + disable_intr(); 1.45 + if(eoi_pending) { 1.46 + end_of_irq(INTR_TO_IRQ(eoi_pending)); 1.47 } 1.48 } 1.49 1.50 @@ -149,13 +157,31 @@ 1.51 static void set_intr_entry(int num, void (*handler)(void)) 1.52 { 1.53 int type = IS_TRAP(num) ? GATE_TRAP : GATE_INTR; 1.54 - gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type); 1.55 + 1.56 + /* the syscall interrupt has to have a dpl of 3 otherwise calling it from 1.57 + * user space will raise a general protection exception. All the rest should 1.58 + * have a dpl of 0 to disallow user programs to execute critical interrupt 1.59 + * handlers and possibly crashing the system. 1.60 + */ 1.61 + int dpl = (num == SYSCALL_INT) ? 3 : 0; 1.62 + 1.63 + gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, dpl, type); 1.64 } 1.65 1.66 void end_of_irq(int irq) 1.67 { 1.68 + int intr_state = get_intr_state(); 1.69 + disable_intr(); 1.70 + 1.71 + if(!eoi_pending) { 1.72 + return; 1.73 + } 1.74 + eoi_pending = 0; 1.75 + 1.76 if(irq > 7) { 1.77 outb(OCW2_EOI, PIC2_CMD); 1.78 } 1.79 outb(OCW2_EOI, PIC1_CMD); 1.80 + 1.81 + set_intr_state(intr_state); 1.82 }