Clear x86_default_fpu STX/MMX register state at boot
[akaros.git] / kern / arch / x86 / smp_boot.c
index 9886fd2..efb11e2 100644 (file)
@@ -4,11 +4,6 @@
  * See LICENSE for details.
  */
 
  * See LICENSE for details.
  */
 
-#ifdef __SHARC__
-#pragma nosharc
-#define SINIT(x) x
-#endif
-
 #include <arch/x86.h>
 #include <arch/arch.h>
 #include <smp.h>
 #include <arch/x86.h>
 #include <arch/arch.h>
 #include <smp.h>
 #include <env.h>
 #include <trap.h>
 #include <kmalloc.h>
 #include <env.h>
 #include <trap.h>
 #include <kmalloc.h>
+#include <cpu_feat.h>
+#include <arch/fsgsbase.h>
+#include <ros/procinfo.h>
+
+#include "vmm/vmm.h"
 
 
-extern handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
-volatile uint32_t num_cpus = 0xee;
-uintptr_t RO smp_stack_top;
+extern handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
+int x86_num_cores_booted = 1;
+uintptr_t smp_stack_top;
 barrier_t generic_barrier;
 
 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
 barrier_t generic_barrier;
 
 #define DECLARE_HANDLER_CHECKLISTS(vector)                          \
