Skip the shitty e1000s on c89
[akaros.git] / kern / arch / x86 / smp_boot.c
index 9b5a34f..f08b997 100644 (file)
@@ -31,6 +31,7 @@
 extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
 volatile uint32_t num_cpus = 0xee;
 uintptr_t RO smp_stack_top;
+barrier_t generic_barrier;
 
 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
        INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CPUS);
@@ -59,11 +60,36 @@ static void init_smp_call_function(void)
 
 /******************************************************************************/
 
-static void smp_final_core_init(struct hw_trapframe *hw_tf, void *data)
+void smp_final_core_init(void)
 {
-       setup_default_mtrrs(data);
+       /* It is possible that the non-0 cores will wake up before the broadcast
+        * ipi.  this can be due to spurious IRQs or some such.  anyone other than
+        * core 0 that comes in here will wait til core 0 has set everything up */
+       static bool wait = TRUE;
+       if (get_os_coreid(hw_core_id()) == 0)
+               wait = FALSE;
+       while (wait)
+               cpu_relax();
+#ifdef CONFIG_FAST_COREID
+       /* Need to bootstrap the rdtscp MSR with our OS coreid */
+       int coreid = get_os_coreid(hw_core_id());
+       write_msr(MSR_TSC_AUX, coreid);
+
+       /* Busted versions of qemu bug out here (32 bit) */
+       int rdtscp_ecx;
+       asm volatile ("rdtscp" : "=c"(rdtscp_ecx) : : "eax", "edx");
+       if (read_msr(MSR_TSC_AUX) != rdtscp_ecx) {
+               printk("Broken rdtscp detected!  Rebuild without CONFIG_FAST_COREID\n");
+               if (coreid)
+                       while(1);
+               /* note this panic may think it is not core 0, and core 0 might not have
+                * an issue (seems random) */
+               panic("");
+       }
+#endif
+       setup_default_mtrrs(&generic_barrier);
        smp_percpu_init();
-       waiton_barrier(data);
+       waiton_barrier(&generic_barrier);
 }
 
 // this needs to be set in smp_entry too...
@@ -186,10 +212,10 @@ void smp_boot(void)
        init_smp_call_function();
 
        /* Final core initialization */
-       barrier_t generic_barrier;
        init_barrier(&generic_barrier, num_cpus);
        /* This will break the cores out of their hlt in smp_entry.S */
-       smp_call_function_all(smp_final_core_init, &generic_barrier, 0);
+       send_broadcast_ipi(254);
+       smp_final_core_init();  /* need to init ourselves as well */
 }
 
 /* This is called from smp_entry by each core to finish the core bootstrapping.
@@ -218,11 +244,7 @@ uintptr_t smp_main(void)
        hw_coreid_lookup[my_hw_id] = my_hw_id;
 
        // Get a per-core kernel stack
-       page_t *my_stack;
-       if (kpage_alloc(&my_stack))
-               panic("Unable to alloc a per-core stack!");
-       memset(page2kva(my_stack), 0, PGSIZE);
-       uintptr_t my_stack_top = (uintptr_t)page2kva(my_stack) + PGSIZE;
+       uintptr_t my_stack_top = get_kstack();
 
        /* This blob is the GDT, the GDT PD, and the TSS. */
        unsigned int blob_size = sizeof(segdesc_t) * SEG_COUNT +
@@ -236,7 +258,7 @@ uintptr_t smp_main(void)
         * to smp_percpu_init(), but we can't trust our coreid (since they haven't
         * been remapped yet (so we can't write it directly to per_cpu_info)).  So
         * we use the bottom of the stack page... */
-       *(uintptr_t*)page2kva(my_stack) = (uintptr_t)gdt_etc;
+       *kstack_bottom_addr(my_stack_top) = (uintptr_t)gdt_etc;
 
        // Build and load the gdt / gdt_pd
        memcpy(my_gdt, gdt, sizeof(segdesc_t)*SEG_COUNT);
@@ -246,7 +268,6 @@ uintptr_t smp_main(void)
 
        /* Set up our kernel stack when changing rings */
        x86_set_stacktop_tss(my_ts, my_stack_top);
-       x86_sysenter_init(my_stack_top);
        // Initialize the TSS field of my_gdt.
        syssegdesc_t *ts_slot = (syssegdesc_t*)&my_gdt[GD_TSS >> 3];
        *ts_slot = (syssegdesc_t)SEG_SYS_SMALL(STS_T32A, (uintptr_t)my_ts,
@@ -257,6 +278,9 @@ uintptr_t smp_main(void)
        // Loads the same IDT used by the other cores
        asm volatile("lidt %0" : : "m"(idt_pd));
 
+#ifdef CONFIG_ENABLE_MPTABLES
+       apiconline();
+#else
        // APIC setup
        // set LINT0 to receive ExtINTs (KVM's default).  At reset they are 0x1000.
        write_mmreg32(LAPIC_LVT_LINT0, 0x700);
@@ -265,6 +289,7 @@ uintptr_t smp_main(void)
        mask_lapic_lvt(LAPIC_LVT_LINT0);
        // and then turn it on
        lapic_enable();
+#endif
 
        // set a default logical id for now
        lapic_set_logid(lapic_get_id());
@@ -279,7 +304,8 @@ uintptr_t smp_main(void)
  * to call it on too deep of a stack frame. */
 void __arch_pcpu_init(uint32_t coreid)
 {
-       uintptr_t my_stack_bot;
+       uintptr_t *my_stack_bot;
+       struct per_cpu_info *pcpui = &per_cpu_info[coreid];
 
        /* Flushes any potentially old mappings from smp_boot() (note the page table
         * removal) */
@@ -294,14 +320,26 @@ void __arch_pcpu_init(uint32_t coreid)
 
        /* core 0 sets up via the global gdt symbol */
        if (!coreid) {
-               per_cpu_info[0].tss = &ts;
-               per_cpu_info[0].gdt = gdt;
+               pcpui->tss = &ts;
+               pcpui->gdt = gdt;
        } else {
-               my_stack_bot = ROUNDDOWN(read_sp(), PGSIZE);
-               per_cpu_info[coreid].tss = (taskstate_t*)(*(uintptr_t*)my_stack_bot);
-               per_cpu_info[coreid].gdt = (segdesc_t*)(*(uintptr_t*)my_stack_bot +
-                                          sizeof(taskstate_t) + sizeof(pseudodesc_t));
+               my_stack_bot = kstack_bottom_addr(ROUNDUP(read_sp() - 1, PGSIZE));
+               pcpui->tss = (taskstate_t*)(*my_stack_bot);
+               pcpui->gdt = (segdesc_t*)(*my_stack_bot +
+                                         sizeof(taskstate_t) + sizeof(pseudodesc_t));
        }
+#ifdef CONFIG_X86_64
+       /* Core 0 set up the base MSRs in entry64 */
+       if (!coreid) {
+               assert(read_msr(MSR_GS_BASE) == (uint64_t)pcpui);
+               assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
+       } else {
+               write_msr(MSR_GS_BASE, (uint64_t)pcpui);
+               write_msr(MSR_KERN_GS_BASE, (uint64_t)pcpui);
+       }
+#endif
+       /* Don't try setting up til after setting GS */
+       x86_sysenter_init(x86_get_stacktop_tss(pcpui->tss));
        /* need to init perfctr before potentiall using it in timer handler */
        perfmon_init();
 }