| Commit | Line | Data |
|---|---|---|
| c8fe38ae MD |
1 | /*- |
| 2 | * Copyright (c) 1992 Terrence R. Lambert. | |
| 3 | * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. | |
| 4 | * Copyright (c) 1997 KATO Takenori. | |
| 5 | * Copyright (c) 2008 The DragonFly Project. | |
| 6 | * All rights reserved. | |
| 7 | * | |
| 8 | * This code is derived from software contributed to Berkeley by | |
| 9 | * William Jolitz. | |
| 10 | * | |
| 11 | * Redistribution and use in source and binary forms, with or without | |
| 12 | * modification, are permitted provided that the following conditions | |
| 13 | * are met: | |
| 14 | * 1. Redistributions of source code must retain the above copyright | |
| 15 | * notice, this list of conditions and the following disclaimer. | |
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 17 | * notice, this list of conditions and the following disclaimer in the | |
| 18 | * documentation and/or other materials provided with the distribution. | |
| 19 | * 3. All advertising materials mentioning features or use of this software | |
| 20 | * must display the following acknowledgement: | |
| 21 | * This product includes software developed by the University of | |
| 22 | * California, Berkeley and its contributors. | |
| 23 | * 4. Neither the name of the University nor the names of its contributors | |
| 24 | * may be used to endorse or promote products derived from this software | |
| 25 | * without specific prior written permission. | |
| 26 | * | |
| 27 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 28 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 29 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 30 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 31 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 32 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 33 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 34 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 35 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 36 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 37 | * SUCH DAMAGE. | |
| 38 | * | |
| 39 | * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp | |
| c8fe38ae MD |
40 | */ |
| 41 | ||
| 42 | #include "opt_cpu.h" | |
| 43 | ||
| 44 | #include <sys/param.h> | |
| 45 | #include <sys/bus.h> | |
| c8fe38ae MD |
46 | #include <sys/eventhandler.h> |
| 47 | #include <sys/systm.h> | |
| 48 | #include <sys/kernel.h> | |
| 49 | #include <sys/sysctl.h> | |
| 50 | #include <sys/power.h> | |
| 51 | ||
| 52 | #include <machine/asmacros.h> | |
| 53 | #include <machine/clock.h> | |
| 54 | #include <machine/cputypes.h> | |
| 55 | #include <machine/frame.h> | |
| 46d4e165 | 56 | #include <machine_base/isa/intr_machdep.h> |
| c8fe38ae MD |
57 | #include <machine/segments.h> |
| 58 | #include <machine/specialreg.h> | |
| 59 | #include <machine/md_var.h> | |
| 60 | ||
| c8fe38ae MD |
61 | /* XXX - should be in header file: */ |
| 62 | void printcpuinfo(void); | |
| 63 | void identify_cpu(void); | |
| 64 | void earlysetcpuclass(void); | |
| 65 | void panicifcpuunsupported(void); | |
| 66 | ||
| a2a636cc | 67 | static u_int find_cpu_vendor_id(void); |
| c8fe38ae MD |
68 | static void print_AMD_info(void); |
| 69 | static void print_AMD_assoc(int i); | |
| a2a636cc | 70 | static void print_via_padlock_info(void); |
| c8fe38ae MD |
71 | |
| 72 | int cpu_class; | |
| c1543a89 | 73 | char machine[] = "x86_64"; |
| c8fe38ae MD |
74 | SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, |
| 75 | machine, 0, "Machine class"); | |
| 76 | ||
| 77 | static char cpu_model[128]; | |
| 78 | SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, | |
| 79 | cpu_model, 0, "Machine model"); | |
| 80 | ||
| 81 | static int hw_clockrate; | |
| 82 | SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, | |
| 83 | &hw_clockrate, 0, "CPU instruction clock rate"); | |
| 84 | ||
| 85 | static char cpu_brand[48]; | |
| 86 | ||
| 87 | static struct { | |
| 88 | char *cpu_name; | |
| 89 | int cpu_class; | |
| c1543a89 | 90 | } x86_64_cpus[] = { |
| a2a636cc MD |
91 | { "Clawhammer", CPUCLASS_K8 }, /* CPU_CLAWHAMMER */ |
| 92 | { "Sledgehammer", CPUCLASS_K8 }, /* CPU_SLEDGEHAMMER */ | |
| 93 | }; | |
| 94 | ||
| 95 | static struct { | |
| 96 | char *vendor; | |
| 97 | u_int vendor_id; | |
| 98 | } cpu_vendors[] = { | |
| 99 | { INTEL_VENDOR_ID, CPU_VENDOR_INTEL }, /* GenuineIntel */ | |
| 100 | { AMD_VENDOR_ID, CPU_VENDOR_AMD }, /* AuthenticAMD */ | |
| 101 | { CENTAUR_VENDOR_ID, CPU_VENDOR_CENTAUR }, /* CentaurHauls */ | |
| c8fe38ae MD |
102 | }; |
| 103 | ||
| 104 | int cpu_cores; | |
| 105 | int cpu_logical; | |
| 106 | ||
| 107 | ||
| 108 | extern int pq_l2size; | |
| 109 | extern int pq_l2nways; | |
| 110 | ||
| 111 | void | |
| 112 | printcpuinfo(void) | |
| 113 | { | |
| 114 | u_int regs[4], i; | |
| 115 | char *brand; | |
| 116 | ||
| c1543a89 | 117 | cpu_class = x86_64_cpus[cpu].cpu_class; |
| c8fe38ae | 118 | kprintf("CPU: "); |
| c1543a89 | 119 | strncpy(cpu_model, x86_64_cpus[cpu].cpu_name, sizeof (cpu_model)); |
| c8fe38ae MD |
120 | |
| 121 | /* Check for extended CPUID information and a processor name. */ | |
| 122 | if (cpu_exthigh >= 0x80000004) { | |
| 123 | brand = cpu_brand; | |
| 124 | for (i = 0x80000002; i < 0x80000005; i++) { | |
| 125 | do_cpuid(i, regs); | |
| 126 | memcpy(brand, regs, sizeof(regs)); | |
| 127 | brand += sizeof(regs); | |
| 128 | } | |
| 129 | } | |
| 130 | ||
| a2a636cc MD |
131 | switch (cpu_vendor_id) { |
| 132 | case CPU_VENDOR_INTEL: | |
| c8fe38ae MD |
133 | /* Please make up your mind folks! */ |
| 134 | strcat(cpu_model, "EM64T"); | |
| a2a636cc MD |
135 | break; |
| 136 | case CPU_VENDOR_AMD: | |
| c8fe38ae MD |
137 | /* |
| 138 | * Values taken from AMD Processor Recognition | |
| 139 | * http://www.amd.com/K6/k6docs/pdf/20734g.pdf | |
| 140 | * (also describes ``Features'' encodings. | |
| 141 | */ | |
| 142 | strcpy(cpu_model, "AMD "); | |
| a2a636cc | 143 | if ((cpu_id & 0xf00) == 0xf00) |
| c8fe38ae | 144 | strcat(cpu_model, "AMD64 Processor"); |
| a2a636cc | 145 | else |
| c8fe38ae | 146 | strcat(cpu_model, "Unknown"); |
| a2a636cc MD |
147 | break; |
| 148 | case CPU_VENDOR_CENTAUR: | |
| 149 | strcpy(cpu_model, "VIA "); | |
| 150 | if ((cpu_id & 0xff0) == 0x6f0) | |
| 151 | strcat(cpu_model, "Nano Processor"); | |
| 152 | else | |
| 153 | strcat(cpu_model, "Unknown"); | |
| 154 | break; | |
| 155 | default: | |
| 156 | strcat(cpu_model, "Unknown"); | |
| 157 | break; | |
| c8fe38ae MD |
158 | } |
| 159 | ||
| 160 | /* | |
| 161 | * Replace cpu_model with cpu_brand minus leading spaces if | |
| 162 | * we have one. | |
| 163 | */ | |
| 164 | brand = cpu_brand; | |
| 165 | while (*brand == ' ') | |
| 166 | ++brand; | |
| 167 | if (*brand != '\0') | |
| 168 | strcpy(cpu_model, brand); | |
| 169 | ||
| 170 | kprintf("%s (", cpu_model); | |
| e73e7a30 | 171 | switch(cpu_class) { |
| a2a636cc MD |
172 | case CPUCLASS_K8: |
| 173 | hw_clockrate = (tsc_frequency + 5000) / 1000000; | |
| 174 | kprintf("%jd.%02d-MHz ", | |
| 175 | (intmax_t)(tsc_frequency + 4999) / 1000000, | |
| 176 | (u_int)((tsc_frequency + 4999) / 10000) % 100); | |
| 177 | kprintf("K8"); | |
| 178 | break; | |
| c8fe38ae | 179 | default: |
| a2a636cc | 180 | kprintf("Unknown"); /* will panic below... */ |
| c8fe38ae MD |
181 | } |
| 182 | kprintf("-class CPU)\n"); | |
| a2a636cc MD |
183 | if (*cpu_vendor) |
| 184 | kprintf(" Origin = \"%s\"", cpu_vendor); | |
| 185 | if (cpu_id) | |
| c8fe38ae MD |
186 | kprintf(" Id = 0x%x", cpu_id); |
| 187 | ||
| a2a636cc MD |
188 | if (cpu_vendor_id == CPU_VENDOR_INTEL || |
| 189 | cpu_vendor_id == CPU_VENDOR_AMD || | |
| 190 | cpu_vendor_id == CPU_VENDOR_CENTAUR) { | |
| c8fe38ae MD |
191 | kprintf(" Stepping = %u", cpu_id & 0xf); |
| 192 | if (cpu_high > 0) { | |
| 193 | u_int cmp = 1, htt = 1; | |
| 194 | ||
| 195 | /* | |
| 196 | * Here we should probably set up flags indicating | |
| 197 | * whether or not various features are available. | |
| 198 | * The interesting ones are probably VME, PSE, PAE, | |
| 199 | * and PGE. The code already assumes without bothering | |
| 200 | * to check that all CPUs >= Pentium have a TSC and | |
| 201 | * MSRs. | |
| 202 | */ | |
| 203 | kprintf("\n Features=0x%b", cpu_feature, | |
| 204 | "\020" | |
| 205 | "\001FPU" /* Integral FPU */ | |
| 206 | "\002VME" /* Extended VM86 mode support */ | |
| 207 | "\003DE" /* Debugging Extensions (CR4.DE) */ | |
| 208 | "\004PSE" /* 4MByte page tables */ | |
| 209 | "\005TSC" /* Timestamp counter */ | |
| 210 | "\006MSR" /* Machine specific registers */ | |
| 211 | "\007PAE" /* Physical address extension */ | |
| 212 | "\010MCE" /* Machine Check support */ | |
| 213 | "\011CX8" /* CMPEXCH8 instruction */ | |
| 214 | "\012APIC" /* SMP local APIC */ | |
| 215 | "\013oldMTRR" /* Previous implementation of MTRR */ | |
| 216 | "\014SEP" /* Fast System Call */ | |
| 217 | "\015MTRR" /* Memory Type Range Registers */ | |
| 218 | "\016PGE" /* PG_G (global bit) support */ | |
| 219 | "\017MCA" /* Machine Check Architecture */ | |
| 220 | "\020CMOV" /* CMOV instruction */ | |
| 221 | "\021PAT" /* Page attributes table */ | |
| 222 | "\022PSE36" /* 36 bit address space support */ | |
| 223 | "\023PN" /* Processor Serial number */ | |
| 224 | "\024CLFLUSH" /* Has the CLFLUSH instruction */ | |
| 225 | "\025<b20>" | |
| 226 | "\026DTS" /* Debug Trace Store */ | |
| 227 | "\027ACPI" /* ACPI support */ | |
| 228 | "\030MMX" /* MMX instructions */ | |
| 229 | "\031FXSR" /* FXSAVE/FXRSTOR */ | |
| 230 | "\032SSE" /* Streaming SIMD Extensions */ | |
| 231 | "\033SSE2" /* Streaming SIMD Extensions #2 */ | |
| 232 | "\034SS" /* Self snoop */ | |
| 233 | "\035HTT" /* Hyperthreading (see EBX bit 16-23) */ | |
| 234 | "\036TM" /* Thermal Monitor clock slowdown */ | |
| 235 | "\037IA64" /* CPU can execute IA64 instructions */ | |
| 236 | "\040PBE" /* Pending Break Enable */ | |
| 237 | ); | |
| 238 | ||
| 239 | if (cpu_feature2 != 0) { | |
| 240 | kprintf("\n Features2=0x%b", cpu_feature2, | |
| 241 | "\020" | |
| 242 | "\001SSE3" /* SSE3 */ | |
| 243 | "\002<b1>" | |
| 244 | "\003DTES64" /* 64-bit Debug Trace */ | |
| 245 | "\004MON" /* MONITOR/MWAIT Instructions */ | |
| 246 | "\005DS_CPL" /* CPL Qualified Debug Store */ | |
| 247 | "\006VMX" /* Virtual Machine Extensions */ | |
| 248 | "\007SMX" /* Safer Mode Extensions */ | |
| 249 | "\010EST" /* Enhanced SpeedStep */ | |
| 250 | "\011TM2" /* Thermal Monitor 2 */ | |
| 251 | "\012SSSE3" /* SSSE3 */ | |
| 252 | "\013CNXT-ID" /* L1 context ID available */ | |
| 253 | "\014<b11>" | |
| 254 | "\015<b12>" | |
| 255 | "\016CX16" /* CMPXCHG16B Instruction */ | |
| 256 | "\017xTPR" /* Send Task Priority Messages*/ | |
| 257 | "\020PDCM" /* Perf/Debug Capability MSR */ | |
| 258 | "\021<b16>" | |
| 259 | "\022<b17>" | |
| 260 | "\023DCA" /* Direct Cache Access */ | |
| 261 | "\024SSE4.1" | |
| 262 | "\025SSE4.2" | |
| 263 | "\026x2APIC" /* xAPIC Extensions */ | |
| 33a33a56 | 264 | "\027MOVBE" /* MOVBE instruction */ |
| c8fe38ae MD |
265 | "\030POPCNT" |
| 266 | "\031<b24>" | |
| 267 | "\032<b25>" | |
| 9e3d0133 SW |
268 | "\033XSAVE" |
| 269 | "\034OSXSAVE" | |
| c8fe38ae MD |
270 | "\035<b28>" |
| 271 | "\036<b29>" | |
| 272 | "\037<b30>" | |
| 273 | "\040<b31>" | |
| 274 | ); | |
| 275 | } | |
| 276 | ||
| 277 | /* | |
| 278 | * AMD64 Architecture Programmer's Manual Volume 3: | |
| 279 | * General-Purpose and System Instructions | |
| 280 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf | |
| 281 | * | |
| 282 | * IA-32 Intel Architecture Software Developer's Manual, | |
| 283 | * Volume 2A: Instruction Set Reference, A-M | |
| 284 | * ftp://download.intel.com/design/Pentium4/manuals/25366617.pdf | |
| 285 | */ | |
| 286 | if (amd_feature != 0) { | |
| 287 | kprintf("\n AMD Features=0x%b", amd_feature, | |
| 288 | "\020" /* in hex */ | |
| 289 | "\001<s0>" /* Same */ | |
| 290 | "\002<s1>" /* Same */ | |
| 291 | "\003<s2>" /* Same */ | |
| 292 | "\004<s3>" /* Same */ | |
| 293 | "\005<s4>" /* Same */ | |
| 294 | "\006<s5>" /* Same */ | |
| 295 | "\007<s6>" /* Same */ | |
| 296 | "\010<s7>" /* Same */ | |
| 297 | "\011<s8>" /* Same */ | |
| 298 | "\012<s9>" /* Same */ | |
| 299 | "\013<b10>" /* Undefined */ | |
| 300 | "\014SYSCALL" /* Have SYSCALL/SYSRET */ | |
| 301 | "\015<s12>" /* Same */ | |
| 302 | "\016<s13>" /* Same */ | |
| 303 | "\017<s14>" /* Same */ | |
| 304 | "\020<s15>" /* Same */ | |
| 305 | "\021<s16>" /* Same */ | |
| 306 | "\022<s17>" /* Same */ | |
| 307 | "\023<b18>" /* Reserved, unknown */ | |
| 308 | "\024MP" /* Multiprocessor Capable */ | |
| 309 | "\025NX" /* Has EFER.NXE, NX */ | |
| 310 | "\026<b21>" /* Undefined */ | |
| 311 | "\027MMX+" /* AMD MMX Extensions */ | |
| 312 | "\030<s23>" /* Same */ | |
| 313 | "\031<s24>" /* Same */ | |
| 314 | "\032FFXSR" /* Fast FXSAVE/FXRSTOR */ | |
| 315 | "\033Page1GB" /* 1-GB large page support */ | |
| 316 | "\034RDTSCP" /* RDTSCP */ | |
| 317 | "\035<b28>" /* Undefined */ | |
| 318 | "\036LM" /* 64 bit long mode */ | |
| 319 | "\0373DNow!+" /* AMD 3DNow! Extensions */ | |
| 320 | "\0403DNow!" /* AMD 3DNow! */ | |
| 321 | ); | |
| 322 | } | |
| 323 | ||
| 324 | if (amd_feature2 != 0) { | |
| 325 | kprintf("\n AMD Features2=0x%b", amd_feature2, | |
| 326 | "\020" | |
| 327 | "\001LAHF" /* LAHF/SAHF in long mode */ | |
| 328 | "\002CMP" /* CMP legacy */ | |
| 329 | "\003SVM" /* Secure Virtual Mode */ | |
| 330 | "\004ExtAPIC" /* Extended APIC register */ | |
| 331 | "\005CR8" /* CR8 in legacy mode */ | |
| a2a636cc MD |
332 | "\006ABM" /* LZCNT instruction */ |
| 333 | "\007SSE4A" /* SSE4A */ | |
| 334 | "\010MAS" /* Misaligned SSE mode */ | |
| c8fe38ae | 335 | "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ |
| a2a636cc MD |
336 | "\012OSVW" /* OS visible workaround */ |
| 337 | "\013IBS" /* Instruction based sampling */ | |
| 338 | "\014SSE5" /* SSE5 */ | |
| 339 | "\015SKINIT" /* SKINIT/STGI */ | |
| 340 | "\016WDT" /* Watchdog timer */ | |
| c8fe38ae MD |
341 | "\017<b14>" |
| 342 | "\020<b15>" | |
| 343 | "\021<b16>" | |
| 344 | "\022<b17>" | |
| 345 | "\023<b18>" | |
| 346 | "\024<b19>" | |
| 347 | "\025<b20>" | |
| 348 | "\026<b21>" | |
| 349 | "\027<b22>" | |
| 350 | "\030<b23>" | |
| 351 | "\031<b24>" | |
| 352 | "\032<b25>" | |
| 353 | "\033<b26>" | |
| 354 | "\034<b27>" | |
| 355 | "\035<b28>" | |
| 356 | "\036<b29>" | |
| 357 | "\037<b30>" | |
| 358 | "\040<b31>" | |
| 359 | ); | |
| 360 | } | |
| 361 | ||
| a2a636cc MD |
362 | if (cpu_vendor_id == CPU_VENDOR_CENTAUR) |
| 363 | print_via_padlock_info(); | |
| 364 | ||
| 365 | if ((cpu_feature & CPUID_HTT) && | |
| 366 | cpu_vendor_id == CPU_VENDOR_AMD) | |
| c8fe38ae MD |
367 | cpu_feature &= ~CPUID_HTT; |
| 368 | ||
| 369 | /* | |
| 370 | * If this CPU supports HTT or CMP then mention the | |
| 371 | * number of physical/logical cores it contains. | |
| 372 | */ | |
| 373 | if (cpu_feature & CPUID_HTT) | |
| 374 | htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; | |
| a2a636cc | 375 | if (cpu_vendor_id == CPU_VENDOR_AMD && |
| c8fe38ae MD |
376 | (amd_feature2 & AMDID2_CMP)) |
| 377 | cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; | |
| a2a636cc | 378 | else if (cpu_vendor_id == CPU_VENDOR_INTEL && |
| c8fe38ae MD |
379 | (cpu_high >= 4)) { |
| 380 | cpuid_count(4, 0, regs); | |
| 381 | if ((regs[0] & 0x1f) != 0) | |
| 382 | cmp = ((regs[0] >> 26) & 0x3f) + 1; | |
| 383 | } | |
| 384 | cpu_cores = cmp; | |
| 385 | cpu_logical = htt / cmp; | |
| 386 | if (cmp > 1) | |
| 387 | kprintf("\n Cores per package: %d", cmp); | |
| 388 | if ((htt / cmp) > 1) | |
| 389 | kprintf("\n Logical CPUs per core: %d", | |
| 390 | cpu_logical); | |
| 391 | } | |
| 392 | } | |
| 393 | /* Avoid ugly blank lines: only print newline when we have to. */ | |
| 394 | if (*cpu_vendor || cpu_id) | |
| 395 | kprintf("\n"); | |
| 396 | ||
| 397 | if (!bootverbose) | |
| 398 | return; | |
| 399 | ||
| a2a636cc | 400 | if (cpu_vendor_id == CPU_VENDOR_AMD) |
| c8fe38ae MD |
401 | print_AMD_info(); |
| 402 | } | |
| 403 | ||
| 404 | void | |
| 405 | panicifcpuunsupported(void) | |
| 406 | { | |
| a2a636cc | 407 | |
| c8fe38ae MD |
408 | #ifndef HAMMER_CPU |
| 409 | #error "You need to specify a cpu type" | |
| 410 | #endif | |
| 411 | /* | |
| 412 | * Now that we have told the user what they have, | |
| 413 | * let them know if that machine type isn't configured. | |
| 414 | */ | |
| 415 | switch (cpu_class) { | |
| a2a636cc MD |
416 | case CPUCLASS_X86: |
| 417 | #ifndef HAMMER_CPU | |
| 418 | case CPUCLASS_K8: | |
| c8fe38ae MD |
419 | #endif |
| 420 | panic("CPU class not configured"); | |
| 421 | default: | |
| 422 | break; | |
| 423 | } | |
| 424 | } | |
| 425 | ||
| 426 | ||
| 427 | #if JG | |
| 428 | /* Update TSC freq with the value indicated by the caller. */ | |
| 429 | static void | |
| 430 | tsc_freq_changed(void *arg, const struct cf_level *level, int status) | |
| 431 | { | |
| 432 | /* If there was an error during the transition, don't do anything. */ | |
| 433 | if (status != 0) | |
| 434 | return; | |
| 435 | ||
| 436 | /* Total setting for this level gives the new frequency in MHz. */ | |
| 437 | hw_clockrate = level->total_set.freq; | |
| 438 | } | |
| 439 | ||
| 440 | EVENTHANDLER_DEFINE(cpufreq_post_change, tsc_freq_changed, NULL, | |
| 441 | EVENTHANDLER_PRI_ANY); | |
| 442 | #endif | |
| 443 | ||
| 444 | /* | |
| a2a636cc | 445 | * Final stage of CPU identification. |
| c8fe38ae MD |
446 | */ |
| 447 | void | |
| 448 | identify_cpu(void) | |
| 449 | { | |
| 450 | u_int regs[4]; | |
| 451 | ||
| 452 | do_cpuid(0, regs); | |
| 453 | cpu_high = regs[0]; | |
| 454 | ((u_int *)&cpu_vendor)[0] = regs[1]; | |
| 455 | ((u_int *)&cpu_vendor)[1] = regs[3]; | |
| 456 | ((u_int *)&cpu_vendor)[2] = regs[2]; | |
| 457 | cpu_vendor[12] = '\0'; | |
| a2a636cc | 458 | cpu_vendor_id = find_cpu_vendor_id(); |
| c8fe38ae MD |
459 | |
| 460 | do_cpuid(1, regs); | |
| 461 | cpu_id = regs[0]; | |
| 462 | cpu_procinfo = regs[1]; | |
| 463 | cpu_feature = regs[3]; | |
| 464 | cpu_feature2 = regs[2]; | |
| 465 | ||
| a2a636cc MD |
466 | if (cpu_vendor_id == CPU_VENDOR_INTEL || |
| 467 | cpu_vendor_id == CPU_VENDOR_AMD || | |
| 468 | cpu_vendor_id == CPU_VENDOR_CENTAUR) { | |
| c8fe38ae MD |
469 | do_cpuid(0x80000000, regs); |
| 470 | cpu_exthigh = regs[0]; | |
| 471 | } | |
| 472 | if (cpu_exthigh >= 0x80000001) { | |
| 473 | do_cpuid(0x80000001, regs); | |
| 474 | amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff); | |
| 475 | amd_feature2 = regs[2]; | |
| 476 | } | |
| 477 | if (cpu_exthigh >= 0x80000008) { | |
| 478 | do_cpuid(0x80000008, regs); | |
| 479 | cpu_procinfo2 = regs[2]; | |
| 480 | } | |
| 481 | ||
| 482 | /* XXX */ | |
| a2a636cc MD |
483 | cpu = CPU_CLAWHAMMER; |
| 484 | } | |
| 485 | ||
| 486 | static u_int | |
| 487 | find_cpu_vendor_id(void) | |
| 488 | { | |
| 489 | int i; | |
| 490 | ||
| 491 | for (i = 0; i < sizeof(cpu_vendors) / sizeof(cpu_vendors[0]); i++) | |
| 492 | if (strcmp(cpu_vendor, cpu_vendors[i].vendor) == 0) | |
| 493 | return (cpu_vendors[i].vendor_id); | |
| 494 | return (0); | |
| c8fe38ae MD |
495 | } |
| 496 | ||
| 497 | static void | |
| 498 | print_AMD_assoc(int i) | |
| 499 | { | |
| 500 | if (i == 255) | |
| 501 | kprintf(", fully associative\n"); | |
| 502 | else | |
| 503 | kprintf(", %d-way associative\n", i); | |
| 504 | } | |
| 505 | ||
| 506 | static void | |
| 507 | print_AMD_l2_assoc(int i) | |
| 508 | { | |
| 509 | switch (i & 0x0f) { | |
| 510 | case 0: kprintf(", disabled/not present\n"); break; | |
| 511 | case 1: kprintf(", direct mapped\n"); break; | |
| 512 | case 2: kprintf(", 2-way associative\n"); break; | |
| 513 | case 4: kprintf(", 4-way associative\n"); break; | |
| 514 | case 6: kprintf(", 8-way associative\n"); break; | |
| 515 | case 8: kprintf(", 16-way associative\n"); break; | |
| 516 | case 15: kprintf(", fully associative\n"); break; | |
| 517 | default: kprintf(", reserved configuration\n"); break; | |
| 518 | } | |
| 519 | } | |
| 520 | ||
| 521 | static void | |
| 522 | print_AMD_info(void) | |
| 523 | { | |
| 524 | u_int regs[4]; | |
| 525 | ||
| 526 | if (cpu_exthigh < 0x80000005) | |
| 527 | return; | |
| 528 | ||
| 529 | do_cpuid(0x80000005, regs); | |
| 530 | kprintf("L1 2MB data TLB: %d entries", (regs[0] >> 16) & 0xff); | |
| 531 | print_AMD_assoc(regs[0] >> 24); | |
| 532 | ||
| 533 | kprintf("L1 2MB instruction TLB: %d entries", regs[0] & 0xff); | |
| 534 | print_AMD_assoc((regs[0] >> 8) & 0xff); | |
| 535 | ||
| 536 | kprintf("L1 4KB data TLB: %d entries", (regs[1] >> 16) & 0xff); | |
| 537 | print_AMD_assoc(regs[1] >> 24); | |
| 538 | ||
| 539 | kprintf("L1 4KB instruction TLB: %d entries", regs[1] & 0xff); | |
| 540 | print_AMD_assoc((regs[1] >> 8) & 0xff); | |
| 541 | ||
| 542 | kprintf("L1 data cache: %d kbytes", regs[2] >> 24); | |
| 543 | kprintf(", %d bytes/line", regs[2] & 0xff); | |
| 544 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0xff); | |
| 545 | print_AMD_assoc((regs[2] >> 16) & 0xff); | |
| 546 | ||
| 547 | kprintf("L1 instruction cache: %d kbytes", regs[3] >> 24); | |
| 548 | kprintf(", %d bytes/line", regs[3] & 0xff); | |
| 549 | kprintf(", %d lines/tag", (regs[3] >> 8) & 0xff); | |
| 550 | print_AMD_assoc((regs[3] >> 16) & 0xff); | |
| 551 | ||
| 552 | if (cpu_exthigh >= 0x80000006) { | |
| 553 | do_cpuid(0x80000006, regs); | |
| 554 | if ((regs[0] >> 16) != 0) { | |
| 555 | kprintf("L2 2MB data TLB: %d entries", | |
| 556 | (regs[0] >> 16) & 0xfff); | |
| 557 | print_AMD_l2_assoc(regs[0] >> 28); | |
| 558 | kprintf("L2 2MB instruction TLB: %d entries", | |
| 559 | regs[0] & 0xfff); | |
| 560 | print_AMD_l2_assoc((regs[0] >> 28) & 0xf); | |
| 561 | } else { | |
| 562 | kprintf("L2 2MB unified TLB: %d entries", | |
| 563 | regs[0] & 0xfff); | |
| 564 | print_AMD_l2_assoc((regs[0] >> 28) & 0xf); | |
| 565 | } | |
| 566 | if ((regs[1] >> 16) != 0) { | |
| 567 | kprintf("L2 4KB data TLB: %d entries", | |
| 568 | (regs[1] >> 16) & 0xfff); | |
| 569 | print_AMD_l2_assoc(regs[1] >> 28); | |
| 570 | ||
| 571 | kprintf("L2 4KB instruction TLB: %d entries", | |
| 572 | (regs[1] >> 16) & 0xfff); | |
| 573 | print_AMD_l2_assoc((regs[1] >> 28) & 0xf); | |
| 574 | } else { | |
| 575 | kprintf("L2 4KB unified TLB: %d entries", | |
| 576 | (regs[1] >> 16) & 0xfff); | |
| 577 | print_AMD_l2_assoc((regs[1] >> 28) & 0xf); | |
| 578 | } | |
| 579 | kprintf("L2 unified cache: %d kbytes", regs[2] >> 16); | |
| 580 | kprintf(", %d bytes/line", regs[2] & 0xff); | |
| 581 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0x0f); | |
| 582 | print_AMD_l2_assoc((regs[2] >> 12) & 0x0f); | |
| 583 | } | |
| 584 | } | |
| a2a636cc MD |
585 | |
| 586 | static void | |
| 587 | print_via_padlock_info(void) | |
| 588 | { | |
| 589 | u_int regs[4]; | |
| 590 | ||
| 591 | /* Check for supported models. */ | |
| 592 | switch (cpu_id & 0xff0) { | |
| 593 | case 0x690: | |
| 594 | if ((cpu_id & 0xf) < 3) | |
| 595 | return; | |
| 596 | case 0x6a0: | |
| 597 | case 0x6d0: | |
| 598 | case 0x6f0: | |
| 599 | break; | |
| 600 | default: | |
| 601 | return; | |
| 602 | } | |
| 603 | ||
| 604 | do_cpuid(0xc0000000, regs); | |
| 605 | if (regs[0] >= 0xc0000001) | |
| 606 | do_cpuid(0xc0000001, regs); | |
| 607 | else | |
| 608 | return; | |
| 609 | ||
| 610 | kprintf("\n VIA Padlock Features=0x%b", regs[3], | |
| 611 | "\020" | |
| 612 | "\003RNG" /* RNG */ | |
| 613 | "\007AES" /* ACE */ | |
| 614 | "\011AES-CTR" /* ACE2 */ | |
| 615 | "\013SHA1,SHA256" /* PHE */ | |
| 616 | "\015RSA" /* PMM */ | |
| 617 | ); | |
| 618 | } |