-       INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CPUS);
+       INIT_CHECKLIST(f##vector##_cpu_list, MAX_NUM_CORES);
 
 #define INIT_HANDLER_WRAPPER(v)                                     \
 {                                                                   \
        handler_wrappers[(v)].vector = 0xe##v;                          \
        handler_wrappers[(v)].cpu_list = &f##v##_cpu_list;              \
 
 #define INIT_HANDLER_WRAPPER(v)                                     \
 {                                                                   \
        handler_wrappers[(v)].vector = 0xe##v;                          \
        handler_wrappers[(v)].cpu_list = &f##v##_cpu_list;              \
-       handler_wrappers[(v)].cpu_list->mask.size = num_cpus;           \
+       handler_wrappers[(v)].cpu_list->mask.size = num_cores;          \
 }
 
 DECLARE_HANDLER_CHECKLISTS(0);
 }
 
 DECLARE_HANDLER_CHECKLISTS(0);
@@ -80,32 +80,19 @@ static void setup_rdtscp(int coreid)
 /* TODO: consider merging __arch_pcpu with parts of this (sync with RISCV) */
 void smp_final_core_init(void)
 {
 /* TODO: consider merging __arch_pcpu with parts of this (sync with RISCV) */
 void smp_final_core_init(void)
 {
-       /* 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.
-        * those other cores might have come up before core 0 remapped the coreids,
-        * so we can only look at the HW coreid, which is only 0 for core 0. */
-       static bool wait = TRUE;
-       if (hw_core_id() == 0)
-               wait = FALSE;
-       while (wait)
-               cpu_relax();
-       /* at this point, it is safe to get the OS coreid */
+       /* Set the coreid in pcpui for fast access to it through TLS. */
        int coreid = get_os_coreid(hw_core_id());
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
        pcpui->coreid = coreid;
        int coreid = get_os_coreid(hw_core_id());
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
        pcpui->coreid = coreid;
-       write_msr(MSR_GS_BASE, (uint64_t)pcpui);
+       write_msr(MSR_GS_BASE, (uintptr_t)pcpui);       /* our cr4 isn't set yet */
        write_msr(MSR_KERN_GS_BASE, (uint64_t)pcpui);
        /* don't need this for the kernel anymore, but userspace can still use it */
        setup_rdtscp(coreid);
        /* After this point, all cores have set up their segmentation and whatnot to
        write_msr(MSR_KERN_GS_BASE, (uint64_t)pcpui);
        /* don't need this for the kernel anymore, but userspace can still use it */
        setup_rdtscp(coreid);
        /* After this point, all cores have set up their segmentation and whatnot to
-        * be able to do a proper core_id().  As a note to posterity, using the
-        * LAPIC coreid (like get_hw_coreid()) needs the LAPIC set up, which happens
-        * by the end of vm_init() */
+        * be able to do a proper core_id(). */
        waiton_barrier(&generic_barrier);
        waiton_barrier(&generic_barrier);
-       if (hw_core_id() == 0) {
+       if (coreid == 0)
                core_id_ready = TRUE;
                core_id_ready = TRUE;
-       }
        /* being paranoid with this, it's all a bit ugly */
        waiton_barrier(&generic_barrier);
        setup_default_mtrrs(&generic_barrier);
        /* being paranoid with this, it's all a bit ugly */
        waiton_barrier(&generic_barrier);
        setup_default_mtrrs(&generic_barrier);
@@ -115,10 +102,10 @@ void smp_final_core_init(void)
 
 // this needs to be set in smp_entry too...
 #define trampoline_pg 0x00001000UL
 
 // this needs to be set in smp_entry too...
 #define trampoline_pg 0x00001000UL
-extern char (SNT SREADONLY smp_entry)[];
-extern char (SNT SREADONLY smp_entry_end)[];
-extern char (SNT SREADONLY smp_boot_lock)[];
-extern char (SNT SREADONLY smp_semaphore)[];
+extern char smp_entry[];
+extern char smp_entry_end[];
+extern char smp_boot_lock[];
+extern char smp_semaphore[];
 
 static inline uint16_t *get_smp_semaphore()
 {
 
 static inline uint16_t *get_smp_semaphore()
 {
@@ -136,39 +123,15 @@ static void __spin_bootlock_raw(void)
                      "jne 1b;" : : "m"(*bootlock) : "eax", "cc", "memory");
 }
 
                      "jne 1b;" : : "m"(*bootlock) : "eax", "cc", "memory");
 }
 
-/* hw_coreid_lookup will get packed, but keep it's hw values.  
- * os_coreid_lookup will remain sparse, but it's values will be consecutive.
- * for both arrays, -1 means an empty slot.  hw_step tracks the next valid entry
- * in hw_coreid_lookup, jumping over gaps of -1's. */
-static void smp_remap_coreids(void)
-{
-       for (int i = 0, hw_step = 0; i < num_cpus; i++, hw_step++) {
-               if (hw_coreid_lookup[i] == -1) {
-                       while (hw_coreid_lookup[hw_step] == -1) {
-                               hw_step++;
-                               if (hw_step == MAX_NUM_CPUS)
-                                       panic("Mismatch in num_cpus and hw_step");
-                       }
-                       hw_coreid_lookup[i] = hw_coreid_lookup[hw_step];
-                       hw_coreid_lookup[hw_step] = -1;
-                       os_coreid_lookup[hw_step] = i;
-               }
-       }
-}
-
 void smp_boot(void)
 {
        struct per_cpu_info *pcpui0 = &per_cpu_info[0];
 void smp_boot(void)
 {
        struct per_cpu_info *pcpui0 = &per_cpu_info[0];
-       /* set core0's mappings */
-       assert(lapic_get_id() == 0);
-       os_coreid_lookup[0] = 0;
-       hw_coreid_lookup[0] = 0;
-
        page_t *smp_stack;
        page_t *smp_stack;
+
        // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
        // page1 (2nd page) is reserved, hardcoded in pmap.c
        memset(KADDR(trampoline_pg), 0, PGSIZE);
        // NEED TO GRAB A LOWMEM FREE PAGE FOR AP BOOTUP CODE
        // page1 (2nd page) is reserved, hardcoded in pmap.c
        memset(KADDR(trampoline_pg), 0, PGSIZE);
-       memcpy(KADDR(trampoline_pg), (void *COUNT(PGSIZE))TC(smp_entry),
+       memcpy(KADDR(trampoline_pg), (void *)smp_entry,
            smp_entry_end - smp_entry);
 
        /* Make sure the trampoline page is mapped.  64 bit already has the tramp pg
            smp_entry_end - smp_entry);
 
        /* Make sure the trampoline page is mapped.  64 bit already has the tramp pg
@@ -177,7 +140,7 @@ void smp_boot(void)
        // Allocate a stack for the cores starting up.  One for all, must share
        if (kpage_alloc(&smp_stack))
                panic("No memory for SMP boot stack!");
        // Allocate a stack for the cores starting up.  One for all, must share
        if (kpage_alloc(&smp_stack))
                panic("No memory for SMP boot stack!");
-       smp_stack_top = SINIT((uintptr_t)(page2kva(smp_stack) + PGSIZE));
+       smp_stack_top = (uintptr_t)(page2kva(smp_stack) + PGSIZE);
 
        /* During SMP boot, core_id_early() returns 0, so all of the cores, which
         * grab locks concurrently, share the same pcpui and thus the same
 
        /* During SMP boot, core_id_early() returns 0, so all of the cores, which
         * grab locks concurrently, share the same pcpui and thus the same
@@ -213,20 +176,23 @@ 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_bootlock_raw();
        // 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_bootlock_raw();
-       printk("Number of Cores Detected: %d\n", num_cpus);
+       printk("Number of Cores Detected: %d\n", x86_num_cores_booted);
 #ifdef CONFIG_DISABLE_SMT
 #ifdef CONFIG_DISABLE_SMT
-       assert(!(num_cpus % 2));
-       printk("Using only %d Idlecores (SMT Disabled)\n", num_cpus >> 1);
+       assert(!(num_cores % 2));
+       printk("Using only %d Idlecores (SMT Disabled)\n", num_cores >> 1);
 #endif /* CONFIG_DISABLE_SMT */
 #endif /* CONFIG_DISABLE_SMT */
-       smp_remap_coreids();
 
        /* cleans up the trampoline page, and any other low boot mem mappings */
        x86_cleanup_bootmem();
 
        /* cleans up the trampoline page, and any other low boot mem mappings */
        x86_cleanup_bootmem();
-       // It had a refcount of 2 earlier, so we need to dec once more to free it
-       // but only if all cores are in (or we reset / reinit those that failed)
-       // TODO after we parse ACPI tables
-       if (num_cpus == 8) // TODO - ghetto coded for our 8 way SMPs
+       /* trampoline_pg had a refcount of 2 earlier, so we need to dec once more to free it
+        * but only if all cores are in (or we reset / reinit those that failed) */
+       if (x86_num_cores_booted == num_cores) {
                page_decref(pa2page(trampoline_pg));
                page_decref(pa2page(trampoline_pg));
+       } else {
+               warn("ACPI/MP found %d cores, smp_boot initialized %d, using %d\n",
+                    num_cores, x86_num_cores_booted, x86_num_cores_booted);
+               num_cores = x86_num_cores_booted;
+       }
        // Dealloc the temp shared stack
        page_decref(smp_stack);
 
        // Dealloc the temp shared stack
        page_decref(smp_stack);
 
@@ -234,7 +200,7 @@ void smp_boot(void)
        init_smp_call_function();
 
        /* Final core initialization */
        init_smp_call_function();
 
        /* Final core initialization */
-       init_barrier(&generic_barrier, num_cpus);
+       init_barrier(&generic_barrier, num_cores);
        /* This will break the cores out of their hlt in smp_entry.S */
        send_broadcast_ipi(I_POKE_CORE);
        smp_final_core_init();  /* need to init ourselves as well */
        /* This will break the cores out of their hlt in smp_entry.S */
        send_broadcast_ipi(I_POKE_CORE);
        smp_final_core_init();  /* need to init ourselves as well */
@@ -258,12 +224,8 @@ uintptr_t smp_main(void)
                cprintf("I am the Boot Strap Processor\n");
        else
                cprintf("I am an Application Processor\n");
                cprintf("I am the Boot Strap Processor\n");
        else
                cprintf("I am an Application Processor\n");
-       cprintf("Num_Cpus: %d\n\n", num_cpus);
+       cprintf("Num_Cores: %d\n\n", num_cores);
        */
        */
-       /* set up initial mappings.  core0 will adjust it later */
-       unsigned long my_hw_id = lapic_get_id();
-       os_coreid_lookup[my_hw_id] = my_hw_id;
-       hw_coreid_lookup[my_hw_id] = my_hw_id;
 
        // Get a per-core kernel stack
        uintptr_t my_stack_top = get_kstack();
 
        // Get a per-core kernel stack
        uintptr_t my_stack_top = get_kstack();
@@ -302,8 +264,6 @@ uintptr_t smp_main(void)
 
        apiconline();
 
 
        apiconline();
 
-       // set a default logical id for now
-       lapic_set_logid(lapic_get_id());
 
        return my_stack_top; // will be loaded in smp_entry.S
 }
 
        return my_stack_top; // will be loaded in smp_entry.S
 }
@@ -317,18 +277,35 @@ void __arch_pcpu_init(uint32_t coreid)
 {
        uintptr_t *my_stack_bot;
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
 {
        uintptr_t *my_stack_bot;
        struct per_cpu_info *pcpui = &per_cpu_info[coreid];
+       uint32_t eax, edx;
 
        /* Flushes any potentially old mappings from smp_boot() (note the page table
         * removal) */
        tlbflush();
 
        /* 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. */
+       if (cpu_has_feat(CPU_FEAT_X86_FSGSBASE))
+               lcr4(rcr4() | CR4_FSGSBASE);
+
+       /*
+        * Enable SSE instructions.
+        * CR4.OSFXSR enables SSE and ensures that MXCSR/XMM gets saved with FXSAVE
+        * CR4.OSXSAVE enables XSAVE instructions. Only set if XSAVE supported.
+        * CR4.OSXMME indicates OS support for software exception handlers for
+        * SIMD floating-point exceptions (turn it on to get #XM exceptions
+        * in the event of a SIMD error instead of #UD exceptions).
+        */
        lcr4(rcr4() | CR4_OSFXSR | CR4_OSXMME);
 
        lcr4(rcr4() | CR4_OSFXSR | CR4_OSXMME);
 
+       if (cpu_has_feat(CPU_FEAT_X86_XSAVE)) {
+               // You MUST set CR4.OSXSAVE before loading xcr0
+               lcr4(rcr4() | CR4_OSXSAVE);
+               // Set xcr0 to the Akaros-wide default
+               lxcr0(__proc_global_info.x86_default_xcr0);
+       }
+
+       // Initialize fpu and extended state by restoring our default XSAVE area.
+       init_fp_state();
+
        /* core 0 sets up via the global gdt symbol */
        if (!coreid) {
                pcpui->tss = &ts;
        /* core 0 sets up via the global gdt symbol */
        if (!coreid) {
                pcpui->tss = &ts;
@@ -339,10 +316,12 @@ void __arch_pcpu_init(uint32_t coreid)
                pcpui->gdt = (segdesc_t*)(*my_stack_bot +
                                          sizeof(taskstate_t) + sizeof(pseudodesc_t));
        }
                pcpui->gdt = (segdesc_t*)(*my_stack_bot +
                                          sizeof(taskstate_t) + sizeof(pseudodesc_t));
        }
-       assert(read_msr(MSR_GS_BASE) == (uint64_t)pcpui);
+       assert(read_gsbase() == (uintptr_t)pcpui);
        assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
        /* Don't try setting up til after setting GS */
        x86_sysenter_init(x86_get_stacktop_tss(pcpui->tss));
        assert(read_msr(MSR_KERN_GS_BASE) == (uint64_t)pcpui);
        /* 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();
+       /* need to init perfctr before potentially using it in timer handler */
+       perfmon_pcpu_init();
+       vmm_pcpu_init();
+       lcr4(rcr4() & ~CR4_TSD);
 }
 }