x86 interrupts are disabled til cur_tf is set
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 27 Sep 2011 21:27:36 +0000 (14:27 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:07 +0000 (17:36 -0700)
Whenever we're in the kernel with interrupts enabled, if there is a
process that is running (or should be running) on the core, current and
cur_tf should both be set.  On the first time into the kernel (syscall,
trap, etc) from userspace, cur_tf needs to get set.

Also remember that a 0'd cur_tf means that we should no longer run a
context (which happens after a kthread returns from blocking if the
process is no longer present).  In those situations, it is still okay to
have current set.  That is just which process's context we have loaded.

kern/arch/i686/trap.c
kern/arch/i686/trapentry.S

index 6b38037..810ab8c 100644 (file)
@@ -161,9 +161,9 @@ void idt_init(void)
 
        // turn on syscall handling and other user-accessible ints
        // DPL 3 means this can be triggered by the int instruction
-       // STS_TG32 sets the IDT type to a Trap Gate (interrupts enabled)
+       // STS_TG32 sets the IDT type to a Interrupt Gate (interrupts disabled)
        idt[T_SYSCALL].gd_dpl = SINIT(3);
-       idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
+       idt[T_SYSCALL].gd_type = SINIT(STS_IG32);
        idt[T_BRKPT].gd_dpl = SINIT(3);
 
        /* Setup a TSS so that we get the right stack when we trap to the kernel. */
@@ -241,6 +241,8 @@ print_trapframe(trapframe_t *tf)
        spin_unlock_irqsave(&ptf_lock);
 }
 
+/* Certain traps want IRQs enabled, such as the syscall.  Others can't handle
+ * it, like the page fault handler.  Turn them on on a case-by-case basis. */
 static void trap_dispatch(struct trapframe *tf)
 {
        // Handle processor exceptions.
@@ -252,12 +254,14 @@ static void trap_dispatch(struct trapframe *tf)
                        kfree(fn_name);
                        break;
                case T_BRKPT:
+                       enable_irq();
                        monitor(tf);
                        break;
                case T_PGFLT:
                        page_fault_handler(tf);
                        break;
                case T_SYSCALL:
+                       enable_irq();
                        // check for userspace, for now
                        assert(tf->tf_cs != GD_KT);
                        /* Set up and run the async calls */
@@ -297,6 +301,7 @@ env_pop_ancillary_state(env_t* e)
  * Eventually, we ought to do this in trapentry.S */
 static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe **tf)
 {
+       assert(!irq_is_enabled());
        pcpui->actual_tf = **tf;
        pcpui->cur_tf = &pcpui->actual_tf;
        *tf = &pcpui->actual_tf;
@@ -338,6 +343,7 @@ void trap(struct trapframe *tf)
        assert(0);
 }
 
+/* Note IRQs are disabled unless explicitly turned on. */
 void irq_handler(struct trapframe *tf)
 {
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
@@ -431,6 +437,8 @@ void sysenter_callwrapper(struct trapframe *tf)
        /* Copy out the TF for now, set tf to point to it. */
        if (!in_kernel(tf))
                set_current_tf(pcpui, &tf);
+       /* Once we've set_current_tf, we can enable interrupts */
+       enable_irq();
 
        if (in_kernel(tf))
                panic("sysenter from a kernel TF!!");
@@ -547,10 +555,6 @@ void __kernel_message(struct trapframe *tf, void *data)
        per_cpu_info_t *myinfo = &per_cpu_info[core_id()];
        kernel_message_t msg_cp, *k_msg;
 
-       /* Copy out the TF for now, set tf to point to it. */
-       if (!in_kernel(tf))
-               set_current_tf(myinfo, &tf);
-
        lapic_send_eoi();
        while (1) { // will break out when there are no more messages
                /* Try to get an immediate message.  Exec and free it. */
index 8b22fcd..15e992a 100644 (file)
@@ -247,7 +247,6 @@ _allirqs:
 # All of the pushl zeros are to keep the trap frame looking the same as when we
 # receive a trap or an interrupt
 sysenter_handler:
-       sti                                             # enable interrupts (things are sane here)
        cld
        pushl $0                                # ss
        pushl $0                                # esp