Removed KSTACKTOP
[akaros.git] / kern / arch / i686 / trap.c
index 35438c9..0413dd5 100644 (file)
@@ -19,6 +19,8 @@
 #include <stdio.h>
 #include <slab.h>
 #include <syscall.h>
+#include <kdebug.h>
+#include <kmalloc.h>
 
 taskstate_t RO ts;
 
@@ -90,7 +92,12 @@ void set_stack_top(uintptr_t stacktop)
 /* Note the check implies we only are on a one page stack (or the first page) */
 uintptr_t get_stack_top(void)
 {
-       uintptr_t stacktop = per_cpu_info[core_id()].tss->ts_esp0;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       uintptr_t stacktop;
+       /* so we can check this in interrupt handlers (before smp_boot()) */
+       if (!pcpui->tss)
+               return ROUNDUP(read_esp(), PGSIZE);
+       stacktop = pcpui->tss->ts_esp0;
        if (stacktop != ROUNDUP(read_esp(), PGSIZE))
                panic("Bad stacktop: %08p esp one is %08p\n", stacktop,
                      ROUNDUP(read_esp(), PGSIZE));
@@ -115,6 +122,14 @@ void pop_kernel_tf(struct trapframe *tf)
        panic("ret failed");                            /* mostly to placate your mom */
 }
 
+/* Sends a non-maskable interrupt; the handler will print a trapframe. */
+void send_nmi(uint32_t os_coreid)
+{
+       /* NMI / IPI for x86 are limited to 8 bits */
+       uint8_t hw_core = (uint8_t)get_hw_coreid(os_coreid);
+       __send_nmi(hw_core);
+}
+
 void idt_init(void)
 {
        extern segdesc_t (RO gdt)[];
@@ -148,13 +163,14 @@ void idt_init(void)
        idt[T_SYSCALL].gd_type = SINIT(STS_TG32);
        idt[T_BRKPT].gd_dpl = SINIT(3);
 
-       /* Setup a TSS so that we get the right stack when we trap to the kernel.
-        * We need to use the KVA for stacktop, and not the memlayout virtual
-        * address, so we can free it later (and check for other bugs). */
-       pte_t *pte = pgdir_walk(boot_pgdir, (void*)KSTACKTOP - PGSIZE, 0);
-       uintptr_t stacktop_kva = (uintptr_t)ppn2kva(PTE2PPN(*pte)) + PGSIZE;
-       ts.ts_esp0 = stacktop_kva;
+       /* Setup a TSS so that we get the right stack when we trap to the kernel. */
+       ts.ts_esp0 = (uintptr_t)bootstacktop;
        ts.ts_ss0 = SINIT(GD_KD);
+#ifdef __CONFIG_KTHREAD_POISON__
+       /* TODO: KTHR-STACK */
+       uintptr_t *poison = (uintptr_t*)ROUNDDOWN(bootstacktop - 1, PGSIZE);
+       *poison = 0xdeadbeef;
+#endif /* __CONFIG_KTHREAD_POISON__ */
 
        // Initialize the TSS field of the gdt.
        SEG16ROINIT(gdt[GD_TSS >> 3],STS_T32A, (uint32_t)(&ts),sizeof(taskstate_t),0);
@@ -219,11 +235,16 @@ print_trapframe(trapframe_t *tf)
        spin_unlock_irqsave(&ptf_lock);
 }
 
-static void
-trap_dispatch(trapframe_t *tf)
+static void trap_dispatch(struct trapframe *tf)
 {
        // Handle processor exceptions.
        switch(tf->tf_trapno) {
+               case T_NMI:
+                       print_trapframe(tf);
+                       char *fn_name = get_fn_name(tf->tf_eip);
+                       printk("Core %d is at %08p (%s)\n", core_id(), tf->tf_eip, fn_name);
+                       kfree(fn_name);
+                       break;
                case T_BRKPT:
                        monitor(tf);
                        break;
@@ -233,16 +254,9 @@ trap_dispatch(trapframe_t *tf)
                case T_SYSCALL:
                        // check for userspace, for now
                        assert(tf->tf_cs != GD_KT);
-                       struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
-                       coreinfo->cur_ret.returnloc = &(tf->tf_regs.reg_eax);
-                       coreinfo->cur_ret.errno_loc = &(tf->tf_regs.reg_esi);
-                       // syscall code wants an edible reference for current
-                       kref_get(&coreinfo->cur_proc->kref, 1);
-                       tf->tf_regs.reg_eax =
-                               syscall(coreinfo->cur_proc, tf->tf_regs.reg_eax, tf->tf_regs.reg_edx,
-                                       tf->tf_regs.reg_ecx, tf->tf_regs.reg_ebx,
-                                       tf->tf_regs.reg_edi, tf->tf_regs.reg_esi);
-                       kref_put(&coreinfo->cur_proc->kref);
+                       /* Set up and run the async calls */
+                       prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
+                                     tf->tf_regs.reg_edx);
                        break;
                default:
                        // Unexpected trap: The user process or the kernel has a bug.
@@ -251,8 +265,9 @@ trap_dispatch(trapframe_t *tf)
                                panic("Damn Damn!  Unhandled trap in the kernel!");
                        else {
                                warn("Unexpected trap from userspace");
-                               kref_get(&current->kref, 1);
+                               proc_incref(current, 1);
                                proc_destroy(current);
+                               assert(0);
                                return;
                        }
        }
