| Commit | Line | Data |
|---|---|---|
| 90e8a35b | 1 | /*- |
| bb832add | 2 | * Copyright (c) 1992 Terrence R. Lambert. |
| 90e8a35b | 3 | * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. |
| 984263bc | 4 | * Copyright (c) 1997 KATO Takenori. |
| 984263bc MD |
5 | * All rights reserved. |
| 6 | * | |
| 7 | * This code is derived from software contributed to Berkeley by | |
| 8 | * William Jolitz. | |
| 9 | * | |
| 10 | * Redistribution and use in source and binary forms, with or without | |
| 11 | * modification, are permitted provided that the following conditions | |
| 12 | * are met: | |
| 13 | * 1. Redistributions of source code must retain the above copyright | |
| 14 | * notice, this list of conditions and the following disclaimer. | |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 16 | * notice, this list of conditions and the following disclaimer in the | |
| 17 | * documentation and/or other materials provided with the distribution. | |
| 18 | * 3. All advertising materials mentioning features or use of this software | |
| 19 | * must display the following acknowledgement: | |
| 20 | * This product includes software developed by the University of | |
| 21 | * California, Berkeley and its contributors. | |
| 22 | * 4. Neither the name of the University nor the names of its contributors | |
| 23 | * may be used to endorse or promote products derived from this software | |
| 24 | * without specific prior written permission. | |
| 25 | * | |
| 26 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
| 27 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 28 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 29 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
| 30 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 31 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 32 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 33 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 34 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 35 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 36 | * SUCH DAMAGE. | |
| 37 | * | |
| 38 | * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp | |
| 90e8a35b | 39 | * $FreeBSD: src/sys/i386/i386/identcpu.c,v 1.206 2009/11/12 10:59:00 nyan |
| 984263bc | 40 | */ |
| 984263bc MD |
41 | #include "opt_cpu.h" |
| 42 | ||
| 43 | #include <sys/param.h> | |
| 44 | #include <sys/systm.h> | |
| 45 | #include <sys/kernel.h> | |
| 46 | #include <sys/sysctl.h> | |
| 11e9db57 | 47 | #include <sys/lock.h> |
| 984263bc MD |
48 | |
| 49 | #include <machine/asmacros.h> | |
| 50 | #include <machine/clock.h> | |
| 51 | #include <machine/cputypes.h> | |
| 52 | #include <machine/segments.h> | |
| 53 | #include <machine/specialreg.h> | |
| 54 | #include <machine/md_var.h> | |
| 87cf6827 | 55 | #include <machine/intr_machdep.h> |
| 984263bc MD |
56 | |
| 57 | #define IDENTBLUE_CYRIX486 0 | |
| 58 | #define IDENTBLUE_IBMCPU 1 | |
| 59 | #define IDENTBLUE_CYRIXM2 2 | |
| 60 | ||
| 61 | /* XXX - should be in header file: */ | |
| 62 | void printcpuinfo(void); | |
| 63 | void finishidentcpu(void); | |
| 90e8a35b | 64 | void earlysetcpuclass(void); |
| 984263bc MD |
65 | #if defined(I586_CPU) && defined(CPU_WT_ALLOC) |
| 66 | void enable_K5_wt_alloc(void); | |
| 67 | void enable_K6_wt_alloc(void); | |
| 68 | void enable_K6_2_wt_alloc(void); | |
| 69 | #endif | |
| 70 | void panicifcpuunsupported(void); | |
| 71 | ||
| 72 | static void identifycyrix(void); | |
| 90e8a35b AP |
73 | static void init_exthigh(void); |
| 74 | static u_int find_cpu_vendor_id(void); | |
| 984263bc | 75 | static void print_AMD_info(void); |
| 90e8a35b AP |
76 | static void print_INTEL_info(void); |
| 77 | static void print_INTEL_TLB(u_int data); | |
| 984263bc MD |
78 | static void print_AMD_assoc(int i); |
| 79 | static void print_transmeta_info(void); | |
| 7f722cda | 80 | static void print_via_padlock_info(void); |
| 984263bc | 81 | |
| 90e8a35b | 82 | int cpu_class; |
| 984263bc MD |
83 | u_int cpu_exthigh; /* Highest arg to extended CPUID */ |
| 84 | u_int cyrix_did; /* Device ID of Cyrix CPU */ | |
| a9295349 | 85 | char machine[] = MACHINE; |
| 984263bc MD |
86 | SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, |
| 87 | machine, 0, "Machine class"); | |
| 88 | ||
| 89 | static char cpu_model[128]; | |
| 90 | SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, | |
| 91 | cpu_model, 0, "Machine model"); | |
| 92 | ||
| 90e8a35b AP |
93 | static int hw_clockrate; |
| 94 | SYSCTL_INT(_hw, OID_AUTO, clockrate, CTLFLAG_RD, | |
| 95 | &hw_clockrate, 0, "CPU instruction clock rate"); | |
| 96 | ||
| 984263bc MD |
97 | static char cpu_brand[48]; |
| 98 | ||
| 90e8a35b | 99 | #define MAX_ADDITIONAL_INFO 16 |
| 20f0a2d3 MD |
100 | |
| 101 | static const char *additional_cpu_info_ary[MAX_ADDITIONAL_INFO]; | |
| 102 | static u_int additional_cpu_info_count; | |
| 103 | ||
| 90e8a35b | 104 | #define MAX_BRAND_INDEX 8 |
| 984263bc MD |
105 | |
| 106 | static const char *cpu_brandtable[MAX_BRAND_INDEX + 1] = { | |
| 107 | NULL, /* No brand */ | |
| 108 | "Intel Celeron", | |
| 109 | "Intel Pentium III", | |
| 110 | "Intel Pentium III Xeon", | |
| 90e8a35b AP |
111 | NULL, |
| 112 | NULL, | |
| 113 | NULL, | |
| 114 | NULL, | |
| 115 | "Intel Pentium 4" | |
| 984263bc MD |
116 | }; |
| 117 | ||
| 90e8a35b AP |
118 | static struct { |
| 119 | char *cpu_name; | |
| 120 | int cpu_class; | |
| 121 | } i386_cpus[] = { | |
| 984263bc MD |
122 | { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */ |
| 123 | { "i386SX", CPUCLASS_386 }, /* CPU_386SX */ | |
| 124 | { "i386DX", CPUCLASS_386 }, /* CPU_386 */ | |
| 125 | { "i486SX", CPUCLASS_486 }, /* CPU_486SX */ | |
| 126 | { "i486DX", CPUCLASS_486 }, /* CPU_486 */ | |
| 127 | { "Pentium", CPUCLASS_586 }, /* CPU_586 */ | |
| 128 | { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */ | |
| 129 | { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ | |
| 130 | { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */ | |
| 131 | { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */ | |
| 132 | { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */ | |
| 133 | { "Cyrix 6x86MX", CPUCLASS_686 }, /* CPU_M2 */ | |
| 134 | { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */ | |
| 135 | { "Cyrix 486S/DX", CPUCLASS_486 }, /* CPU_CY486DX */ | |
| 136 | { "Pentium II", CPUCLASS_686 }, /* CPU_PII */ | |
| 137 | { "Pentium III", CPUCLASS_686 }, /* CPU_PIII */ | |
| 138 | { "Pentium 4", CPUCLASS_686 }, /* CPU_P4 */ | |
| 139 | }; | |
| 140 | ||
| 90e8a35b AP |
141 | static struct { |
| 142 | char *vendor; | |
| 143 | u_int vendor_id; | |
| 144 | } cpu_vendors[] = { | |
| 145 | { INTEL_VENDOR_ID, CPU_VENDOR_INTEL }, /* GenuineIntel */ | |
| 146 | { AMD_VENDOR_ID, CPU_VENDOR_AMD }, /* AuthenticAMD */ | |
| 147 | { CENTAUR_VENDOR_ID, CPU_VENDOR_CENTAUR }, /* CentaurHauls */ | |
| 148 | { NSC_VENDOR_ID, CPU_VENDOR_NSC }, /* Geode by NSC */ | |
| 149 | { CYRIX_VENDOR_ID, CPU_VENDOR_CYRIX }, /* CyrixInstead */ | |
| 150 | { TRANSMETA_VENDOR_ID, CPU_VENDOR_TRANSMETA }, /* GenuineTMx86 */ | |
| 151 | { SIS_VENDOR_ID, CPU_VENDOR_SIS }, /* SiS SiS SiS */ | |
| 152 | { UMC_VENDOR_ID, CPU_VENDOR_UMC }, /* UMC UMC UMC */ | |
| 153 | { NEXGEN_VENDOR_ID, CPU_VENDOR_NEXGEN }, /* NexGenDriven */ | |
| 154 | { RISE_VENDOR_ID, CPU_VENDOR_RISE }, /* RiseRiseRise */ | |
| 155 | #if 0 | |
| 156 | /* XXX CPUID 8000_0000h and 8086_0000h, not 0000_0000h */ | |
| 157 | { "TransmetaCPU", CPU_VENDOR_TRANSMETA }, | |
| 158 | #endif | |
| 159 | }; | |
| 160 | ||
| 161 | int cpu_cores; | |
| 162 | int cpu_logical; | |
| 163 | ||
| 984263bc MD |
164 | #if defined(I586_CPU) && !defined(NO_F00F_HACK) |
| 165 | int has_f00f_bug = 0; /* Initialized so that it can be patched. */ | |
| 166 | #endif | |
| 167 | ||
| 90e8a35b AP |
168 | static void |
| 169 | init_exthigh(void) | |
| 170 | { | |
| 171 | static int done = 0; | |
| 172 | u_int regs[4]; | |
| 173 | ||
| 174 | if (done == 0) { | |
| 175 | if (cpu_high > 0 && | |
| 176 | (cpu_vendor_id == CPU_VENDOR_INTEL || | |
| 177 | cpu_vendor_id == CPU_VENDOR_AMD || | |
| 178 | cpu_vendor_id == CPU_VENDOR_TRANSMETA || | |
| 179 | cpu_vendor_id == CPU_VENDOR_CENTAUR || | |
| 180 | cpu_vendor_id == CPU_VENDOR_NSC)) { | |
| 181 | do_cpuid(0x80000000, regs); | |
| 182 | if (regs[0] >= 0x80000000) | |
| 183 | cpu_exthigh = regs[0]; | |
| 184 | } | |
| 185 | ||
| 186 | done = 1; | |
| 187 | } | |
| 188 | } | |
| 189 | ||
| 984263bc MD |
190 | void |
| 191 | printcpuinfo(void) | |
| 192 | { | |
| 984263bc | 193 | u_int regs[4], i; |
| 984263bc MD |
194 | char *brand; |
| 195 | ||
| 196 | cpu_class = i386_cpus[cpu].cpu_class; | |
| 26be20a0 | 197 | kprintf("CPU: "); |
| 984263bc MD |
198 | strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof (cpu_model)); |
| 199 | ||
| 984263bc | 200 | /* Check for extended CPUID information and a processor name. */ |
| 90e8a35b AP |
201 | init_exthigh(); |
| 202 | if (cpu_exthigh >= 0x80000004) { | |
| 203 | brand = cpu_brand; | |
| 204 | for (i = 0x80000002; i < 0x80000005; i++) { | |
| 205 | do_cpuid(i, regs); | |
| 206 | memcpy(brand, regs, sizeof(regs)); | |
| 207 | brand += sizeof(regs); | |
| 984263bc MD |
208 | } |
| 209 | } | |
| 210 | ||
| 90e8a35b | 211 | if (cpu_vendor_id == CPU_VENDOR_INTEL) { |
| 984263bc MD |
212 | if ((cpu_id & 0xf00) > 0x300) { |
| 213 | u_int brand_index; | |
| 214 | ||
| 215 | cpu_model[0] = '\0'; | |
| 216 | ||
| 217 | switch (cpu_id & 0x3000) { | |
| 218 | case 0x1000: | |
| 219 | strcpy(cpu_model, "Overdrive "); | |
| 220 | break; | |
| 221 | case 0x2000: | |
| 222 | strcpy(cpu_model, "Dual "); | |
| 223 | break; | |
| 224 | } | |
| 225 | ||
| 226 | switch (cpu_id & 0xf00) { | |
| 227 | case 0x400: | |
| 228 | strcat(cpu_model, "i486 "); | |
| 229 | /* Check the particular flavor of 486 */ | |
| 230 | switch (cpu_id & 0xf0) { | |
| 231 | case 0x00: | |
| 232 | case 0x10: | |
| 233 | strcat(cpu_model, "DX"); | |
| 234 | break; | |
| 235 | case 0x20: | |
| 236 | strcat(cpu_model, "SX"); | |
| 237 | break; | |
| 238 | case 0x30: | |
| 239 | strcat(cpu_model, "DX2"); | |
| 240 | break; | |
| 241 | case 0x40: | |
| 242 | strcat(cpu_model, "SL"); | |
| 243 | break; | |
| 244 | case 0x50: | |
| 245 | strcat(cpu_model, "SX2"); | |
| 246 | break; | |
| 247 | case 0x70: | |
| 248 | strcat(cpu_model, | |
| 249 | "DX2 Write-Back Enhanced"); | |
| 250 | break; | |
| 251 | case 0x80: | |
| 252 | strcat(cpu_model, "DX4"); | |
| 253 | break; | |
| 254 | } | |
| 255 | break; | |
| 256 | case 0x500: | |
| 257 | /* Check the particular flavor of 586 */ | |
| 258 | strcat(cpu_model, "Pentium"); | |
| 259 | switch (cpu_id & 0xf0) { | |
| 260 | case 0x00: | |
| 261 | strcat(cpu_model, " A-step"); | |
| 262 | break; | |
| 263 | case 0x10: | |
| 264 | strcat(cpu_model, "/P5"); | |
| 265 | break; | |
| 266 | case 0x20: | |
| 267 | strcat(cpu_model, "/P54C"); | |
| 268 | break; | |
| 269 | case 0x30: | |
| 90e8a35b | 270 | strcat(cpu_model, "/P24T"); |
| 984263bc MD |
271 | break; |
| 272 | case 0x40: | |
| 273 | strcat(cpu_model, "/P55C"); | |
| 274 | break; | |
| 275 | case 0x70: | |
| 276 | strcat(cpu_model, "/P54C"); | |
| 277 | break; | |
| 278 | case 0x80: | |
| 279 | strcat(cpu_model, "/P55C (quarter-micron)"); | |
| 280 | break; | |
| 281 | default: | |
| 282 | /* nothing */ | |
| 283 | break; | |
| 284 | } | |
| 285 | #if defined(I586_CPU) && !defined(NO_F00F_HACK) | |
| 286 | /* | |
| 287 | * XXX - If/when Intel fixes the bug, this | |
| 288 | * should also check the version of the | |
| 289 | * CPU, not just that it's a Pentium. | |
| 290 | */ | |
| 291 | has_f00f_bug = 1; | |
| 292 | #endif | |
| 293 | break; | |
| 294 | case 0x600: | |
| 295 | /* Check the particular flavor of 686 */ | |
| 296 | switch (cpu_id & 0xf0) { | |
| 297 | case 0x00: | |
| 298 | strcat(cpu_model, "Pentium Pro A-step"); | |
| 299 | break; | |
| 300 | case 0x10: | |
| 301 | strcat(cpu_model, "Pentium Pro"); | |
| 302 | break; | |
| 303 | case 0x30: | |
| 304 | case 0x50: | |
| 305 | case 0x60: | |
| 306 | strcat(cpu_model, | |
| 307 | "Pentium II/Pentium II Xeon/Celeron"); | |
| 308 | cpu = CPU_PII; | |
| 309 | break; | |
| 310 | case 0x70: | |
| 311 | case 0x80: | |
| 312 | case 0xa0: | |
| 313 | case 0xb0: | |
| 314 | strcat(cpu_model, | |
| 315 | "Pentium III/Pentium III Xeon/Celeron"); | |
| 316 | cpu = CPU_PIII; | |
| 317 | break; | |
| 318 | default: | |
| 319 | strcat(cpu_model, "Unknown 80686"); | |
| 320 | break; | |
| 321 | } | |
| 322 | break; | |
| 323 | case 0xf00: | |
| 324 | strcat(cpu_model, "Pentium 4"); | |
| 325 | cpu = CPU_P4; | |
| 326 | break; | |
| 327 | default: | |
| 328 | strcat(cpu_model, "unknown"); | |
| 329 | break; | |
| 330 | } | |
| 331 | ||
| 332 | /* | |
| 333 | * If we didn't get a brand name from the extended | |
| 334 | * CPUID, try to look it up in the brand table. | |
| 335 | */ | |
| 336 | if (cpu_high > 0 && *cpu_brand == '\0') { | |
| 337 | brand_index = cpu_procinfo & CPUID_BRAND_INDEX; | |
| 338 | if (brand_index <= MAX_BRAND_INDEX && | |
| 339 | cpu_brandtable[brand_index] != NULL) | |
| 340 | strcpy(cpu_brand, | |
| 341 | cpu_brandtable[brand_index]); | |
| 342 | } | |
| 343 | } | |
| 90e8a35b | 344 | } else if (cpu_vendor_id == CPU_VENDOR_AMD) { |
| 984263bc MD |
345 | /* |
| 346 | * Values taken from AMD Processor Recognition | |
| 347 | * http://www.amd.com/K6/k6docs/pdf/20734g.pdf | |
| 348 | * (also describes ``Features'' encodings. | |
| 349 | */ | |
| 350 | strcpy(cpu_model, "AMD "); | |
| 351 | switch (cpu_id & 0xFF0) { | |
| 352 | case 0x410: | |
| 353 | strcat(cpu_model, "Standard Am486DX"); | |
| 354 | break; | |
| 355 | case 0x430: | |
| 356 | strcat(cpu_model, "Enhanced Am486DX2 Write-Through"); | |
| 357 | break; | |
| 358 | case 0x470: | |
| 359 | strcat(cpu_model, "Enhanced Am486DX2 Write-Back"); | |
| 360 | break; | |
| 361 | case 0x480: | |
| 362 | strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Through"); | |
| 363 | break; | |
| 364 | case 0x490: | |
| 365 | strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Back"); | |
| 366 | break; | |
| 367 | case 0x4E0: | |
| 368 | strcat(cpu_model, "Am5x86 Write-Through"); | |
| 369 | break; | |
| 370 | case 0x4F0: | |
| 371 | strcat(cpu_model, "Am5x86 Write-Back"); | |
| 372 | break; | |
| 373 | case 0x500: | |
| 374 | strcat(cpu_model, "K5 model 0"); | |
| 375 | tsc_is_broken = 1; | |
| 376 | break; | |
| 377 | case 0x510: | |
| 378 | strcat(cpu_model, "K5 model 1"); | |
| 379 | break; | |
| 380 | case 0x520: | |
| 381 | strcat(cpu_model, "K5 PR166 (model 2)"); | |
| 382 | break; | |
| 383 | case 0x530: | |
| 384 | strcat(cpu_model, "K5 PR200 (model 3)"); | |
| 385 | break; | |
| 386 | case 0x560: | |
| 387 | strcat(cpu_model, "K6"); | |
| 388 | break; | |
| 389 | case 0x570: | |
| 390 | strcat(cpu_model, "K6 266 (model 1)"); | |
| 391 | break; | |
| 392 | case 0x580: | |
| 393 | strcat(cpu_model, "K6-2"); | |
| 394 | break; | |
| 395 | case 0x590: | |
| 396 | strcat(cpu_model, "K6-III"); | |
| 397 | break; | |
| 92632b4a AH |
398 | case 0x5a0: |
| 399 | strcat(cpu_model, "Geode LX"); | |
| 400 | /* | |
| 401 | * Make sure the TSC runs through suspension, | |
| 90e8a35b | 402 | * otherwise we can't use it as timecounter |
| 92632b4a AH |
403 | */ |
| 404 | wrmsr(0x1900, rdmsr(0x1900) | 0x20ULL); | |
| 405 | break; | |
| 984263bc MD |
406 | default: |
| 407 | strcat(cpu_model, "Unknown"); | |
| 408 | break; | |
| 409 | } | |
| 410 | #if defined(I586_CPU) && defined(CPU_WT_ALLOC) | |
| 411 | if ((cpu_id & 0xf00) == 0x500) { | |
| 412 | if (((cpu_id & 0x0f0) > 0) | |
| 413 | && ((cpu_id & 0x0f0) < 0x60) | |
| 414 | && ((cpu_id & 0x00f) > 3)) | |
| 415 | enable_K5_wt_alloc(); | |
| 416 | else if (((cpu_id & 0x0f0) > 0x80) | |
| 417 | || (((cpu_id & 0x0f0) == 0x80) | |
| 418 | && (cpu_id & 0x00f) > 0x07)) | |
| 419 | enable_K6_2_wt_alloc(); | |
| 420 | else if ((cpu_id & 0x0f0) > 0x50) | |
| 421 | enable_K6_wt_alloc(); | |
| 422 | } | |
| 423 | #endif | |
| 90e8a35b | 424 | } else if (cpu_vendor_id == CPU_VENDOR_CYRIX) { |
| 984263bc MD |
425 | strcpy(cpu_model, "Cyrix "); |
| 426 | switch (cpu_id & 0xff0) { | |
| 427 | case 0x440: | |
| 428 | strcat(cpu_model, "MediaGX"); | |
| 429 | break; | |
| 430 | case 0x520: | |
| 431 | strcat(cpu_model, "6x86"); | |
| 432 | break; | |
| 433 | case 0x540: | |
| 434 | cpu_class = CPUCLASS_586; | |
| 435 | strcat(cpu_model, "GXm"); | |
| 436 | break; | |
| 437 | case 0x600: | |
| 438 | strcat(cpu_model, "6x86MX"); | |
| 439 | break; | |
| 440 | default: | |
| 441 | /* | |
| 442 | * Even though CPU supports the cpuid | |
| 443 | * instruction, it can be disabled. | |
| 444 | * Therefore, this routine supports all Cyrix | |
| 445 | * CPUs. | |
| 446 | */ | |
| 447 | switch (cyrix_did & 0xf0) { | |
| 448 | case 0x00: | |
| 449 | switch (cyrix_did & 0x0f) { | |
| 450 | case 0x00: | |
| 451 | strcat(cpu_model, "486SLC"); | |
| 452 | break; | |
| 453 | case 0x01: | |
| 454 | strcat(cpu_model, "486DLC"); | |
| 455 | break; | |
| 456 | case 0x02: | |
| 457 | strcat(cpu_model, "486SLC2"); | |
| 458 | break; | |
| 459 | case 0x03: | |
| 460 | strcat(cpu_model, "486DLC2"); | |
| 461 | break; | |
| 462 | case 0x04: | |
| 463 | strcat(cpu_model, "486SRx"); | |
| 464 | break; | |
| 465 | case 0x05: | |
| 466 | strcat(cpu_model, "486DRx"); | |
| 467 | break; | |
| 468 | case 0x06: | |
| 469 | strcat(cpu_model, "486SRx2"); | |
| 470 | break; | |
| 471 | case 0x07: | |
| 472 | strcat(cpu_model, "486DRx2"); | |
| 473 | break; | |
| 474 | case 0x08: | |
| 475 | strcat(cpu_model, "486SRu"); | |
| 476 | break; | |
| 477 | case 0x09: | |
| 478 | strcat(cpu_model, "486DRu"); | |
| 479 | break; | |
| 480 | case 0x0a: | |
| 481 | strcat(cpu_model, "486SRu2"); | |
| 482 | break; | |
| 483 | case 0x0b: | |
| 484 | strcat(cpu_model, "486DRu2"); | |
| 485 | break; | |
| 486 | default: | |
| 487 | strcat(cpu_model, "Unknown"); | |
| 488 | break; | |
| 489 | } | |
| 490 | break; | |
| 491 | case 0x10: | |
| 492 | switch (cyrix_did & 0x0f) { | |
| 493 | case 0x00: | |
| 494 | strcat(cpu_model, "486S"); | |
| 495 | break; | |
| 496 | case 0x01: | |
| 497 | strcat(cpu_model, "486S2"); | |
| 498 | break; | |
| 499 | case 0x02: | |
| 500 | strcat(cpu_model, "486Se"); | |
| 501 | break; | |
| 502 | case 0x03: | |
| 503 | strcat(cpu_model, "486S2e"); | |
| 504 | break; | |
| 505 | case 0x0a: | |
| 506 | strcat(cpu_model, "486DX"); | |
| 507 | break; | |
| 508 | case 0x0b: | |
| 509 | strcat(cpu_model, "486DX2"); | |
| 510 | break; | |
| 511 | case 0x0f: | |
| 512 | strcat(cpu_model, "486DX4"); | |
| 513 | break; | |
| 514 | default: | |
| 515 | strcat(cpu_model, "Unknown"); | |
| 516 | break; | |
| 517 | } | |
| 518 | break; | |
| 519 | case 0x20: | |
| 520 | if ((cyrix_did & 0x0f) < 8) | |
| 521 | strcat(cpu_model, "6x86"); /* Where did you get it? */ | |
| 522 | else | |
| 523 | strcat(cpu_model, "5x86"); | |
| 524 | break; | |
| 525 | case 0x30: | |
| 526 | strcat(cpu_model, "6x86"); | |
| 527 | break; | |
| 528 | case 0x40: | |
| 529 | if ((cyrix_did & 0xf000) == 0x3000) { | |
| 530 | cpu_class = CPUCLASS_586; | |
| 531 | strcat(cpu_model, "GXm"); | |
| 532 | } else | |
| 533 | strcat(cpu_model, "MediaGX"); | |
| 534 | break; | |
| 535 | case 0x50: | |
| 536 | strcat(cpu_model, "6x86MX"); | |
| 537 | break; | |
| 538 | case 0xf0: | |
| 539 | switch (cyrix_did & 0x0f) { | |
| 540 | case 0x0d: | |
| 541 | strcat(cpu_model, "Overdrive CPU"); | |
| 12afb922 | 542 | break; |
| 984263bc MD |
543 | case 0x0e: |
| 544 | strcpy(cpu_model, "Texas Instruments 486SXL"); | |
| 545 | break; | |
| 546 | case 0x0f: | |
| 547 | strcat(cpu_model, "486SLC/DLC"); | |
| 548 | break; | |
| 549 | default: | |
| 550 | strcat(cpu_model, "Unknown"); | |
| 551 | break; | |
| 552 | } | |
| 553 | break; | |
| 554 | default: | |
| 555 | strcat(cpu_model, "Unknown"); | |
| 556 | break; | |
| 557 | } | |
| 558 | break; | |
| 559 | } | |
| 90e8a35b | 560 | } else if (cpu_vendor_id == CPU_VENDOR_RISE) { |
| 984263bc MD |
561 | strcpy(cpu_model, "Rise "); |
| 562 | switch (cpu_id & 0xff0) { | |
| 563 | case 0x500: | |
| 564 | strcat(cpu_model, "mP6"); | |
| 565 | break; | |
| 566 | default: | |
| 567 | strcat(cpu_model, "Unknown"); | |
| 568 | } | |
| 90e8a35b | 569 | } else if (cpu_vendor_id == CPU_VENDOR_CENTAUR) { |
| 984263bc MD |
570 | switch (cpu_id & 0xff0) { |
| 571 | case 0x540: | |
| 572 | strcpy(cpu_model, "IDT WinChip C6"); | |
| 573 | tsc_is_broken = 1; | |
| 574 | break; | |
| 575 | case 0x580: | |
| 576 | strcpy(cpu_model, "IDT WinChip 2"); | |
| 577 | break; | |
| 3a473633 MD |
578 | case 0x660: |
| 579 | strcpy(cpu_model, "VIA C3 Samuel"); | |
| 580 | break; | |
| 984263bc | 581 | case 0x670: |
| 3a473633 MD |
582 | if (cpu_id & 0x8) |
| 583 | strcpy(cpu_model, "VIA C3 Ezra"); | |
| 584 | else | |
| 585 | strcpy(cpu_model, "VIA C3 Samuel 2"); | |
| 586 | break; | |
| 587 | case 0x680: | |
| 588 | strcpy(cpu_model, "VIA C3 Ezra-T"); | |
| 589 | break; | |
| 590 | case 0x690: | |
| 591 | strcpy(cpu_model, "VIA C3 Nehemiah"); | |
| 7f722cda TN |
592 | break; |
| 593 | case 0x6a0: | |
| 594 | case 0x6d0: | |
| 595 | strcpy(cpu_model, "VIA C7 Esther"); | |
| 984263bc | 596 | break; |
| 9107d534 TN |
597 | case 0x6f0: |
| 598 | strcpy(cpu_model, "VIA Nano"); | |
| 599 | break; | |
| 984263bc MD |
600 | default: |
| 601 | strcpy(cpu_model, "VIA/IDT Unknown"); | |
| 602 | } | |
| 90e8a35b | 603 | } else if (cpu_vendor_id == CPU_VENDOR_IBM) { |
| 984263bc | 604 | strcpy(cpu_model, "Blue Lightning CPU"); |
| 90e8a35b AP |
605 | } else if (cpu_vendor_id == CPU_VENDOR_NSC) { |
| 606 | switch (cpu_id & 0xfff) { | |
| 607 | case 0x540: | |
| 608 | strcpy(cpu_model, "Geode SC1100"); | |
| 609 | cpu = CPU_GEODE1100; | |
| 610 | tsc_is_broken = 1; | |
| 611 | break; | |
| 612 | default: | |
| 613 | strcpy(cpu_model, "Geode/NSC unknown"); | |
| 614 | break; | |
| 615 | } | |
| 984263bc MD |
616 | } |
| 617 | ||
| 618 | /* | |
| 619 | * Replace cpu_model with cpu_brand minus leading spaces if | |
| 620 | * we have one. | |
| 621 | */ | |
| 622 | brand = cpu_brand; | |
| 623 | while (*brand == ' ') | |
| 624 | ++brand; | |
| 625 | if (*brand != '\0') | |
| 626 | strcpy(cpu_model, brand); | |
| 627 | ||
| 26be20a0 | 628 | kprintf("%s (", cpu_model); |
| 984263bc MD |
629 | switch(cpu_class) { |
| 630 | case CPUCLASS_286: | |
| 26be20a0 | 631 | kprintf("286"); |
| 984263bc | 632 | break; |
| 984263bc | 633 | case CPUCLASS_386: |
| 26be20a0 | 634 | kprintf("386"); |
| 984263bc | 635 | break; |
| 984263bc MD |
636 | #if defined(I486_CPU) |
| 637 | case CPUCLASS_486: | |
| 26be20a0 | 638 | kprintf("486"); |
| 90e8a35b | 639 | /* bzero_vector = i486_bzero; */ |
| 984263bc MD |
640 | break; |
| 641 | #endif | |
| 642 | #if defined(I586_CPU) | |
| 643 | case CPUCLASS_586: | |
| 90e8a35b AP |
644 | hw_clockrate = (tsc_frequency + 5000) / 1000000; |
| 645 | kprintf("%jd.%02d-MHz ", | |
| 646 | (intmax_t)(tsc_frequency + 4999) / 1000000, | |
| 647 | (u_int)((tsc_frequency + 4999) / 10000) % 100); | |
| 26be20a0 | 648 | kprintf("586"); |
| 984263bc MD |
649 | break; |
| 650 | #endif | |
| 651 | #if defined(I686_CPU) | |
| 652 | case CPUCLASS_686: | |
| 90e8a35b AP |
653 | hw_clockrate = (tsc_frequency + 5000) / 1000000; |
| 654 | kprintf("%jd.%02d-MHz ", | |
| 655 | (intmax_t)(tsc_frequency + 4999) / 1000000, | |
| 656 | (u_int)((tsc_frequency + 4999) / 10000) % 100); | |
| 26be20a0 | 657 | kprintf("686"); |
| 984263bc MD |
658 | break; |
| 659 | #endif | |
| 660 | default: | |
| 26be20a0 | 661 | kprintf("Unknown"); /* will panic below... */ |
| 984263bc | 662 | } |
| 26be20a0 | 663 | kprintf("-class CPU)\n"); |
| 984263bc | 664 | if(*cpu_vendor) |
| 26be20a0 | 665 | kprintf(" Origin = \"%s\"",cpu_vendor); |
| 984263bc | 666 | if(cpu_id) |
| 26be20a0 | 667 | kprintf(" Id = 0x%x", cpu_id); |
| 984263bc | 668 | |
| 90e8a35b AP |
669 | if (cpu_vendor_id == CPU_VENDOR_INTEL || |
| 670 | cpu_vendor_id == CPU_VENDOR_AMD || | |
| 671 | cpu_vendor_id == CPU_VENDOR_TRANSMETA || | |
| 672 | cpu_vendor_id == CPU_VENDOR_RISE || | |
| 673 | cpu_vendor_id == CPU_VENDOR_CENTAUR || | |
| 674 | cpu_vendor_id == CPU_VENDOR_NSC || | |
| 675 | (cpu_vendor_id == CPU_VENDOR_CYRIX && | |
| 984263bc | 676 | ((cpu_id & 0xf00) > 0x500))) { |
| 26be20a0 | 677 | kprintf(" Stepping = %u", cpu_id & 0xf); |
| 90e8a35b | 678 | if (cpu_vendor_id == CPU_VENDOR_CYRIX) |
| 26be20a0 | 679 | kprintf(" DIR=0x%04x", cyrix_did); |
| 984263bc | 680 | if (cpu_high > 0) { |
| 90e8a35b AP |
681 | u_int cmp = 1, htt = 1; |
| 682 | ||
| 984263bc MD |
683 | /* |
| 684 | * Here we should probably set up flags indicating | |
| 685 | * whether or not various features are available. | |
| 686 | * The interesting ones are probably VME, PSE, PAE, | |
| 687 | * and PGE. The code already assumes without bothering | |
| 688 | * to check that all CPUs >= Pentium have a TSC and | |
| 689 | * MSRs. | |
| 690 | */ | |
| 26be20a0 | 691 | kprintf("\n Features=0x%b", cpu_feature, |
| 984263bc MD |
692 | "\020" |
| 693 | "\001FPU" /* Integral FPU */ | |
| 694 | "\002VME" /* Extended VM86 mode support */ | |
| 695 | "\003DE" /* Debugging Extensions (CR4.DE) */ | |
| 696 | "\004PSE" /* 4MByte page tables */ | |
| 697 | "\005TSC" /* Timestamp counter */ | |
| 698 | "\006MSR" /* Machine specific registers */ | |
| 699 | "\007PAE" /* Physical address extension */ | |
| 700 | "\010MCE" /* Machine Check support */ | |
| 701 | "\011CX8" /* CMPEXCH8 instruction */ | |
| 702 | "\012APIC" /* SMP local APIC */ | |
| 703 | "\013oldMTRR" /* Previous implementation of MTRR */ | |
| 704 | "\014SEP" /* Fast System Call */ | |
| 705 | "\015MTRR" /* Memory Type Range Registers */ | |
| 706 | "\016PGE" /* PG_G (global bit) support */ | |
| 707 | "\017MCA" /* Machine Check Architecture */ | |
| 708 | "\020CMOV" /* CMOV instruction */ | |
| 709 | "\021PAT" /* Page attributes table */ | |
| 710 | "\022PSE36" /* 36 bit address space support */ | |
| 711 | "\023PN" /* Processor Serial number */ | |
| 712 | "\024CLFLUSH" /* Has the CLFLUSH instruction */ | |
| 713 | "\025<b20>" | |
| 714 | "\026DTS" /* Debug Trace Store */ | |
| 715 | "\027ACPI" /* ACPI support */ | |
| 716 | "\030MMX" /* MMX instructions */ | |
| 717 | "\031FXSR" /* FXSAVE/FXRSTOR */ | |
| 718 | "\032SSE" /* Streaming SIMD Extensions */ | |
| 719 | "\033SSE2" /* Streaming SIMD Extensions #2 */ | |
| 720 | "\034SS" /* Self snoop */ | |
| 721 | "\035HTT" /* Hyperthreading (see EBX bit 16-23) */ | |
| 722 | "\036TM" /* Thermal Monitor clock slowdown */ | |
| 723 | "\037IA64" /* CPU can execute IA64 instructions */ | |
| 724 | "\040PBE" /* Pending Break Enable */ | |
| 725 | ); | |
| 726 | ||
| 97ee3efc | 727 | if (cpu_feature2 != 0) { |
| e6164301 | 728 | kprintf("\n Features2=0x%b", cpu_feature2, |
| 97ee3efc TS |
729 | "\020" |
| 730 | "\001SSE3" /* SSE3 */ | |
| ef4da631 | 731 | "\002PCLMULQDQ" /* Carry-Less Mul Quadword */ |
| 9e3d0133 | 732 | "\003DTES64" /* 64-bit Debug Trace */ |
| 97ee3efc TS |
733 | "\004MON" /* MONITOR/MWAIT Instructions */ |
| 734 | "\005DS_CPL" /* CPL Qualified Debug Store */ | |
| 735 | "\006VMX" /* Virtual Machine Extensions */ | |
| 9e3d0133 | 736 | "\007SMX" /* Safer Mode Extensions */ |
| 97ee3efc TS |
737 | "\010EST" /* Enhanced SpeedStep */ |
| 738 | "\011TM2" /* Thermal Monitor 2 */ | |
| 9e3d0133 SW |
739 | "\012SSSE3" /* SSSE3 */ |
| 740 | "\013CNXT-ID" /* L1 context ID available */ | |
| 97ee3efc TS |
741 | "\014<b11>" |
| 742 | "\015<b12>" | |
| 743 | "\016CX16" /* CMPXCHG16B Instruction */ | |
| 9e3d0133 SW |
744 | "\017xTPR" /* Send Task Priority Messages*/ |
| 745 | "\020PDCM" /* Perf/Debug Capability MSR */ | |
| 97ee3efc TS |
746 | "\021<b16>" |
| 747 | "\022<b17>" | |
| 9e3d0133 SW |
748 | "\023DCA" /* Direct Cache Access */ |
| 749 | "\024SSE4.1" | |
| 750 | "\025SSE4.2" | |
| 751 | "\026x2APIC" /* xAPIC Extensions */ | |
| 9ea9a016 | 752 | "\027MOVBE" /* MOVBE Instruction */ |
| 9e3d0133 | 753 | "\030POPCNT" |
| 97ee3efc | 754 | "\031<b24>" |
| ef4da631 | 755 | "\032AESNI" /* AES Crypto*/ |
| 9e3d0133 SW |
756 | "\033XSAVE" |
| 757 | "\034OSXSAVE" | |
| 97ee3efc TS |
758 | "\035<b28>" |
| 759 | "\036<b29>" | |
| 760 | "\037<b30>" | |
| 9ea9a016 | 761 | "\040VMM" /* Running on a hypervisor */ |
| 97ee3efc TS |
762 | ); |
| 763 | } | |
| 764 | ||
| 90e8a35b AP |
765 | /* |
| 766 | * AMD64 Architecture Programmer's Manual Volume 3: | |
| 767 | * General-Purpose and System Instructions | |
| 768 | * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/24594.pdf | |
| 769 | * | |
| 770 | * IA-32 Intel Architecture Software Developer's Manual, | |
| 771 | * Volume 2A: Instruction Set Reference, A-M | |
| 772 | * ftp://download.intel.com/design/Pentium4/manuals/25366617.pdf | |
| 773 | */ | |
| 774 | if (amd_feature != 0) { | |
| 775 | kprintf("\n AMD Features=0x%b", amd_feature, | |
| 776 | "\020" /* in hex */ | |
| 777 | "\001<s0>" /* Same */ | |
| 778 | "\002<s1>" /* Same */ | |
| 779 | "\003<s2>" /* Same */ | |
| 780 | "\004<s3>" /* Same */ | |
| 781 | "\005<s4>" /* Same */ | |
| 782 | "\006<s5>" /* Same */ | |
| 783 | "\007<s6>" /* Same */ | |
| 784 | "\010<s7>" /* Same */ | |
| 785 | "\011<s8>" /* Same */ | |
| 786 | "\012<s9>" /* Same */ | |
| 787 | "\013<b10>" /* Undefined */ | |
| 788 | "\014SYSCALL" /* Have SYSCALL/SYSRET */ | |
| 789 | "\015<s12>" /* Same */ | |
| 790 | "\016<s13>" /* Same */ | |
| 791 | "\017<s14>" /* Same */ | |
| 792 | "\020<s15>" /* Same */ | |
| 793 | "\021<s16>" /* Same */ | |
| 794 | "\022<s17>" /* Same */ | |
| 795 | "\023<b18>" /* Reserved, unknown */ | |
| 796 | "\024MP" /* Multiprocessor Capable */ | |
| 797 | "\025NX" /* Has EFER.NXE, NX */ | |
| 798 | "\026<b21>" /* Undefined */ | |
| 799 | "\027MMX+" /* AMD MMX Extensions */ | |
| 800 | "\030<s23>" /* Same */ | |
| 801 | "\031<s24>" /* Same */ | |
| 802 | "\032FFXSR" /* Fast FXSAVE/FXRSTOR */ | |
| 803 | "\033Page1GB" /* 1-GB large page support */ | |
| 804 | "\034RDTSCP" /* RDTSCP */ | |
| 805 | "\035<b28>" /* Undefined */ | |
| 806 | "\036LM" /* 64 bit long mode */ | |
| 807 | "\0373DNow!+" /* AMD 3DNow! Extensions */ | |
| 808 | "\0403DNow!" /* AMD 3DNow! */ | |
| 809 | ); | |
| 810 | } | |
| 811 | ||
| 812 | if (amd_feature2 != 0) { | |
| 813 | kprintf("\n AMD Features2=0x%b", amd_feature2, | |
| 814 | "\020" | |
| 815 | "\001LAHF" /* LAHF/SAHF in long mode */ | |
| 816 | "\002CMP" /* CMP legacy */ | |
| 817 | "\003SVM" /* Secure Virtual Mode */ | |
| 818 | "\004ExtAPIC" /* Extended APIC register */ | |
| 819 | "\005CR8" /* CR8 in legacy mode */ | |
| 820 | "\006ABM" /* LZCNT instruction */ | |
| 821 | "\007SSE4A" /* SSE4A */ | |
| 822 | "\010MAS" /* Misaligned SSE mode */ | |
| 823 | "\011Prefetch" /* 3DNow! Prefetch/PrefetchW */ | |
| 824 | "\012OSVW" /* OS visible workaround */ | |
| 825 | "\013IBS" /* Instruction based sampling */ | |
| 826 | "\014SSE5" /* SSE5 */ | |
| 827 | "\015SKINIT" /* SKINIT/STGI */ | |
| 828 | "\016WDT" /* Watchdog timer */ | |
| 829 | "\017<b14>" | |
| 830 | "\020<b15>" | |
| 831 | "\021<b16>" | |
| 832 | "\022<b17>" | |
| 833 | "\023<b18>" | |
| 834 | "\024<b19>" | |
| 835 | "\025<b20>" | |
| 836 | "\026<b21>" | |
| 837 | "\027<b22>" | |
| 838 | "\030<b23>" | |
| 839 | "\031<b24>" | |
| 840 | "\032<b25>" | |
| 841 | "\033<b26>" | |
| 842 | "\034<b27>" | |
| 843 | "\035<b28>" | |
| 844 | "\036<b29>" | |
| 845 | "\037<b30>" | |
| 846 | "\040<b31>" | |
| 847 | ); | |
| 848 | } | |
| 849 | ||
| 850 | if (cpu_vendor_id == CPU_VENDOR_CENTAUR) | |
| ca6dce84 SW |
851 | print_via_padlock_info(); |
| 852 | ||
| 90e8a35b AP |
853 | if ((cpu_feature & CPUID_HTT) && |
| 854 | cpu_vendor_id == CPU_VENDOR_AMD) | |
| 855 | cpu_feature &= ~CPUID_HTT; | |
| 856 | ||
| 857 | /* | |
| 858 | * If this CPU supports HTT or CMP then mention the | |
| 859 | * number of physical/logical cores it contains. | |
| 860 | */ | |
| 861 | if (cpu_feature & CPUID_HTT) | |
| 862 | htt = (cpu_procinfo & CPUID_HTT_CORES) >> 16; | |
| 863 | if (cpu_vendor_id == CPU_VENDOR_AMD && | |
| 864 | (amd_feature2 & AMDID2_CMP)) | |
| 865 | cmp = (cpu_procinfo2 & AMDID_CMP_CORES) + 1; | |
| 866 | else if (cpu_vendor_id == CPU_VENDOR_INTEL && | |
| 867 | (cpu_high >= 4)) { | |
| 868 | cpuid_count(4, 0, regs); | |
| 869 | if ((regs[0] & 0x1f) != 0) | |
| 870 | cmp = ((regs[0] >> 26) & 0x3f) + 1; | |
| 871 | } | |
| 872 | cpu_cores = cmp; | |
| 873 | cpu_logical = htt / cmp; | |
| 874 | if (cmp > 1) | |
| 875 | kprintf("\n Cores per package: %d", cmp); | |
| 876 | if ((htt / cmp) > 1) | |
| 877 | kprintf("\n Logical CPUs per core: %d", | |
| 878 | cpu_logical); | |
| 879 | #if 0 | |
| 984263bc | 880 | /* |
| 90e8a35b AP |
881 | * If this CPU supports P-state invariant TSC then |
| 882 | * mention the capability. | |
| 984263bc | 883 | */ |
| 90e8a35b AP |
884 | switch (cpu_vendor_id) { |
| 885 | case CPU_VENDOR_AMD: | |
| 886 | if ((amd_pminfo & AMDPM_TSC_INVARIANT) || | |
| 887 | CPUID_TO_FAMILY(cpu_id) >= 0x10 || | |
| 888 | cpu_id == 0x60fb2) | |
| 889 | tsc_is_invariant = 1; | |
| 890 | break; | |
| 891 | case CPU_VENDOR_INTEL: | |
| 892 | if ((amd_pminfo & AMDPM_TSC_INVARIANT) || | |
| 893 | (CPUID_TO_FAMILY(cpu_id) == 0x6 && | |
| 894 | CPUID_TO_MODEL(cpu_id) >= 0xe) || | |
| 895 | (CPUID_TO_FAMILY(cpu_id) == 0xf && | |
| 896 | CPUID_TO_MODEL(cpu_id) >= 0x3)) | |
| 897 | tsc_is_invariant = 1; | |
| 898 | break; | |
| 899 | case CPU_VENDOR_CENTAUR: | |
| 900 | if (CPUID_TO_FAMILY(cpu_id) == 0x6 && | |
| 901 | CPUID_TO_MODEL(cpu_id) >= 0xf && | |
| 902 | (rdmsr(0x1203) & 0x100000000ULL) == 0) | |
| 903 | tsc_is_invariant = 1; | |
| 904 | break; | |
| 905 | } | |
| 906 | if (tsc_is_invariant) | |
| 907 | kprintf("\n TSC: P-state invariant"); | |
| 908 | #endif | |
| 909 | ||
| 984263bc | 910 | } |
| 90e8a35b | 911 | } else if (cpu_vendor_id == CPU_VENDOR_CYRIX) { |
| 26be20a0 SW |
912 | kprintf(" DIR=0x%04x", cyrix_did); |
| 913 | kprintf(" Stepping=%u", (cyrix_did & 0xf000) >> 12); | |
| 914 | kprintf(" Revision=%u", (cyrix_did & 0x0f00) >> 8); | |
| 984263bc MD |
915 | #ifndef CYRIX_CACHE_REALLY_WORKS |
| 916 | if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700) | |
| 26be20a0 | 917 | kprintf("\n CPU cache: write-through mode"); |
| 984263bc MD |
918 | #endif |
| 919 | } | |
| 90e8a35b | 920 | |
| 984263bc MD |
921 | /* Avoid ugly blank lines: only print newline when we have to. */ |
| 922 | if (*cpu_vendor || cpu_id) | |
| 26be20a0 | 923 | kprintf("\n"); |
| 984263bc | 924 | |
| 20f0a2d3 | 925 | for (i = 0; i < additional_cpu_info_count; ++i) { |
| 26be20a0 | 926 | kprintf(" %s\n", additional_cpu_info_ary[i]); |
| 90e8a35b | 927 | } |
| 20f0a2d3 | 928 | |
| 984263bc MD |
929 | if (!bootverbose) |
| 930 | return; | |
| 931 | ||
| 90e8a35b | 932 | if (cpu_vendor_id == CPU_VENDOR_AMD) |
| 984263bc | 933 | print_AMD_info(); |
| 90e8a35b AP |
934 | else if (cpu_vendor_id == CPU_VENDOR_INTEL) |
| 935 | print_INTEL_info(); | |
| 936 | else if (cpu_vendor_id == CPU_VENDOR_TRANSMETA) | |
| 984263bc | 937 | print_transmeta_info(); |
| cbc5d70e SZ |
938 | |
| 939 | #ifdef CPU_HAS_SSE2 | |
| 940 | kprintf("Use SSE2 (lfence, mfence)\n"); | |
| 941 | #endif | |
| 942 | #ifdef CPU_HAS_FXSR | |
| 943 | kprintf("Use FXSR (sfence)\n"); | |
| 944 | #endif | |
| 984263bc MD |
945 | } |
| 946 | ||
| 947 | void | |
| 948 | panicifcpuunsupported(void) | |
| 949 | { | |
| 950 | ||
| 90e8a35b | 951 | #if !defined(lint) |
| 4db955e1 | 952 | #if !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU) |
| 984263bc MD |
953 | #error This kernel is not configured for one of the supported CPUs |
| 954 | #endif | |
| 90e8a35b AP |
955 | #else /* lint */ |
| 956 | #endif /* lint */ | |
| 984263bc MD |
957 | /* |
| 958 | * Now that we have told the user what they have, | |
| 959 | * let them know if that machine type isn't configured. | |
| 960 | */ | |
| 961 | switch (cpu_class) { | |
| 90e8a35b | 962 | case CPUCLASS_286: /* a 286 should not make it this far, anyway */ |
| 984263bc | 963 | case CPUCLASS_386: |
| 984263bc MD |
964 | #if !defined(I486_CPU) |
| 965 | case CPUCLASS_486: | |
| 966 | #endif | |
| 967 | #if !defined(I586_CPU) | |
| 968 | case CPUCLASS_586: | |
| 969 | #endif | |
| 970 | #if !defined(I686_CPU) | |
| 971 | case CPUCLASS_686: | |
| 972 | #endif | |
| 973 | panic("CPU class not configured"); | |
| 974 | default: | |
| 975 | break; | |
| 976 | } | |
| 977 | } | |
| 978 | ||
| 979 | ||
| 980 | static volatile u_int trap_by_rdmsr; | |
| 981 | ||
| 982 | /* | |
| 983 | * Special exception 6 handler. | |
| 984 | * The rdmsr instruction generates invalid opcodes fault on 486-class | |
| 985 | * Cyrix CPU. Stacked eip register points the rdmsr instruction in the | |
| 986 | * function identblue() when this handler is called. Stacked eip should | |
| 987 | * be advanced. | |
| 988 | */ | |
| 989 | inthand_t bluetrap6; | |
| 89b88cd2 | 990 | |
| 90e8a35b AP |
991 | __asm |
| 992 | (" \n\ | |
| 993 | .text \n\ | |
| 994 | .p2align 2,0x90 \n\ | |
| 995 | .type " __XSTRING(CNAME(bluetrap6)) ",@function \n\ | |
| 996 | " __XSTRING(CNAME(bluetrap6)) ": \n\ | |
| 997 | ss \n\ | |
| 998 | movl $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) " \n\ | |
| 999 | addl $2, (%esp) /* rdmsr is a 2-byte instruction */ \n\ | |
| 1000 | iret \n\ | |
| 1001 | "); | |
| 984263bc MD |
1002 | |
| 1003 | /* | |
| 1004 | * Special exception 13 handler. | |
| 1005 | * Accessing non-existent MSR generates general protection fault. | |
| 1006 | */ | |
| 1007 | inthand_t bluetrap13; | |
| 89b88cd2 | 1008 | |
| 90e8a35b AP |
1009 | __asm |
| 1010 | (" \n\ | |
| 1011 | .text \n\ | |
| 1012 | .p2align 2,0x90 \n\ | |
| 1013 | .type " __XSTRING(CNAME(bluetrap13)) ",@function \n\ | |
| 1014 | " __XSTRING(CNAME(bluetrap13)) ": \n\ | |
| 1015 | ss \n\ | |
| 1016 | movl $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) " \n\ | |
| 1017 | popl %eax /* discard error code */ \n\ | |
| 1018 | addl $2, (%esp) /* rdmsr is a 2-byte instruction */ \n\ | |
| 1019 | iret \n\ | |
| 1020 | "); | |
| 984263bc MD |
1021 | |
| 1022 | /* | |
| 1023 | * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not | |
| 1024 | * support cpuid instruction. This function should be called after | |
| 1025 | * loading interrupt descriptor table register. | |
| 1026 | * | |
| 1027 | * I don't like this method that handles fault, but I couldn't get | |
| 1028 | * information for any other methods. Does blue giant know? | |
| 1029 | */ | |
| 1030 | static int | |
| 1031 | identblue(void) | |
| 1032 | { | |
| 1033 | ||
| 1034 | trap_by_rdmsr = 0; | |
| 1035 | ||
| 1036 | /* | |
| 1037 | * Cyrix 486-class CPU does not support rdmsr instruction. | |
| 1038 | * The rdmsr instruction generates invalid opcode fault, and exception | |
| 1039 | * will be trapped by bluetrap6() on Cyrix 486-class CPU. The | |
| 1040 | * bluetrap6() set the magic number to trap_by_rdmsr. | |
| 1041 | */ | |
| 90e8a35b AP |
1042 | setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, |
| 1043 | GSEL(GCODE_SEL, SEL_KPL)); | |
| 984263bc MD |
1044 | |
| 1045 | /* | |
| 1046 | * Certain BIOS disables cpuid instruction of Cyrix 6x86MX CPU. | |
| 1047 | * In this case, rdmsr generates general protection fault, and | |
| 1048 | * exception will be trapped by bluetrap13(). | |
| 1049 | */ | |
| 90e8a35b AP |
1050 | setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, |
| 1051 | GSEL(GCODE_SEL, SEL_KPL)); | |
| 984263bc MD |
1052 | |
| 1053 | rdmsr(0x1002); /* Cyrix CPU generates fault. */ | |
| 1054 | ||
| 1055 | if (trap_by_rdmsr == 0xa8c1d) | |
| 1056 | return IDENTBLUE_CYRIX486; | |
| 1057 | else if (trap_by_rdmsr == 0xa89c4) | |
| 1058 | return IDENTBLUE_CYRIXM2; | |
| 1059 | return IDENTBLUE_IBMCPU; | |
| 1060 | } | |
| 1061 | ||
| 1062 | ||
| 1063 | /* | |
| 1064 | * identifycyrix() set lower 16 bits of cyrix_did as follows: | |
| 1065 | * | |
| 1066 | * F E D C B A 9 8 7 6 5 4 3 2 1 0 | |
| 1067 | * +-------+-------+---------------+ | |
| 1068 | * | SID | RID | Device ID | | |
| 1069 | * | (DIR 1) | (DIR 0) | | |
| 1070 | * +-------+-------+---------------+ | |
| 1071 | */ | |
| 1072 | static void | |
| 1073 | identifycyrix(void) | |
| 1074 | { | |
| 984263bc MD |
1075 | int ccr2_test = 0, dir_test = 0; |
| 1076 | u_char ccr2, ccr3; | |
| 1077 | ||
| 8a8d5d85 | 1078 | mpintr_lock(); |
| 984263bc MD |
1079 | |
| 1080 | ccr2 = read_cyrix_reg(CCR2); | |
| 1081 | write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW); | |
| 1082 | read_cyrix_reg(CCR2); | |
| 1083 | if (read_cyrix_reg(CCR2) != ccr2) | |
| 1084 | ccr2_test = 1; | |
| 1085 | write_cyrix_reg(CCR2, ccr2); | |
| 1086 | ||
| 1087 | ccr3 = read_cyrix_reg(CCR3); | |
| 1088 | write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3); | |
| 1089 | read_cyrix_reg(CCR3); | |
| 1090 | if (read_cyrix_reg(CCR3) != ccr3) | |
| 1091 | dir_test = 1; /* CPU supports DIRs. */ | |
| 1092 | write_cyrix_reg(CCR3, ccr3); | |
| 1093 | ||
| 1094 | if (dir_test) { | |
| 1095 | /* Device ID registers are available. */ | |
| 1096 | cyrix_did = read_cyrix_reg(DIR1) << 8; | |
| 1097 | cyrix_did += read_cyrix_reg(DIR0); | |
| 1098 | } else if (ccr2_test) | |
| 1099 | cyrix_did = 0x0010; /* 486S A-step */ | |
| 1100 | else | |
| 1101 | cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */ | |
| 8a8d5d85 | 1102 | mpintr_unlock(); |
| 984263bc MD |
1103 | } |
| 1104 | ||
| 90e8a35b AP |
1105 | #if 0 |
| 1106 | /* Update TSC freq with the value indicated by the caller. */ | |
| 1107 | static void | |
| 1108 | tsc_frequency_changed(void *arg, const struct cf_level *level, int status) | |
| 1109 | { | |
| 1110 | /* | |
| 1111 | * If there was an error during the transition or | |
| 1112 | * TSC is P-state invariant, don't do anything. | |
| 1113 | */ | |
| 1114 | if (status != 0 || tsc_is_invariant) | |
| 1115 | return; | |
| 1116 | ||
| 1117 | /* Total setting for this level gives the new frequency in MHz. */ | |
| 1118 | hw_clockrate = level->total_set.freq; | |
| 1119 | } | |
| 1120 | #endif | |
| 1121 | ||
| 984263bc MD |
1122 | /* |
| 1123 | * Final stage of CPU identification. -- Should I check TI? | |
| 1124 | */ | |
| 1125 | void | |
| 1126 | finishidentcpu(void) | |
| 1127 | { | |
| 1128 | int isblue = 0; | |
| 1129 | u_char ccr3; | |
| 1130 | u_int regs[4]; | |
| 1131 | ||
| 90e8a35b AP |
1132 | cpu_vendor_id = find_cpu_vendor_id(); |
| 1133 | ||
| 1134 | /* | |
| 1135 | * Clear "Limit CPUID Maxval" bit and get the largest standard CPUID | |
| 1136 | * function number again if it is set from BIOS. It is necessary | |
| 1137 | * for probing correct CPU topology later. | |
| 1138 | * XXX This is only done on the BSP package. | |
| 1139 | */ | |
| 1140 | if (cpu_vendor_id == CPU_VENDOR_INTEL && cpu_high > 0 && cpu_high < 4 && | |
| 1141 | ((CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x3) || | |
| 1142 | (CPUID_TO_FAMILY(cpu_id) == 0x6 && CPUID_TO_MODEL(cpu_id) >= 0xe))) { | |
| 1143 | uint64_t msr; | |
| 1144 | msr = rdmsr(MSR_IA32_MISC_ENABLE); | |
| 1145 | if ((msr & 0x400000ULL) != 0) { | |
| 1146 | wrmsr(MSR_IA32_MISC_ENABLE, msr & ~0x400000ULL); | |
| 1147 | do_cpuid(0, regs); | |
| 1148 | cpu_high = regs[0]; | |
| 1149 | } | |
| 1150 | } | |
| 1151 | ||
| 1152 | /* Detect AMD features (PTE no-execute bit, 3dnow, 64 bit mode etc) */ | |
| 1153 | if (cpu_vendor_id == CPU_VENDOR_INTEL || | |
| 1154 | cpu_vendor_id == CPU_VENDOR_AMD) { | |
| 1155 | init_exthigh(); | |
| 1156 | if (cpu_exthigh >= 0x80000001) { | |
| 1157 | do_cpuid(0x80000001, regs); | |
| 1158 | amd_feature = regs[3] & ~(cpu_feature & 0x0183f3ff); | |
| 1159 | amd_feature2 = regs[2]; | |
| 1160 | } | |
| 1161 | #if 0 | |
| 1162 | if (cpu_exthigh >= 0x80000007) { | |
| 1163 | do_cpuid(0x80000007, regs); | |
| 1164 | amd_pminfo = regs[3]; | |
| 1165 | } | |
| 1166 | #endif | |
| 1167 | if (cpu_exthigh >= 0x80000008) { | |
| 1168 | do_cpuid(0x80000008, regs); | |
| 1169 | cpu_procinfo2 = regs[2]; | |
| 1170 | } | |
| 1171 | } else if (cpu_vendor_id == CPU_VENDOR_CYRIX) { | |
| 984263bc MD |
1172 | if (cpu == CPU_486) { |
| 1173 | /* | |
| 1174 | * These conditions are equivalent to: | |
| 1175 | * - CPU does not support cpuid instruction. | |
| 1176 | * - Cyrix/IBM CPU is detected. | |
| 1177 | */ | |
| 1178 | isblue = identblue(); | |
| 1179 | if (isblue == IDENTBLUE_IBMCPU) { | |
| 1180 | strcpy(cpu_vendor, "IBM"); | |
| 90e8a35b | 1181 | cpu_vendor_id = CPU_VENDOR_IBM; |
| 984263bc | 1182 | cpu = CPU_BLUE; |
| d87e79b9 | 1183 | goto finish; |
| 984263bc MD |
1184 | } |
| 1185 | } | |
| 1186 | switch (cpu_id & 0xf00) { | |
| 1187 | case 0x600: | |
| 1188 | /* | |
| 1189 | * Cyrix's datasheet does not describe DIRs. | |
| 1190 | * Therefor, I assume it does not have them | |
| 1191 | * and use the result of the cpuid instruction. | |
| 1192 | * XXX they seem to have it for now at least. -Peter | |
| 1193 | */ | |
| 1194 | identifycyrix(); | |
| 1195 | cpu = CPU_M2; | |
| 1196 | break; | |
| 1197 | default: | |
| 1198 | identifycyrix(); | |
| 1199 | /* | |
| 1200 | * This routine contains a trick. | |
| 1201 | * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now. | |
| 1202 | */ | |
| 1203 | switch (cyrix_did & 0x00f0) { | |
| 1204 | case 0x00: | |
| 1205 | case 0xf0: | |
| 1206 | cpu = CPU_486DLC; | |
| 1207 | break; | |
| 1208 | case 0x10: | |
| 1209 | cpu = CPU_CY486DX; | |
| 1210 | break; | |
| 1211 | case 0x20: | |
| 1212 | if ((cyrix_did & 0x000f) < 8) | |
| 1213 | cpu = CPU_M1; | |
| 1214 | else | |
| 1215 | cpu = CPU_M1SC; | |
| 1216 | break; | |
| 1217 | case 0x30: | |
| 1218 | cpu = CPU_M1; | |
| 1219 | break; | |
| 1220 | case 0x40: | |
| 1221 | /* MediaGX CPU */ | |
| 1222 | cpu = CPU_M1SC; | |
| 1223 | break; | |
| 1224 | default: | |
| 1225 | /* M2 and later CPUs are treated as M2. */ | |
| 1226 | cpu = CPU_M2; | |
| 1227 | ||
| 1228 | /* | |
| 1229 | * enable cpuid instruction. | |
| 1230 | */ | |
| 1231 | ccr3 = read_cyrix_reg(CCR3); | |
| 1232 | write_cyrix_reg(CCR3, CCR3_MAPEN0); | |
| 1233 | write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID); | |
| 1234 | write_cyrix_reg(CCR3, ccr3); | |
| 1235 | ||
| 1236 | do_cpuid(0, regs); | |
| 1237 | cpu_high = regs[0]; /* eax */ | |
| 1238 | do_cpuid(1, regs); | |
| 1239 | cpu_id = regs[0]; /* eax */ | |
| 1240 | cpu_feature = regs[3]; /* edx */ | |
| 1241 | break; | |
| 1242 | } | |
| 1243 | } | |
| 1244 | } else if (cpu == CPU_486 && *cpu_vendor == '\0') { | |
| 1245 | /* | |
| 1246 | * There are BlueLightning CPUs that do not change | |
| 1247 | * undefined flags by dividing 5 by 2. In this case, | |
| 1248 | * the CPU identification routine in locore.s leaves | |
| 1249 | * cpu_vendor null string and puts CPU_486 into the | |
| 1250 | * cpu. | |
| 1251 | */ | |
| 1252 | isblue = identblue(); | |
| 1253 | if (isblue == IDENTBLUE_IBMCPU) { | |
| 1254 | strcpy(cpu_vendor, "IBM"); | |
| 90e8a35b | 1255 | cpu_vendor_id = CPU_VENDOR_IBM; |
| 984263bc | 1256 | cpu = CPU_BLUE; |
| 984263bc MD |
1257 | } |
| 1258 | } | |
| d87e79b9 MD |
1259 | |
| 1260 | /* | |
| 1261 | * Set MI flags for MI procedures implemented using machine-specific | |
| 1262 | * features. | |
| 1263 | */ | |
| 1264 | finish: | |
| 1265 | if (cpu_feature & CPUID_SSE2) | |
| 1266 | cpu_mi_feature |= CPU_MI_BZERONT; | |
| 1267 | ||
| 2a06bc07 VS |
1268 | if (cpu_feature2 & CPUID2_MON) |
| 1269 | cpu_mi_feature |= CPU_MI_MONITOR; | |
| cbc5d70e SZ |
1270 | |
| 1271 | #ifdef CPU_HAS_SSE2 | |
| 1272 | if ((cpu_feature & CPUID_SSE2) == 0) | |
| 1273 | panic("CPU does not has SSE2, remove options CPU_HAS_SSE2\n"); | |
| 1274 | #endif | |
| 1275 | #ifdef CPU_HAS_FXSR | |
| 1276 | if ((cpu_feature & CPUID_FXSR) == 0) | |
| 1277 | panic("CPU does not has FXSR, remove options CPU_HAS_FXSR\n"); | |
| 1278 | #endif | |
| 984263bc MD |
1279 | } |
| 1280 | ||
| 90e8a35b AP |
1281 | static u_int |
| 1282 | find_cpu_vendor_id(void) | |
| 1283 | { | |
| 1284 | int i; | |
| 1285 | ||
| c157ff7a | 1286 | for (i = 0; i < NELEM(cpu_vendors); i++) |
| 90e8a35b AP |
1287 | if (strcmp(cpu_vendor, cpu_vendors[i].vendor) == 0) |
| 1288 | return (cpu_vendors[i].vendor_id); | |
| 1289 | return (0); | |
| 1290 | } | |
| 1291 | ||
| 984263bc MD |
1292 | static void |
| 1293 | print_AMD_assoc(int i) | |
| 1294 | { | |
| 1295 | if (i == 255) | |
| 26be20a0 | 1296 | kprintf(", fully associative\n"); |
| 984263bc | 1297 | else |
| 26be20a0 | 1298 | kprintf(", %d-way associative\n", i); |
| 984263bc MD |
1299 | } |
| 1300 | ||
| 2ef741b7 SZ |
1301 | /* |
| 1302 | * #31116 Rev 3.06 section 3.9 | |
| 1303 | * CPUID Fn8000_0006 L2/L3 Cache and L2 TLB Identifiers | |
| 1304 | */ | |
| 1305 | static void | |
| 1306 | print_AMD_L2L3_assoc(int i) | |
| 1307 | { | |
| 1308 | static const char *assoc_str[] = { | |
| 1309 | [0x0] = "disabled", | |
| 1310 | [0x1] = "direct mapped", | |
| 1311 | [0x2] = "2-way associative", | |
| 1312 | [0x4] = "4-way associative", | |
| 1313 | [0x6] = "8-way associative", | |
| 1314 | [0x8] = "16-way associative", | |
| 1315 | [0xa] = "32-way associative", | |
| 1316 | [0xb] = "48-way associative", | |
| 1317 | [0xc] = "64-way associative", | |
| 1318 | [0xd] = "96-way associative", | |
| 1319 | [0xe] = "128-way associative", | |
| 1320 | [0xf] = "fully associative" | |
| 1321 | }; | |
| 1322 | ||
| 1323 | i &= 0xf; | |
| 1324 | if (assoc_str[i] == NULL) | |
| 1325 | kprintf(", unknown associative\n"); | |
| 1326 | else | |
| 1327 | kprintf(", %s\n", assoc_str[i]); | |
| 1328 | } | |
| 1329 | ||
| 984263bc MD |
1330 | static void |
| 1331 | print_AMD_info(void) | |
| 1332 | { | |
| 1333 | quad_t amd_whcr; | |
| 1334 | ||
| 1335 | if (cpu_exthigh >= 0x80000005) { | |
| 1336 | u_int regs[4]; | |
| 1337 | ||
| 1338 | do_cpuid(0x80000005, regs); | |
| 26be20a0 | 1339 | kprintf("Data TLB: %d entries", (regs[1] >> 16) & 0xff); |
| 984263bc | 1340 | print_AMD_assoc(regs[1] >> 24); |
| 26be20a0 | 1341 | kprintf("Instruction TLB: %d entries", regs[1] & 0xff); |
| 984263bc | 1342 | print_AMD_assoc((regs[1] >> 8) & 0xff); |
| 26be20a0 SW |
1343 | kprintf("L1 data cache: %d kbytes", regs[2] >> 24); |
| 1344 | kprintf(", %d bytes/line", regs[2] & 0xff); | |
| 1345 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0xff); | |
| 984263bc | 1346 | print_AMD_assoc((regs[2] >> 16) & 0xff); |
| 26be20a0 SW |
1347 | kprintf("L1 instruction cache: %d kbytes", regs[3] >> 24); |
| 1348 | kprintf(", %d bytes/line", regs[3] & 0xff); | |
| 1349 | kprintf(", %d lines/tag", (regs[3] >> 8) & 0xff); | |
| 984263bc | 1350 | print_AMD_assoc((regs[3] >> 16) & 0xff); |
| 90e8a35b | 1351 | if (cpu_exthigh >= 0x80000006) { /* K6-III or later */ |
| 984263bc | 1352 | do_cpuid(0x80000006, regs); |
| 9b95ebe5 HP |
1353 | /* |
| 1354 | * Report right L2 cache size on Duron rev. A0. | |
| 1355 | */ | |
| 1356 | if ((cpu_id & 0xFF0) == 0x630) | |
| 26be20a0 | 1357 | kprintf("L2 internal cache: 64 kbytes"); |
| 9b95ebe5 | 1358 | else |
| 90e8a35b | 1359 | kprintf("L2 internal cache: %d kbytes", regs[2] >> 16); |
| 9b95ebe5 | 1360 | |
| 26be20a0 SW |
1361 | kprintf(", %d bytes/line", regs[2] & 0xff); |
| 1362 | kprintf(", %d lines/tag", (regs[2] >> 8) & 0x0f); | |
| 2ef741b7 SZ |
1363 | print_AMD_L2L3_assoc((regs[2] >> 12) & 0x0f); |
| 1364 | ||
| 1365 | /* | |
| 1366 | * #31116 Rev 3.06 section 2.16.2: | |
| 1367 | * ... If EDX[31:16] is not zero then the processor | |
| 1368 | * includes an L3. ... | |
| 1369 | */ | |
| 1370 | if ((regs[3] & 0xffff0000) != 0) { | |
| 1371 | kprintf("L3 shared cache: %d kbytes", | |
| 1372 | (regs[3] >> 18) * 512); | |
| 1373 | kprintf(", %d bytes/line", regs[3] & 0xff); | |
| 1374 | kprintf(", %d lines/tag", (regs[3] >> 8) & 0x0f); | |
| 1375 | print_AMD_L2L3_assoc((regs[3] >> 12) & 0x0f); | |
| 1376 | } | |
| 984263bc MD |
1377 | } |
| 1378 | } | |
| 1379 | if (((cpu_id & 0xf00) == 0x500) | |
| 1380 | && (((cpu_id & 0x0f0) > 0x80) | |
| 1381 | || (((cpu_id & 0x0f0) == 0x80) | |
| 1382 | && (cpu_id & 0x00f) > 0x07))) { | |
| 1383 | /* K6-2(new core [Stepping 8-F]), K6-III or later */ | |
| 1384 | amd_whcr = rdmsr(0xc0000082); | |
| 1385 | if (!(amd_whcr & (0x3ff << 22))) { | |
| 26be20a0 | 1386 | kprintf("Write Allocate Disable\n"); |
| 984263bc | 1387 | } else { |
| 26be20a0 | 1388 | kprintf("Write Allocate Enable Limit: %dM bytes\n", |
| 984263bc | 1389 | (u_int32_t)((amd_whcr & (0x3ff << 22)) >> 22) * 4); |
| 26be20a0 | 1390 | kprintf("Write Allocate 15-16M bytes: %s\n", |
| 984263bc MD |
1391 | (amd_whcr & (1 << 16)) ? "Enable" : "Disable"); |
| 1392 | } | |
| 1393 | } else if (((cpu_id & 0xf00) == 0x500) | |
| 1394 | && ((cpu_id & 0x0f0) > 0x50)) { | |
| 1395 | /* K6, K6-2(old core) */ | |
| 1396 | amd_whcr = rdmsr(0xc0000082); | |
| 1397 | if (!(amd_whcr & (0x7f << 1))) { | |
| 26be20a0 | 1398 | kprintf("Write Allocate Disable\n"); |
| 984263bc | 1399 | } else { |
| 26be20a0 | 1400 | kprintf("Write Allocate Enable Limit: %dM bytes\n", |
| 984263bc | 1401 | (u_int32_t)((amd_whcr & (0x7f << 1)) >> 1) * 4); |
| 26be20a0 | 1402 | kprintf("Write Allocate 15-16M bytes: %s\n", |
| 984263bc | 1403 | (amd_whcr & 0x0001) ? "Enable" : "Disable"); |
| 26be20a0 | 1404 | kprintf("Hardware Write Allocate Control: %s\n", |
| 984263bc MD |
1405 | (amd_whcr & 0x0100) ? "Enable" : "Disable"); |
| 1406 | } | |
| 1407 | } | |
| 984263bc MD |
1408 | |
| 1409 | /* | |
| 90e8a35b AP |
1410 | * Opteron Rev E shows a bug as in very rare occasions a read memory |
| 1411 | * barrier is not performed as expected if it is followed by a | |
| 1412 | * non-atomic read-modify-write instruction. | |
| 1413 | * As long as that bug pops up very rarely (intensive machine usage | |
| 1414 | * on other operating systems generally generates one unexplainable | |
| 1415 | * crash any 2 months) and as long as a model specific fix would be | |
| 1416 | * impratical at this stage, print out a warning string if the broken | |
| 1417 | * model and family are identified. | |
| 984263bc | 1418 | */ |
| 90e8a35b AP |
1419 | if (CPUID_TO_FAMILY(cpu_id) == 0xf && CPUID_TO_MODEL(cpu_id) >= 0x20 && |
| 1420 | CPUID_TO_MODEL(cpu_id) <= 0x3f) | |
| 1421 | kprintf("WARNING: This architecture revision has known SMP " | |
| 1422 | "hardware bugs which may cause random instability\n"); | |
| 984263bc MD |
1423 | } |
| 1424 | ||
| 90e8a35b AP |
1425 | static void |
| 1426 | print_INTEL_info(void) | |
| 984263bc | 1427 | { |
| 90e8a35b AP |
1428 | u_int regs[4]; |
| 1429 | u_int rounds, regnum; | |
| 1430 | u_int nwaycode, nway; | |
| 1431 | ||
| 1432 | if (cpu_high >= 2) { | |
| 1433 | rounds = 0; | |
| 1434 | do { | |
| 1435 | do_cpuid(0x2, regs); | |
| 1436 | if (rounds == 0 && (rounds = (regs[0] & 0xff)) == 0) | |
| 1437 | break; /* we have a buggy CPU */ | |
| 1438 | ||
| 1439 | for (regnum = 0; regnum <= 3; ++regnum) { | |
| 1440 | if (regs[regnum] & (1<<31)) | |
| 1441 | continue; | |
| 1442 | if (regnum != 0) | |
| 1443 | print_INTEL_TLB(regs[regnum] & 0xff); | |
| 1444 | print_INTEL_TLB((regs[regnum] >> 8) & 0xff); | |
| 1445 | print_INTEL_TLB((regs[regnum] >> 16) & 0xff); | |
| 1446 | print_INTEL_TLB((regs[regnum] >> 24) & 0xff); | |
| 1447 | } | |
| 1448 | } while (--rounds > 0); | |
| 984263bc MD |
1449 | } |
| 1450 | ||
| 90e8a35b AP |
1451 | if (cpu_exthigh >= 0x80000006) { |
| 1452 | do_cpuid(0x80000006, regs); | |
| 1453 | nwaycode = (regs[2] >> 12) & 0x0f; | |
| 1454 | if (nwaycode >= 0x02 && nwaycode <= 0x08) | |
| 1455 | nway = 1 << (nwaycode / 2); | |
| 1456 | else | |
| 1457 | nway = 0; | |
| 1458 | kprintf("\nL2 cache: %u kbytes, %u-way associative, %u bytes/line", | |
| 1459 | (regs[2] >> 16) & 0xffff, nway, regs[2] & 0xff); | |
| 984263bc MD |
1460 | } |
| 1461 | ||
| 90e8a35b | 1462 | kprintf("\n"); |
| 984263bc MD |
1463 | } |
| 1464 | ||
| 1465 | static void | |
| 90e8a35b | 1466 | print_INTEL_TLB(u_int data) |
| 984263bc | 1467 | { |
| 90e8a35b AP |
1468 | switch (data) { |
| 1469 | case 0x0: | |
| 1470 | case 0x40: | |
| 1471 | default: | |
| 1472 | break; | |
| 1473 | case 0x1: | |
| 1474 | kprintf("\nInstruction TLB: 4 KB pages, 4-way set associative, 32 entries"); | |
| 1475 | break; | |
| 1476 | case 0x2: | |
| 1477 | kprintf("\nInstruction TLB: 4 MB pages, fully associative, 2 entries"); | |
| 1478 | break; | |
| 1479 | case 0x3: | |
| 1480 | kprintf("\nData TLB: 4 KB pages, 4-way set associative, 64 entries"); | |
| 1481 | break; | |
| 1482 | case 0x4: | |
| 1483 | kprintf("\nData TLB: 4 MB Pages, 4-way set associative, 8 entries"); | |
| 1484 | break; | |
| 1485 | case 0x6: | |
| 1486 | kprintf("\n1st-level instruction cache: 8 KB, 4-way set associative, 32 byte line size"); | |
| 1487 | break; | |
| 1488 | case 0x8: | |
| 1489 | kprintf("\n1st-level instruction cache: 16 KB, 4-way set associative, 32 byte line size"); | |
| 1490 | break; | |
| 1491 | case 0xa: | |
| 1492 | kprintf("\n1st-level data cache: 8 KB, 2-way set associative, 32 byte line size"); | |
| 1493 | break; | |
| 1494 | case 0xc: | |
| 1495 | kprintf("\n1st-level data cache: 16 KB, 4-way set associative, 32 byte line size"); | |
| 1496 | break; | |
| 1497 | case 0x22: | |
| 1498 | kprintf("\n3rd-level cache: 512 KB, 4-way set associative, sectored cache, 64 byte line size"); | |
| 1499 | break; | |
| 1500 | case 0x23: | |
| 1501 | kprintf("\n3rd-level cache: 1 MB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1502 | break; | |
| 1503 | case 0x25: | |
| 1504 | kprintf("\n3rd-level cache: 2 MB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1505 | break; | |
| 1506 | case 0x29: | |
| 1507 | kprintf("\n3rd-level cache: 4 MB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1508 | break; | |
| 1509 | case 0x2c: | |
| 1510 | kprintf("\n1st-level data cache: 32 KB, 8-way set associative, 64 byte line size"); | |
| 1511 | break; | |
| 1512 | case 0x30: | |
| 1513 | kprintf("\n1st-level instruction cache: 32 KB, 8-way set associative, 64 byte line size"); | |
| 1514 | break; | |
| 1515 | case 0x39: | |
| 1516 | kprintf("\n2nd-level cache: 128 KB, 4-way set associative, sectored cache, 64 byte line size"); | |
| 1517 | break; | |
| 1518 | case 0x3b: | |
| 1519 | kprintf("\n2nd-level cache: 128 KB, 2-way set associative, sectored cache, 64 byte line size"); | |
| 1520 | break; | |
| 1521 | case 0x3c: | |
| 1522 | kprintf("\n2nd-level cache: 256 KB, 4-way set associative, sectored cache, 64 byte line size"); | |
| 1523 | break; | |
| 1524 | case 0x41: | |
| 1525 | kprintf("\n2nd-level cache: 128 KB, 4-way set associative, 32 byte line size"); | |
| 1526 | break; | |
| 1527 | case 0x42: | |
| 1528 | kprintf("\n2nd-level cache: 256 KB, 4-way set associative, 32 byte line size"); | |
| 1529 | break; | |
| 1530 | case 0x43: | |
| 1531 | kprintf("\n2nd-level cache: 512 KB, 4-way set associative, 32 byte line size"); | |
| 1532 | break; | |
| 1533 | case 0x44: | |
| 1534 | kprintf("\n2nd-level cache: 1 MB, 4-way set associative, 32 byte line size"); | |
| 1535 | break; | |
| 1536 | case 0x45: | |
| 1537 | kprintf("\n2nd-level cache: 2 MB, 4-way set associative, 32 byte line size"); | |
| 1538 | break; | |
| 1539 | case 0x46: | |
| 1540 | kprintf("\n3rd-level cache: 4 MB, 4-way set associative, 64 byte line size"); | |
| 1541 | break; | |
| 1542 | case 0x47: | |
| 1543 | kprintf("\n3rd-level cache: 8 MB, 8-way set associative, 64 byte line size"); | |
| 1544 | break; | |
| 1545 | case 0x50: | |
| 1546 | kprintf("\nInstruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 64 entries"); | |
| 1547 | break; | |
| 1548 | case 0x51: | |
| 1549 | kprintf("\nInstruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 128 entries"); | |
| 1550 | break; | |
| 1551 | case 0x52: | |
| 1552 | kprintf("\nInstruction TLB: 4 KB, 2 MB or 4 MB pages, fully associative, 256 entries"); | |
| 1553 | break; | |
| 1554 | case 0x5b: | |
| 1555 | kprintf("\nData TLB: 4 KB or 4 MB pages, fully associative, 64 entries"); | |
| 1556 | break; | |
| 1557 | case 0x5c: | |
| 1558 | kprintf("\nData TLB: 4 KB or 4 MB pages, fully associative, 128 entries"); | |
| 1559 | break; | |
| 1560 | case 0x5d: | |
| 1561 | kprintf("\nData TLB: 4 KB or 4 MB pages, fully associative, 256 entries"); | |
| 1562 | break; | |
| 1563 | case 0x60: | |
| 1564 | kprintf("\n1st-level data cache: 16 KB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1565 | break; | |
| 1566 | case 0x66: | |
| 1567 | kprintf("\n1st-level data cache: 8 KB, 4-way set associative, sectored cache, 64 byte line size"); | |
| 1568 | break; | |
| 1569 | case 0x67: | |
| 1570 | kprintf("\n1st-level data cache: 16 KB, 4-way set associative, sectored cache, 64 byte line size"); | |
| 1571 | break; | |
| 1572 | case 0x68: | |
| 1573 | kprintf("\n1st-level data cache: 32 KB, 4 way set associative, sectored cache, 64 byte line size"); | |
| 1574 | break; | |
| 1575 | case 0x70: | |
| 1576 | kprintf("\nTrace cache: 12K-uops, 8-way set associative"); | |
| 1577 | break; | |
| 1578 | case 0x71: | |
| 1579 | kprintf("\nTrace cache: 16K-uops, 8-way set associative"); | |
| 1580 | break; | |
| 1581 | case 0x72: | |
| 1582 | kprintf("\nTrace cache: 32K-uops, 8-way set associative"); | |
| 1583 | break; | |
| 1584 | case 0x78: | |
| 1585 | kprintf("\n2nd-level cache: 1 MB, 4-way set associative, 64-byte line size"); | |
| 1586 | break; | |
| 1587 | case 0x79: | |
| 1588 | kprintf("\n2nd-level cache: 128 KB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1589 | break; | |
| 1590 | case 0x7a: | |
| 1591 | kprintf("\n2nd-level cache: 256 KB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1592 | break; | |
| 1593 | case 0x7b: | |
| 1594 | kprintf("\n2nd-level cache: 512 KB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1595 | break; | |
| 1596 | case 0x7c: | |
| 1597 | kprintf("\n2nd-level cache: 1 MB, 8-way set associative, sectored cache, 64 byte line size"); | |
| 1598 | break; | |
| 1599 | case 0x7d: | |
| 1600 | kprintf("\n2nd-level cache: 2-MB, 8-way set associative, 64-byte line size"); | |
| 1601 | break; | |
| 1602 | case 0x7f: | |
| 1603 | kprintf("\n2nd-level cache: 512-KB, 2-way set associative, 64-byte line size"); | |
| 1604 | break; | |
| 1605 | case 0x82: | |
| 1606 | kprintf("\n2nd-level cache: 256 KB, 8-way set associative, 32 byte line size"); | |
| 1607 | break; | |
| 1608 | case 0x83: | |
| 1609 | kprintf("\n2nd-level cache: 512 KB, 8-way set associative, 32 byte line size"); | |
| 1610 | break; | |
| 1611 | case 0x84: | |
| 1612 | kprintf("\n2nd-level cache: 1 MB, 8-way set associative, 32 byte line size"); | |
| 1613 | break; | |
| 1614 | case 0x85: | |
| 1615 | kprintf("\n2nd-level cache: 2 MB, 8-way set associative, 32 byte line size"); | |
| 1616 | break; | |
| 1617 | case 0x86: | |
| 1618 | kprintf("\n2nd-level cache: 512 KB, 4-way set associative, 64 byte line size"); | |
| 1619 | break; | |
| 1620 | case 0x87: | |
| 1621 | kprintf("\n2nd-level cache: 1 MB, 8-way set associative, 64 byte line size"); | |
| 1622 | break; | |
| 1623 | case 0xb0: | |
| 1624 | kprintf("\nInstruction TLB: 4 KB Pages, 4-way set associative, 128 entries"); | |
| 1625 | break; | |
| 1626 | case 0xb3: | |
| 1627 | kprintf("\nData TLB: 4 KB Pages, 4-way set associative, 128 entries"); | |
| 1628 | break; | |
| 1629 | } | |
| 984263bc MD |
1630 | } |
| 1631 | ||
| 1632 | static void | |
| f123d5a1 | 1633 | print_transmeta_info(void) |
| 984263bc MD |
1634 | { |
| 1635 | u_int regs[4], nreg = 0; | |
| 1636 | ||
| 1637 | do_cpuid(0x80860000, regs); | |
| 1638 | nreg = regs[0]; | |
| 1639 | if (nreg >= 0x80860001) { | |
| 1640 | do_cpuid(0x80860001, regs); | |
| 26be20a0 | 1641 | kprintf(" Processor revision %u.%u.%u.%u\n", |
| 984263bc MD |
1642 | (regs[1] >> 24) & 0xff, |
| 1643 | (regs[1] >> 16) & 0xff, | |
| 1644 | (regs[1] >> 8) & 0xff, | |
| 1645 | regs[1] & 0xff); | |
| 1646 | } | |
| 1647 | if (nreg >= 0x80860002) { | |
| 1648 | do_cpuid(0x80860002, regs); | |
| 26be20a0 | 1649 | kprintf(" Code Morphing Software revision %u.%u.%u-%u-%u\n", |
| 984263bc MD |
1650 | (regs[1] >> 24) & 0xff, |
| 1651 | (regs[1] >> 16) & 0xff, | |
| 1652 | (regs[1] >> 8) & 0xff, | |
| 1653 | regs[1] & 0xff, | |
| 1654 | regs[2]); | |
| 1655 | } | |
| 1656 | if (nreg >= 0x80860006) { | |
| 1657 | char info[65]; | |
| 1658 | do_cpuid(0x80860003, (u_int*) &info[0]); | |
| 1659 | do_cpuid(0x80860004, (u_int*) &info[16]); | |
| 1660 | do_cpuid(0x80860005, (u_int*) &info[32]); | |
| 1661 | do_cpuid(0x80860006, (u_int*) &info[48]); | |
| 1662 | info[64] = 0; | |
| 26be20a0 | 1663 | kprintf(" %s\n", info); |
| 984263bc | 1664 | } |
| 984263bc MD |
1665 | } |
| 1666 | ||
| ca6dce84 SW |
1667 | static void |
| 1668 | print_via_padlock_info(void) | |
| 1669 | { | |
| 1670 | u_int regs[4]; | |
| 1671 | ||
| 1672 | /* Check for supported models. */ | |
| 1673 | switch (cpu_id & 0xff0) { | |
| 1674 | case 0x690: | |
| 1675 | if ((cpu_id & 0xf) < 3) | |
| 1676 | return; | |
| 1677 | case 0x6a0: | |
| 1678 | case 0x6d0: | |
| 1679 | case 0x6f0: | |
| 1680 | break; | |
| 1681 | default: | |
| 1682 | return; | |
| 1683 | } | |
| 1684 | ||
| 1685 | do_cpuid(0xc0000000, regs); | |
| 1686 | if (regs[0] >= 0xc0000001) | |
| 1687 | do_cpuid(0xc0000001, regs); | |
| 1688 | else | |
| 1689 | return; | |
| 1690 | ||
| 1691 | kprintf("\n VIA Padlock Features=0x%b", regs[3], | |
| 1692 | "\020" | |
| 1693 | "\003RNG" /* RNG */ | |
| 1694 | "\007AES" /* ACE */ | |
| 1695 | "\011AES-CTR" /* ACE2 */ | |
| 1696 | "\013SHA1,SHA256" /* PHE */ | |
| 1697 | "\015RSA" /* PMM */ | |
| 1698 | ); | |
| 1699 | } | |
| 1700 | ||
| 20f0a2d3 MD |
1701 | void |
| 1702 | additional_cpu_info(const char *line) | |
| 1703 | { | |
| 1704 | int i; | |
| 1705 | ||
| 1706 | if ((i = additional_cpu_info_count) < MAX_ADDITIONAL_INFO) { | |
| 1707 | additional_cpu_info_ary[i] = line; | |
| 1708 | ++additional_cpu_info_count; | |
| 1709 | } | |
| 1710 | } |