x86: Fix cpu detection shift error
[akaros.git] / kern / arch / x86 / cpuinfo.c
index d3b7884..cbd8e21 100644 (file)
@@ -4,10 +4,6 @@
  * See LICENSE for details.
  */
 
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
 #include <arch/arch.h>
 #include <arch/x86.h>
 #include <arch/mmu.h>
@@ -17,6 +13,7 @@
 #include <pmap.h>
 #include <kdebug.h>
 #include <string.h>
+#include <cpu_feat.h>
 
 /* Check Intel's SDM 2a for Table 3-17 for the cpuid leaves */
 void print_cpuinfo(void)
@@ -25,12 +22,15 @@ void print_cpuinfo(void)
        uint32_t model, family;
        uint64_t msr_val;
        char vendor_id[13];
-       extern char (SNT RO _start)[];
+       int max_std_lvl, max_extd_lvl;
+       extern char _start[];
 
        if (sizeof(long) == 8)
                printk("64 bit Kernel Booting...\n");
        else
                printk("32 bit Kernel Booting...\n");
+
+       // x86 Vendor Detection:
        asm volatile ("cpuid;"
                  "movl    %%ebx, (%2);"
                  "movl    %%edx, 4(%2);"
@@ -41,12 +41,28 @@ void print_cpuinfo(void)
 
        vendor_id[12] = '\0';
        cprintf("Vendor ID: %s\n", vendor_id);
+       /* not a great check - old intel P5s have no vendor id */
+       if (!strcmp(vendor_id, "GenuineIntel"))
+               cpu_set_feat(CPU_FEAT_X86_VENDOR_INTEL);
+       else if (!strcmp(vendor_id, "AuthenticAMD"))
+               cpu_set_feat(CPU_FEAT_X86_VENDOR_AMD);
+
+
+       /* intel supports a way to hide the upper leaves of cpuid, beyond 3.  the
+        * bios might have done this, so we'll make sure it is off. */
+       if (cpu_has_feat(CPU_FEAT_X86_VENDOR_INTEL)) {
+               msr_val = read_msr(IA32_MISC_ENABLE);
+               if (msr_val & (1 << 22))
+                       write_msr(IA32_MISC_ENABLE, msr_val & ~(1 << 22));
+       }
        cprintf("Largest Standard Function Number Supported: %d\n", eax);
+       max_std_lvl = eax;
        cpuid(0x80000000, 0x0, &eax, 0, 0, 0);
        cprintf("Largest Extended Function Number Supported: 0x%08x\n", eax);
+       max_extd_lvl = eax;
        cpuid(1, 0x0, &eax, &ebx, &ecx, &edx);
        family = ((eax & 0x0FF00000) >> 20) + ((eax & 0x00000F00) >> 8);
-       model = ((eax & 0x000F0000) >> 12) + ((eax & 0x000000F0) >> 4);
+       model = ((eax & 0x000F0000) >> 16) + ((eax & 0x000000F0) >> 4);
        cprintf("Family: %d\n", family);
        cprintf("Model: %d\n", model);
        cprintf("Stepping: %d\n", eax & 0x0000000F);
@@ -66,6 +82,8 @@ void print_cpuinfo(void)
                panic("MSRs not supported!");
        if (!(edx & 0x00001000))
                panic("MTRRs not supported!");
+       if (!(edx & (1 << 16)))
+               panic("PAT not supported!");
        if (!(edx & 0x00002000))
                panic("Global Pages not supported!");
        if (!(edx & 0x00000200))
@@ -74,15 +92,16 @@ void print_cpuinfo(void)
                cprintf("x2APIC Detected\n");
        else
                cprintf("x2APIC Not Detected\n");
-       if (ecx & 0x00000060) {
+       /* Not sure how to detect AMD HW virt yet. */
+       if ((ecx & 0x00000060) && cpu_has_feat(CPU_FEAT_X86_VENDOR_INTEL)) {
                msr_val = read_msr(IA32_FEATURE_CONTROL);
                printd("64 Bit Feature Control: 0x%08x\n", msr_val);
                if ((msr_val & 0x5) == 0x5)
                        printk("Hardware virtualization supported\n");
                else
                        printk("Hardware virtualization not supported\n");
-       } else { 
-               printk("Hardware virtualization not supported\n");
+       } else {
+               printk("Hardware virtualization not detected.  (AMD?)\n");
        }
        /* FP and SSE Checks */
        if (edx & 0x00000001)
@@ -122,95 +141,111 @@ void print_cpuinfo(void)
        cpuid(0x07, 0x0, &eax, &ebx, &ecx, &edx);
        if (ebx & 0x00000001) {
                printk("FS/GS Base RD/W supported\n");
-               /* Untested, since we don't have a machine that supports this.  Email us
-                * if this fails. */
-               printk("Attempting to enable WRFSBASE...\n");
-               lcr4(rcr4() | (1 << 16));
+               cpu_set_feat(CPU_FEAT_X86_FSGSBASE);
        } else {
                printk("FS/GS Base RD/W not supported\n");
                #ifdef CONFIG_NOFASTCALL_FSBASE
-               printk("\nGIANT WARNING: Can't write FS Base from userspace, "
-                      "and no FASTCALL support!\n\n");
+               panic("Can't write FS Base from userspace, and no FASTCALL support!");
                #endif
        }
        cpuid(0x80000001, 0x0, &eax, &ebx, &ecx, &edx);
-       if (edx & (1 << 27))
+       if (edx & (1 << 27)) {
                printk("RDTSCP supported\n");
-       else
-               printk("RDTSCP not supported: don't trust detailed measurements\n");
+               /* Set core 0's id, for use during boot (if FAST_COREID) */
+               write_msr(MSR_TSC_AUX, 0);
+       } else {
+               printk("RDTSCP not supported, but emulated for userspace\n");
+       }
+       /* Regardless, make sure userspace can access rdtsc (and rdtscp) */
+       lcr4(rcr4() & ~CR4_TSD);
+       printk("1 GB Jumbo pages %ssupported\n", edx & (1 << 26) ? "" : "not ");
        printk("FS/GS MSRs %ssupported\n", edx & (1 << 29) ? "" : "not ");
-       #ifdef CONFIG_X86_64
        if (!(edx & (1 << 29))) {
                printk("Can't handle no FS/GS MSRs!\n");
                while (1)
                        asm volatile ("hlt");
        }
-       #endif
-       msr_val = read_msr(IA32_MISC_ENABLE);
-       /* we want this to be not set for cpuid.6h to work. */
-       if (msr_val & (1 << 22))
-               write_msr(IA32_MISC_ENABLE, msr_val & ~(1 << 22));
        cpuid(0x00000006, 0x0, &eax, 0, 0, 0);
        if (eax & (1 << 2))
                printk("Always running APIC detected\n");
        else
                printk("Always running APIC *not* detected\n");
+
+       /* TODO: Eventually consolidate all of our "cpuid" stuff. */
+       #define CPUID_FXSR_SUPPORT          (1 << 24)
+       #define CPUID_XSAVE_SUPPORT         (1 << 26)
+       #define CPUID_XSAVEOPT_SUPPORT      (1 << 0)
+
+       cpuid(0x01, 0x00, 0, 0, &ecx, &edx);
+       if (CPUID_FXSR_SUPPORT & edx)
+               cpu_set_feat(CPU_FEAT_X86_FXSR);
+       if (CPUID_XSAVE_SUPPORT & ecx)
+               cpu_set_feat(CPU_FEAT_X86_XSAVE);
+
+       cpuid(0x0d, 0x01, &eax, 0, 0, 0);
+       if (CPUID_XSAVEOPT_SUPPORT & eax)
+               cpu_set_feat(CPU_FEAT_X86_XSAVEOPT);
+
 }
 
-#ifdef CONFIG_X86_64
 #define BIT_SPACING "        "
 #define BIT_DASHES "----------------"
-#else
-#define BIT_SPACING ""
-#define BIT_DASHES ""
-#endif
 
-void show_mapping(uintptr_t start, size_t size)
+void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size)
 {
-       pde_t *pgdir = (pde_t*)vpd;
-       pte_t *pte;
-       pte_t *pde;
+       pte_t pte;
+       int perm;
        page_t *page;
        uintptr_t i;
 
-       printk("   %sVirtual    %sPhysical  Ps Dr Ac CD WT U W P\n", BIT_SPACING,
-              BIT_SPACING);
-       printk("--------------------------------------------%s\n", BIT_DASHES);
+       printk("   %sVirtual    %sPhysical  Ps Dr Ac CD WT U W P EPTE\n",
+              BIT_SPACING, BIT_SPACING);
+       printk("-------------------------------------------------%s\n", BIT_DASHES);
        for(i = 0; i < size; i += PGSIZE, start += PGSIZE) {
                pte = pgdir_walk(pgdir, (void*)start, 0);
                printk("%p  ", start);
-               if (pte) {
-                       pde = &pgdir[PDX(start)];
-                       /* for a jumbo, pde = pte and PTE_PS (better be) = 1 */
-                       printk("%p  %1d  %1d  %1d  %1d  %1d  %1d %1d %1d\n",
-                              PTE_ADDR(*pte), (*pte & PTE_PS) >> 7, (*pte & PTE_D) >> 6,
-                              (*pte & PTE_A) >> 5, (*pte & PTE_PCD) >> 4,
-                              (*pte & PTE_PWT) >> 3, (*pte & *pde & PTE_U) >> 2,
-                              (*pte & *pde & PTE_W) >> 1, (*pte & PTE_P));
+               if (pte_walk_okay(pte)) {
+                       /* A note on PTE perms.  If you look at just the PTE, you don't get
+                        * the full picture for W and U.  Those are the intersection of all
+                        * bits.  In Akaros, we do U or not at the earliest point (PML4
+                        * entries).  All other PTEs have U set.  For W, it's the opposite.
+                        * The PTE for the actual page has W or not, and all others has W
+                        * set.  W needs to be more fine-grained, but U doesn't.  Plus the
+                        * UVPT mapping requires the U to see interior pages (but have W
+                        * off). */
+                       perm = get_va_perms(pgdir, (void*)start);
+                       printk("%p  %1d  %1d  %1d  %1d  %1d  %1d %1d %1d 0x%llx\n",
+                              pte_get_paddr(pte),
+                              pte_is_jumbo(pte),
+                              pte_is_dirty(pte),
+                              pte_is_accessed(pte),
+                              (pte_print(pte) & __PTE_PCD) / __PTE_PCD,
+                              (pte_print(pte) & __PTE_PWT) / __PTE_PWT,
+                              (perm & PTE_U) / PTE_U,
+                              (perm & PTE_W) / PTE_W,
+                              pte_is_present(pte),
+                              *(unsigned long*)kpte_to_epte(pte));
                } else {
                        printk("%p\n", 0);
                }
        }
 }
 
-/* Like backtrace, this is probably not the best place for this. */
-void spinlock_debug(spinlock_t *lock)
+/* return 0 if ok, -1 if it failed for some reason.
+ * Be sensible and call it with 16 bytes.
+ */
+int vendor_id(char *vid)
 {
-#ifdef CONFIG_SPINLOCK_DEBUG
-       eipdebuginfo_t debuginfo;
-       char buf[256];
-       uint32_t eip = (uint32_t)lock->call_site;
-
-       if (!eip) {
-               printk("Lock %p: never locked\n", lock);
-               return;
-       }
-       debuginfo_eip(eip, &debuginfo);
-       memset(buf, 0, 256);
-       strncpy(buf, debuginfo.eip_fn_name, MIN(debuginfo.eip_fn_namelen, 256));
-       buf[MIN(debuginfo.eip_fn_namelen, 255)] = 0;
-       printk("Lock %p: last locked at [<%p>] in %s(%p) on core %d\n", lock, eip, buf,
-              debuginfo.eip_fn_addr, lock->calling_core);
-#endif
-}
+       uint32_t eax, ebx, ecx, edx;
+
+       asm volatile ("cpuid;"
+                 "movl    %%ebx, (%2);"
+                 "movl    %%edx, 4(%2);"
+                 "movl    %%ecx, 8(%2);"
+                : "=a"(eax)
+                : "a"(0), "D"(vid)
+                : "%ebx", "%ecx", "%edx");
 
+       vid[12] = '\0';
+       return 0;
+}