akaros/kern/arch/x86/cpuinfo.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2009 The Regents of the University of California
   3 * Barret Rhoden <brho@cs.berkeley.edu>
   4 * See LICENSE for details.
   5 */
   6
   7#include <arch/arch.h>
   8#include <arch/x86.h>
   9#include <arch/mmu.h>
  10#include <stdio.h>
  11#include <assert.h>
  12#include <ros/memlayout.h>
  13#include <pmap.h>
  14#include <kdebug.h>
  15#include <string.h>
  16#include <cpu_feat.h>
  17
  18int x86_family, x86_model, x86_stepping;
  19
  20/* Check Intel's SDM 2a for Table 3-17 for the cpuid leaves */
  21void print_cpuinfo(void)
  22{
  23        uint32_t eax, ebx, ecx, edx;
  24        uint32_t model, family, ext_model, ext_family;
  25        uint64_t msr_val;
  26        char vendor_id[13];
  27        int max_std_lvl, max_extd_lvl;
  28        extern char _start[];
  29
  30        if (sizeof(long) == 8)
  31                printk("64 bit Kernel Booting...\n");
  32        else
  33                printk("32 bit Kernel Booting...\n");
  34
  35        // x86 Vendor Detection:
  36        asm volatile ("cpuid;"
  37                  "movl    %%ebx, (%2);"
  38                  "movl    %%edx, 4(%2);"
  39                  "movl    %%ecx, 8(%2);"
  40                 : "=a"(eax)
  41                 : "a"(0), "D"(vendor_id)
  42                 : "%ebx", "%ecx", "%edx");
  43
  44        vendor_id[12] = '\0';
  45        cprintf("Vendor ID: %s\n", vendor_id);
  46        /* not a great check - old intel P5s have no vendor id */
  47        if (!strcmp(vendor_id, "GenuineIntel"))
  48                cpu_set_feat(CPU_FEAT_X86_VENDOR_INTEL);
  49        else if (!strcmp(vendor_id, "AuthenticAMD"))
  50                cpu_set_feat(CPU_FEAT_X86_VENDOR_AMD);
  51
  52
  53        /* intel supports a way to hide the upper leaves of cpuid, beyond 3.
  54         * the bios might have done this, so we'll make sure it is off. */
  55        if (cpu_has_feat(CPU_FEAT_X86_VENDOR_INTEL)) {
  56                msr_val = read_msr(IA32_MISC_ENABLE);
  57                if (msr_val & (1 << 22))
  58                        write_msr(IA32_MISC_ENABLE, msr_val & ~(1 << 22));
  59        }
  60        cprintf("Largest Standard Function Number Supported: %d\n", eax);
  61        max_std_lvl = eax;
  62        cpuid(0x80000000, 0x0, &eax, 0, 0, 0);
  63        cprintf("Largest Extended Function Number Supported: 0x%08x\n", eax);
  64        max_extd_lvl = eax;
  65        cpuid(1, 0x0, &eax, &ebx, &ecx, &edx);
  66        ext_family = (eax >> 20) & 0xff;
  67        ext_model = (eax >> 16) & 0xf;
  68        family = (eax >> 8) & 0xf;
  69        model = (eax >> 4) & 0xf;
  70        if ((family == 15) || (family == 6))
  71                model += ext_model << 4;
  72        if (family == 15)
  73                family += ext_family;
  74        x86_family = family;
  75        x86_model = model;
  76        x86_stepping = eax & 0xf;
  77        printk("Family: %d\n", x86_family);
  78        printk("Model: %d\n", x86_model);
  79        printk("Stepping: %d\n", x86_stepping);
  80        // eventually can fill this out with SDM Vol3B App B info, or
  81        // better yet with stepping info.  or cpuid 8000_000{2,3,4}
  82        switch ( family << 8 | model ) {
  83                case(0x061a):
  84                        cprintf("Processor: Core i7\n");
  85                        break;
  86                case(0x060f):
  87                        cprintf("Processor: Core 2 Duo or Similar\n");
  88                        break;
  89                default:
  90                        cprintf("Unknown or non-Intel CPU\n");
  91        }
  92        if (!(edx & 0x00000020))
  93                panic("MSRs not supported!");
  94        if (!(edx & 0x00001000))
  95                panic("MTRRs not supported!");
  96        if (!(edx & (1 << 16)))
  97                panic("PAT not supported!");
  98        if (!(edx & 0x00002000))
  99                panic("Global Pages not supported!");
 100        if (!(edx & 0x00000200))
 101                panic("Local APIC Not Detected!");
 102        if (ecx & 0x00200000)
 103                cprintf("x2APIC Detected\n");
 104        else
 105                panic("x2APIC Not Detected\n");
 106        /* Not sure how to detect AMD HW virt yet. */
 107        if ((ecx & 0x00000060) && cpu_has_feat(CPU_FEAT_X86_VENDOR_INTEL)) {
 108                msr_val = read_msr(IA32_FEATURE_CONTROL);
 109                printd("64 Bit Feature Control: 0x%08x\n", msr_val);
 110                if ((msr_val & 0x5) == 0x5)
 111                        printk("Hardware virtualization supported\n");
 112                else
 113                        printk("Hardware virtualization not supported\n");
 114        } else {
 115                printk("Hardware virtualization not detected.  (AMD?)\n");
 116        }
 117        /* FP and SSE Checks */
 118        if (edx & 0x00000001)
 119                printk("FPU Detected\n");
 120        else
 121                panic("FPU Not Detected!!\n");
 122        printk("SSE support: ");
 123        if (edx & (1 << 25))
 124                printk("sse ");
 125        else
 126                panic("SSE Support Not Detected!!\n");
 127        if (edx & (1 << 26))
 128                printk("sse2 ");
 129        if (ecx & (1 << 0))
 130                printk("sse3 ");
 131        if (ecx & (1 << 9))
 132                printk("ssse3 ");
 133        if (ecx & (1 << 19))
 134                printk("sse4.1 ");
 135        if (ecx & (1 << 20))
 136                printk("sse4.2 ");
 137        if (edx & (1 << 23))
 138                printk("mmx ");
 139        if ((edx & (1 << 25)) && (!(edx & (1 << 24))))
 140                panic("SSE support, but no FXSAVE!");
 141        printk("\n");
 142        cpuid(0x80000008, 0x0, &eax, &ebx, &ecx, &edx);
 143        cprintf("Physical Address Bits: %d\n", eax & 0x000000FF);
 144        msr_val = read_msr(IA32_APIC_BASE);
 145        if (!(msr_val & MSR_APIC_ENABLE))
 146                panic("Local APIC Disabled!!");
 147        cpuid(0x80000007, 0x0, &eax, &ebx, &ecx, &edx);
 148        if (edx & 0x00000100)
 149                printk("Invariant TSC present\n");
 150        else
 151                printk("Invariant TSC not present\n");
 152        cpuid(0x07, 0x0, &eax, &ebx, &ecx, &edx);
 153        if (ebx & 0x00000001) {
 154                printk("FS/GS Base RD/W supported\n");
 155                cpu_set_feat(CPU_FEAT_X86_FSGSBASE);
 156        } else {
 157                printk("FS/GS Base RD/W not supported\n");
 158                #ifdef CONFIG_NOFASTCALL_FSBASE
 159                panic("Can't write FS Base from userspace, and no FASTCALL support!");
 160                #endif
 161        }
 162        cpuid(0x80000001, 0x0, &eax, &ebx, &ecx, &edx);
 163        if (edx & (1 << 27)) {
 164                printk("RDTSCP supported\n");
 165                /* Set core 0's id, for use during boot (if FAST_COREID) */
 166                write_msr(MSR_TSC_AUX, 0);
 167        } else {
 168                printk("RDTSCP not supported, but emulated for userspace\n");
 169        }
 170        /* Regardless, make sure userspace can access rdtsc (and rdtscp) */
 171        lcr4(rcr4() & ~CR4_TSD);
 172        printk("1 GB Jumbo pages %ssupported\n", edx & (1 << 26) ? "" : "not ");
 173        if (!(edx & (1 << 29))) {
 174                printk("Not 64 bit, refusing to boot!\n");
 175                while (1)
 176                        asm volatile ("hlt");
 177        }
 178        cpuid(0x00000006, 0x0, &eax, 0, 0, 0);
 179        if (eax & (1 << 2))
 180                printk("Always running APIC detected\n");
 181        else
 182                printk("Always running APIC *not* detected\n");
 183
 184        /* TODO: Eventually consolidate all of our "cpuid" stuff. */
 185        #define CPUID_FXSR_SUPPORT          (1 << 24)
 186        #define CPUID_XSAVE_SUPPORT         (1 << 26)
 187        #define CPUID_XSAVEOPT_SUPPORT      (1 << 0)
 188        #define CPUID_MONITOR_MWAIT         (1 << 3)
 189        #define CPUID_MWAIT_PWR_MGMT        (1 << 0)
 190
 191        cpuid(0x01, 0x00, 0, 0, &ecx, &edx);
 192        if (CPUID_FXSR_SUPPORT & edx)
 193                cpu_set_feat(CPU_FEAT_X86_FXSR);
 194        if (CPUID_XSAVE_SUPPORT & ecx)
 195                cpu_set_feat(CPU_FEAT_X86_XSAVE);
 196
 197        cpuid(0x0d, 0x01, &eax, 0, 0, 0);
 198        if (CPUID_XSAVEOPT_SUPPORT & eax)
 199                cpu_set_feat(CPU_FEAT_X86_XSAVEOPT);
 200
 201        cpuid(0x01, 0x00, 0, 0, &ecx, 0);
 202        if (CPUID_MONITOR_MWAIT & ecx) {
 203                cpuid(0x05, 0x00, 0, 0, &ecx, 0);
 204                if (CPUID_MWAIT_PWR_MGMT & ecx)
 205                        cpu_set_feat(CPU_FEAT_X86_MWAIT);
 206        }
 207}
 208
 209#define BIT_SPACING "        "
 210#define BIT_DASHES "----------------"
 211
 212void show_mapping(pgdir_t pgdir, uintptr_t start, size_t size)
 213{
 214        pte_t pte;
 215        int perm;
 216        page_t *page;
 217        uintptr_t i;
 218
 219        printk("   %sVirtual    %sPhysical  Ps Dr Ac G CD WT U W P EPTE\n",
 220               BIT_SPACING, BIT_SPACING);
 221        printk("-------------------------------------------------%s\n",
 222               BIT_DASHES);
 223        for(i = 0; i < size; i += PGSIZE, start += PGSIZE) {
 224                pte = pgdir_walk(pgdir, (void*)start, 0);
 225                printk("%p  ", start);
 226                if (pte_walk_okay(pte)) {
 227                        /* A note on PTE perms.  If you look at just the PTE,
 228                         * you don't get the full picture for W and U.  Those
 229                         * are the intersection of all bits.  In Akaros, we do U
 230                         * or not at the earliest point (PML4 entries).  All
 231                         * other PTEs have U set.  For W, it's the opposite.
 232                         * The PTE for the actual page has W or not, and all
 233                         * others has W set.  W needs to be more fine-grained,
 234                         * but U doesn't.  Plus the UVPT mapping requires the U
 235                         * to see interior pages (but have W off). */
 236                        perm = get_va_perms(pgdir, (void*)start);
 237                        printk("%p  %1d  %1d  %1d  %1d %1d  %1d  %1d %1d %1d 0x%llx\n",
 238                               pte_get_paddr(pte),
 239                               pte_is_jumbo(pte),
 240                               pte_is_dirty(pte),
 241                               pte_is_accessed(pte),
 242                               (pte_print(pte) & PTE_G) / PTE_G,
 243                               (pte_print(pte) & __PTE_PCD) / __PTE_PCD,
 244                               (pte_print(pte) & __PTE_PWT) / __PTE_PWT,
 245                               (perm & PTE_U) / PTE_U,
 246                               (perm & PTE_W) / PTE_W,
 247                               pte_is_present(pte),
 248                               *(unsigned long*)kpte_to_epte(pte));
 249                } else {
 250                        printk("%p\n", 0);
 251                }
 252        }
 253}
 254
 255/* return 0 if ok, -1 if it failed for some reason.
 256 * Be sensible and call it with 16 bytes.
 257 */
 258int vendor_id(char *vid)
 259{
 260        uint32_t eax, ebx, ecx, edx;
 261
 262        asm volatile ("cpuid;"
 263                  "movl    %%ebx, (%2);"
 264                  "movl    %%edx, 4(%2);"
 265                  "movl    %%ecx, 8(%2);"
 266                 : "=a"(eax)
 267                 : "a"(0), "D"(vid)
 268                 : "%ebx", "%ecx", "%edx");
 269
 270        vid[12] = '\0';
 271        return 0;
 272}
 273