@@ -272,17 +287,24 @@ env_pop_ancillary_state(env_t* e)
        // Here's where you'll restore FP/MMX/XMM regs
 }
 
+/* Helper.  For now, this copies out the TF to pcpui, and sets the tf to use it.
+ * Eventually, we ought to do this in trapentry.S */
+static void set_current_tf(struct per_cpu_info *pcpui, struct trapframe **tf)
+{
+       pcpui->actual_tf = **tf;
+       pcpui->cur_tf = &pcpui->actual_tf;
+       *tf = &pcpui->actual_tf;
+}
+
 void trap(struct trapframe *tf)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* Copy out the TF for now, set tf to point to it.  */
+       if (!in_kernel(tf))
+               set_current_tf(pcpui, &tf);
+
        printd("Incoming TRAP %d on core %d, TF at %p\n", tf->tf_trapno, core_id(),
               tf);
-       /* Note we are not preemptively saving the TF in the env_tf.  We do maintain
-        * a reference to it in current_tf (a per-cpu pointer).
-        * In general, only save the tf and any silly state once you know it
-        * is necessary (blocking).  And only save it in env_tf when you know you
-        * are single core (PROC_RUNNING_S) */
-       if (!in_kernel(tf))
-               set_current_tf(tf);
        if ((tf->tf_cs & ~3) != GD_UT && (tf->tf_cs & ~3) != GD_KT) {
                print_trapframe(tf);
                panic("Trapframe with invalid CS!");
@@ -292,15 +314,18 @@ void trap(struct trapframe *tf)
         * kernel, we should just return naturally.  Note that current and tf need
         * to still be okay (might not be after blocking) */
        if (in_kernel(tf))
-               return;
-       proc_restartcore(current, tf);
+               return; /* TODO: think about this, might want a helper instead. */
+       proc_restartcore();
        assert(0);
 }
 
 void irq_handler(struct trapframe *tf)
 {
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* Copy out the TF for now, set tf to point to it. */
        if (!in_kernel(tf))
-               set_current_tf(tf);
+               set_current_tf(pcpui, &tf);
+
        //if (core_id())
                printd("Incoming IRQ, ISR: %d on core %d\n", tf->tf_trapno, core_id());
 
@@ -322,7 +347,8 @@ void irq_handler(struct trapframe *tf)
        // For now, only 235-255 are available
        assert(tf->tf_trapno >= 32); // slows us down, but we should never have this
 
-#ifndef __CONFIG_DISABLE_MPTABLES__
+#ifdef __CONFIG_ENABLE_MPTABLES__
+       /* TODO: this should be for any IOAPIC EOI, not just MPTABLES */
        lapic_send_eoi();
 #else
        //Old PIC relatd code. Should be gone for good, but leaving it just incase.
@@ -331,7 +357,13 @@ void irq_handler(struct trapframe *tf)
        else
                lapic_send_eoi();
 #endif
-
+       /* Return to the current process, which should be runnable.  If we're the
+        * kernel, we should just return naturally.  Note that current and tf need
+        * to still be okay (might not be after blocking) */
+       if (in_kernel(tf))
+               return; /* TODO: think about this, might want a helper instead. */
+       proc_restartcore();
+       assert(0);
 }
 
 void
@@ -359,8 +391,9 @@ void page_fault_handler(struct trapframe *tf)
                       current->pid, prot & PROT_READ ? "READ" : "WRITE", fault_va,
                       tf->tf_eip, core_id(), err);
                print_trapframe(tf);
