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  }