Arch independent per-cpu initialization
[akaros.git] / kern / arch / i686 / smp_boot.c
index fae8bd2..d40f9d6 100644 (file)
 #include <smp.h>
 #include <arch/console.h>
 #include <arch/apic.h>
-#include <arch/bitmask.h>
+#include <arch/perfmon.h>
 #include <timing.h>
 
+#include <bitmask.h>
 #include <atomic.h>
-#include <ros/error.h>
+#include <error.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -26,6 +27,7 @@
 #include <env.h>
 #include <trap.h>
 #include <timing.h>
+#include <kmalloc.h>
 
 extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
 volatile uint32_t num_cpus = 0xee;
@@ -160,7 +162,11 @@ void smp_boot(void)
        // mapping pulled out from under them.  Now, if a core loses, it will spin
        // on the trampoline (which we must be careful to not deallocate)
        __spin_lock(get_smp_bootlock());
-       cprintf("Num_Cpus Detected: %d\n", num_cpus);
+       printk("Number of Cores Detected: %d\n", num_cpus);
+#ifdef __CONFIG_DISABLE_SMT__
+       assert(!(num_cpus % 2));
+       printk("Using only %d Idlecores (SMT Disabled)\n", num_cpus >> 1);
+#endif /* __CONFIG_DISABLE_SMT__ */
        smp_remap_coreids();
 
        // Remove the mapping of the page used by the trampoline
@@ -181,33 +187,8 @@ void smp_boot(void)
        /* 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);
-
-       // Should probably flush everyone's TLB at this point, to get rid of
-       // temp mappings that were removed.  TODO
-}
-
-/* zra: sometimes Deputy needs some hints */
-static inline void *COUNT(sizeof(pseudodesc_t))
-get_my_gdt_pd(page_t *my_stack)
-{
-       return page2kva(my_stack) + (PGSIZE - sizeof(pseudodesc_t) -
-                                     sizeof(segdesc_t)*SEG_COUNT);
-}
-
-//static inline void *COUNT(sizeof(segdesc_t)*SEG_COUNT)
-static inline segdesc_t *COUNT(SEG_COUNT)
-get_my_gdt(page_t *my_stack)
-{
-       return TC(page2kva(my_stack) + PGSIZE - sizeof(segdesc_t)*SEG_COUNT);
-}
-
-static inline void *COUNT(sizeof(taskstate_t))
-get_my_ts(page_t *my_stack)
-{
-       return page2kva(my_stack) + PGSIZE -
-               sizeof(pseudodesc_t) - sizeof(segdesc_t)*SEG_COUNT -
-               sizeof(taskstate_t);
 }
 
 /* This is called from smp_entry by each core to finish the core bootstrapping.
@@ -240,19 +221,21 @@ uint32_t smp_main(void)
        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;
+
+       /* This blob is the GDT, the GDT PD, and the TSS. */
+       unsigned int blob_size = sizeof(segdesc_t) * SEG_COUNT +
+                                sizeof(pseudodesc_t) + sizeof(taskstate_t);
+       void *gdt_etc = kmalloc(blob_size, 0);          /* we'll never free this btw */
+       taskstate_t *my_ts = gdt_etc;
+       pseudodesc_t *my_gdt_pd = (void*)my_ts + sizeof(taskstate_t);
+       segdesc_t *my_gdt = (void*)my_gdt_pd + sizeof(pseudodesc_t);
+       /* This is a bit ghetto: we need to communicate our GDT and TSS's location
+        * 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;
 
-       // Set up a gdt / gdt_pd for this core, stored at the top of the stack
-       // This is necessary, eagle-eyed readers know why
-       // GDT should be 4-byte aligned.  TS isn't aligned.  Not sure if it matters.
-       pseudodesc_t *my_gdt_pd = get_my_gdt_pd(my_stack);
-       segdesc_t *COUNT(SEG_COUNT) my_gdt = get_my_gdt(my_stack);
-       // TS also needs to be permanent
-       taskstate_t *my_ts = get_my_ts(my_stack);
-       // Usable portion of the KSTACK grows down from here
-       // Won't actually start using this stack til our first interrupt
-       // (issues with changing the stack pointer and then trying to "return")
-       uintptr_t my_stack_top = (uintptr_t)my_ts;
-       
        // Set up MSR for SYSENTER 
        write_msr(MSR_IA32_SYSENTER_CS, GD_KT);
        write_msr(MSR_IA32_SYSENTER_ESP, my_stack_top);
@@ -297,15 +280,31 @@ uint32_t smp_main(void)
  * must still call this for core 0.  This must NOT be called from smp_main,
  * since it relies on the kernel stack pointer to find the gdt.  Be careful not
  * to call it on too deep of a stack frame. */
-void smp_percpu_init(void)
+void __arch_pcpu_init(uint32_t coreid)
 {
-       uint32_t coreid = core_id();
+       uintptr_t my_stack_bot;
+
+       /* Flushes any potentially old mappings from smp_boot() (note the page table
+        * removal) */
+       tlbflush();
+       /* Ensure the FPU units are initialized */
+       asm volatile ("fninit");
+
+       /* Enable SSE instructions.  We might have to do more, like masking certain
+        * flags or exceptions in the MXCSR, or at least handle the SIMD exceptions.
+        * We don't do it for FP yet either, so YMMV. */
+       lcr4(rcr4() | CR4_OSFXSR | CR4_OSXMME);
 
        /* core 0 sets up via the global gdt symbol */
-       if (!coreid)
+       if (!coreid) {
+               per_cpu_info[0].tss = &ts;
                per_cpu_info[0].gdt = gdt;
-       else
-               per_cpu_info[coreid].gdt = (segdesc_t*)(ROUNDUP(read_esp(), PGSIZE)
-                                          - sizeof(segdesc_t)*SEG_COUNT);
-       STAILQ_INIT(&per_cpu_info[coreid].active_msgs);
+       } else {
+               my_stack_bot = ROUNDDOWN(read_esp(), 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));
+       }
+       /* need to init perfctr before potentiall using it in timer handler */
+       perfmon_init();
 }