-               kref_get(&current->kref, 1);
+               proc_incref(current, 1);
                proc_destroy(current);
+               assert(0);
        }
 }
 
@@ -374,29 +407,18 @@ void sysenter_init(void)
 /* This is called from sysenter's asm, with the tf on the kernel stack. */
 void sysenter_callwrapper(struct trapframe *tf)
 {
-       struct per_cpu_info* coreinfo = &per_cpu_info[core_id()];
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* Copy out the TF for now, set tf to point to it. */
        if (!in_kernel(tf))
-               coreinfo->cur_tf = tf;
-       coreinfo->cur_ret.returnloc = &(tf->tf_regs.reg_eax);
-       coreinfo->cur_ret.errno_loc = &(tf->tf_regs.reg_esi);
-
-       // syscall code wants an edible reference for current
-       kref_get(&current->kref, 1);
-       tf->tf_regs.reg_eax = (intreg_t) syscall(current,
-                                                tf->tf_regs.reg_eax,
-                                                tf->tf_regs.reg_esi,
-                                                tf->tf_regs.reg_ecx,
-                                                tf->tf_regs.reg_ebx,
-                                                tf->tf_regs.reg_edi,
-                                                0);
-       kref_put(&current->kref);
-       /*
-        * careful here - we need to make sure that this current is the right
-        * process, which could be weird if the syscall blocked.  it would need to
-        * restore the proper value in current before returning to here.
-        * likewise, tf could be pointing to random gibberish.
-        */
-       proc_restartcore(current, tf);
+               set_current_tf(pcpui, &tf);
+
+       if (in_kernel(tf))
+               panic("sysenter from a kernel TF!!");
+       /* Set up and run the async calls */
+       prep_syscalls(current, (struct syscall*)tf->tf_regs.reg_eax,
+                     tf->tf_regs.reg_esi);
+       /* If you use pcpui again, reread it, since you might have migrated */
+       proc_restartcore();
 }
 
 struct kmem_cache *kernel_msg_cache;
@@ -414,6 +436,7 @@ uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
        // note this will be freed on the destination core
        k_msg = (kernel_message_t *CT(1))TC(kmem_cache_alloc(kernel_msg_cache, 0));
        k_msg->srcid = core_id();
+       k_msg->dstid = dst;
        k_msg->pc = pc;
        k_msg->arg0 = arg0;
        k_msg->arg1 = arg1;
@@ -432,9 +455,11 @@ uint32_t send_kernel_message(uint32_t dst, amr_t pc, TV(a0t) arg0, TV(a1t) arg1,
                default:
                        panic("Unknown type of kernel message!");
        }
-       // since we touched memory the other core will touch (the lock), we don't
-       // need an wmb_f()
-       send_ipi(get_hw_coreid(dst), I_KERNEL_MSG);
+       /* since we touched memory the other core will touch (the lock), we don't
+        * need an wmb_f() */
+       /* if we're sending a routine message locally, we don't want/need an IPI */
+       if ((dst != k_msg->srcid) || (type == KMSG_IMMEDIATE))
+               send_ipi(get_hw_coreid(dst), I_KERNEL_MSG);
        return 0;
 }
 
@@ -466,6 +491,10 @@ void __kernel_message(struct trapframe *tf)
        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. */
@@ -491,9 +520,14 @@ void __kernel_message(struct trapframe *tf)
                                send_self_ipi(I_KERNEL_MSG);
                        /* Execute the kernel message */
                        assert(msg_cp.pc);
+                       assert(msg_cp.dstid == core_id());
+                       /* TODO: when batching syscalls, this should be reread from cur_tf*/
                        msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
                }
        }
+       /* TODO: should this proc_restartcore, like the irq/trap paths?  Or at least
+        * take some things from __proc_startcore() (since we don't want to re-run
+        * kmsgs). */
 }
 
 /* Runs any outstanding routine kernel messages from within the kernel.  Will
@@ -537,6 +571,7 @@ void process_routine_kmsg(struct trapframe *tf)
                        send_self_ipi(I_KERNEL_MSG);
                /* Execute the kernel message */
                assert(msg_cp.pc);
+               assert(msg_cp.dstid == core_id());
                msg_cp.pc(tf, msg_cp.srcid, msg_cp.arg0, msg_cp.arg1, msg_cp.arg2);
        }
 }