| /* |
| * Copyright (c) 2009 The Regents of the University of California |
| * Barret Rhoden <brho@cs.berkeley.edu> |
| * See LICENSE for details. |
| */ |
| |
| #include <arch/arch.h> |
| #include <arch/x86.h> |
| #include <arch/mmu.h> |
| #include <stdio.h> |
| #include <assert.h> |
| #include <ros/memlayout.h> |
| #include <pmap.h> |
| #include <kdebug.h> |
| #include <string.h> |
| #include <cpu_feat.h> |
| |
| int x86_family, x86_model, x86_stepping; |
| |
| /* Check Intel's SDM 2a for Table 3-17 for the cpuid leaves */ |
| void print_cpuinfo(void) |
| { |
| uint32_t eax, ebx, ecx, edx; |
| uint32_t model, family, ext_model, ext_family; |
| uint64_t msr_val; |
| char vendor_id[13]; |
| 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);" |
| "movl %%ecx, 8(%2);" |
| : "=a"(eax) |
| : "a"(0), "D"(vendor_id) |
| : "%ebx", "%ecx", "%edx"); |
| |
| 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); |
| ext_family = (eax >> 20) & 0xff; |
| ext_model = (eax >> 16) & 0xf; |
| family = (eax >> 8) & 0xf; |
| model = (eax >> 4) & 0xf; |
| if ((family == 15) || (family == 6)) |
| model += ext_model << 4; |
| if (family == 15) |
| family += ext_family; |
| x86_family = family; |
| x86_model = model; |
| x86_stepping = eax & 0xf; |
| printk("Family: %d\n", x86_family); |
| printk("Model: %d\n", x86_model); |
| printk("Stepping: %d\n", x86_stepping); |
| // eventually can fill this out with SDM Vol3B App B info, or |
| // better yet with stepping info. or cpuid 8000_000{2,3,4} |
| switch ( family << 8 | model ) { |
| case(0x061a): |
| cprintf("Processor: Core i7\n"); |
| break; |
| case(0x060f): |
| cprintf("Processor: Core 2 Duo or Similar\n"); |
| break; |
| default: |
| cprintf("Unknown or non-Intel CPU\n"); |
| } |
| if (!(edx & 0x00000020)) |
| 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)) |
| panic("Local APIC Not Detected!"); |
| if (ecx & 0x00200000) |
| cprintf("x2APIC Detected\n"); |
| else |
| panic("x2APIC Not Detected\n"); |
| /* 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 detected. (AMD?)\n"); |
| } |
| /* FP and SSE Checks */ |
| if (edx & 0x00000001) |
| printk("FPU Detected\n"); |
| else |
| panic("FPU Not Detected!!\n"); |
| printk("SSE support: "); |
| if (edx & (1 << 25)) |
| printk("sse "); |
| else |
| panic("SSE Support Not Detected!!\n"); |
| if (edx & (1 << 26)) |
| printk("sse2 "); |
| if (ecx & (1 << 0)) |
| printk("sse3 "); |
| if (ecx & (1 << 9)) |
| printk("ssse3 "); |
| if (ecx & (1 << 19)) |
| printk("sse4.1 "); |
| if (ecx & (1 << 20)) |
| printk("sse4.2 "); |
| if (edx & (1 << 23)) |
| printk("mmx "); |
| if ((edx & (1 << 25)) && (!(edx & (1 << 24)))) |
| panic("SSE support, but no FXSAVE!"); |
| printk("\n"); |
| cpuid(0x80000008, 0x0, &eax, &ebx, &ecx, &edx); |
| cprintf("Physical Address Bits: %d\n", eax & 0x000000FF); |
| msr_val = read_msr(IA32_APIC_BASE); |
| if (!(msr_val & MSR_APIC_ENABLE)) |
| panic("Local APIC Disabled!!"); |
| cpuid(0x80000007, 0x0, &eax, &ebx, &ecx, &edx); |
| if (edx & 0x00000100) |
| printk("Invariant TSC present\n"); |
| else |
| printk("Invariant TSC not present\n"); |
| cpuid(0x07, 0x0, &eax, &ebx, &ecx, &edx); |
| if (ebx & 0x00000001) { |
| printk("FS/GS Base RD/W supported\n"); |
| cpu_set_feat(CPU_FEAT_X86_FSGSBASE); |
| } else { |
| printk("FS/GS Base RD/W not supported\n"); |
| #ifdef CONFIG_NOFASTCALL_FSBASE |
| panic("Can't write FS Base from userspace, and no FASTCALL support!"); |
| #endif |
| } |
| cpuid(0x80000001, 0x0, &eax, &ebx, &ecx, &edx); |
| if (edx & (1 << 27)) { |
| printk("RDTSCP supported\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 "); |
| if (!(edx & (1 << 29))) { |
| printk("Not 64 bit, refusing to boot!\n"); |
| while (1) |
| asm volatile ("hlt"); |
| } |
| 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) |
| #define CPUID_MONITOR_MWAIT (1 << 3) |
| #define CPUID_MWAIT_PWR_MGMT (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); |
| |
| cpuid(0x01, 0x00, 0, 0, &ecx, 0); |
| if (CPUID_MONITOR_MWAIT & ecx) { |
| cpuid(0x05, 0x00, 0, 0, &ecx, 0); |
| if (CPUID_MWAIT_PWR_MGMT & ecx) |
| cpu_set_feat(CPU_FEAT_X86_MWAIT); |
| } |
| } |
| |
| #define BIT_SPACING " " |
| #define BIT_DASHES "----------------" |
| |
| void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size) |
| { |
| pte_t pte; |
| int perm; |
| page_t *page; |
| uintptr_t i; |
| |
| printk(" %sVirtual %sPhysical Ps Dr Ac G 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_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 %1d 0x%llx\n", |
| pte_get_paddr(pte), |
| pte_is_jumbo(pte), |
| pte_is_dirty(pte), |
| pte_is_accessed(pte), |
| (pte_print(pte) & PTE_G) / PTE_G, |
| (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); |
| } |
| } |
| } |
| |
| /* return 0 if ok, -1 if it failed for some reason. |
| * Be sensible and call it with 16 bytes. |
| */ |
| int vendor_id(char *vid) |
| { |
| 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; |
| } |