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