identcpu.c revision 36303
168349Sobrien/* 268349Sobrien * Copyright (c) 1992 Terrence R. Lambert. 368349Sobrien * Copyright (c) 1982, 1987, 1990 The Regents of the University of California. 468349Sobrien * Copyright (c) 1997 KATO Takenori. 568349Sobrien * All rights reserved. 668349Sobrien * 768349Sobrien * This code is derived from software contributed to Berkeley by 868349Sobrien * William Jolitz. 968349Sobrien * 1068349Sobrien * Redistribution and use in source and binary forms, with or without 1168349Sobrien * modification, are permitted provided that the following conditions 1268349Sobrien * are met: 1368349Sobrien * 1. Redistributions of source code must retain the above copyright 1468349Sobrien * notice, this list of conditions and the following disclaimer. 1568349Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1668349Sobrien * notice, this list of conditions and the following disclaimer in the 1768349Sobrien * documentation and/or other materials provided with the distribution. 1868349Sobrien * 3. All advertising materials mentioning features or use of this software 1968349Sobrien * must display the following acknowledgement: 2068349Sobrien * This product includes software developed by the University of 2168349Sobrien * California, Berkeley and its contributors. 2268349Sobrien * 4. Neither the name of the University nor the names of its contributors 2368349Sobrien * may be used to endorse or promote products derived from this software 2468349Sobrien * without specific prior written permission. 2568349Sobrien * 2668349Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2768349Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2868349Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2968349Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3068349Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3168349Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3268349Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3368349Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3468349Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3568349Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3668349Sobrien * SUCH DAMAGE. 3768349Sobrien * 3868349Sobrien * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp 3968349Sobrien * $Id: identcpu.c,v 1.47 1998/05/21 22:53:24 des Exp $ 4068349Sobrien */ 4168349Sobrien 4268349Sobrien#include "opt_cpu.h" 4368349Sobrien 4468349Sobrien#include <sys/param.h> 4568349Sobrien#include <sys/systm.h> 4668349Sobrien#include <sys/kernel.h> 4768349Sobrien#include <sys/sysctl.h> 4868349Sobrien 4968349Sobrien#include <machine/asmacros.h> 5068349Sobrien#include <machine/clock.h> 5168349Sobrien#include <machine/cputypes.h> 5268349Sobrien#include <machine/segments.h> 5368349Sobrien#include <machine/specialreg.h> 5468349Sobrien#include <machine/md_var.h> 5568349Sobrien 5668349Sobrien#include <i386/isa/intr_machdep.h> 5768349Sobrien 5868349Sobrien#define IDENTBLUE_CYRIX486 0 5968349Sobrien#define IDENTBLUE_IBMCPU 1 6068349Sobrien#define IDENTBLUE_CYRIXM2 2 6168349Sobrien 6268349Sobrien/* XXX - should be in header file */ 6368349Sobrienvoid i486_bzero __P((void *buf, size_t len)); 6468349Sobrien 6568349Sobrienvoid printcpuinfo(void); /* XXX should be in different header file */ 6668349Sobrienvoid finishidentcpu(void); 6768349Sobrienvoid earlysetcpuclass(void); 6868349Sobrienvoid panicifcpuunsupported(void); 6968349Sobrienstatic void identifycyrix(void); 7068349Sobrienstatic void print_AMD_info(void); 7168349Sobrienstatic void print_AMD_assoc(int i); 7268349Sobrienstatic void do_cpuid(u_long ax, u_long *p); 7368349Sobrien 7468349Sobrienu_long cyrix_did; /* Device ID of Cyrix CPU */ 7568349Sobrienint cpu_class = CPUCLASS_386; /* least common denominator */ 7668349Sobrienchar machine[] = "i386"; 7768349SobrienSYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 7868349Sobrien 7968349Sobrienstatic char cpu_model[128]; 8068349SobrienSYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 8168349Sobrien 8268349Sobrienstatic struct cpu_nameclass i386_cpus[] = { 8368349Sobrien { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */ 8468349Sobrien { "i386SX", CPUCLASS_386 }, /* CPU_386SX */ 8568349Sobrien { "i386DX", CPUCLASS_386 }, /* CPU_386 */ 8668349Sobrien { "i486SX", CPUCLASS_486 }, /* CPU_486SX */ 8768349Sobrien { "i486DX", CPUCLASS_486 }, /* CPU_486 */ 8868349Sobrien { "Pentium", CPUCLASS_586 }, /* CPU_586 */ 8968349Sobrien { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */ 9068349Sobrien { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ 9168349Sobrien { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */ 9268349Sobrien { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */ 9368349Sobrien { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */ 9468349Sobrien { "Cyrix 6x86MX", CPUCLASS_686 }, /* CPU_M2 */ 9568349Sobrien { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */ 9668349Sobrien { "Cyrix 486S/DX", CPUCLASS_486 }, /* CPU_CY486DX */ 9768349Sobrien { "Pentium II", CPUCLASS_686 }, /* CPU_PII */ 9868349Sobrien}; 9968349Sobrien 10068349Sobrienstatic void 10168349Sobriendo_cpuid(u_long ax, u_long *p) 10268349Sobrien{ 10368349Sobrien __asm __volatile( 10468349Sobrien ".byte 0x0f, 0xa2;" 10568349Sobrien "movl %%eax, (%%esi);" 10668349Sobrien "movl %%ebx, (4)(%%esi);" 10768349Sobrien "movl %%ecx, (8)(%%esi);" 10868349Sobrien "movl %%edx, (12)(%%esi);" 10968349Sobrien : 11068349Sobrien : "a" (ax), "S" (p) 11168349Sobrien : "ax", "bx", "cx", "dx" 11268349Sobrien ); 11368349Sobrien} 11468349Sobrien 11568349Sobrien#if defined(I586_CPU) && !defined(NO_F00F_HACK) 11668349Sobrienint has_f00f_bug = 0; 11768349Sobrien#endif 11868349Sobrien 11968349Sobrienvoid 12068349Sobrienprintcpuinfo(void) 12168349Sobrien{ 12268349Sobrien 12368349Sobrien u_long regs[4], nreg; 12468349Sobrien cpu_class = i386_cpus[cpu].cpu_class; 12568349Sobrien printf("CPU: "); 12668349Sobrien strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model); 12768349Sobrien 12868349Sobrien#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 12968349Sobrien if (strcmp(cpu_vendor,"GenuineIntel") == 0) { 13068349Sobrien if ((cpu_id & 0xf00) > 3) { 131 cpu_model[0] = '\0'; 132 133 switch (cpu_id & 0x3000) { 134 case 0x1000: 135 strcpy(cpu_model, "Overdrive "); 136 break; 137 case 0x2000: 138 strcpy(cpu_model, "Dual "); 139 break; 140 } 141 142 switch (cpu_id & 0xf00) { 143 case 0x400: 144 strcat(cpu_model, "i486 "); 145 break; 146 case 0x500: 147 /* Check the particular flavor of 586 */ 148 strcat(cpu_model, "Pentium"); 149 switch (cpu_id & 0xf0) { 150 case 0x00: 151 strcat(cpu_model, " A-step"); 152 break; 153 case 0x10: 154 strcat(cpu_model, "/P5"); 155 break; 156 case 0x20: 157 strcat(cpu_model, "/P54C"); 158 break; 159 case 0x30: 160 strcat(cpu_model, "/P54T Overdrive"); 161 break; 162 case 0x40: 163 strcat(cpu_model, "/P55C"); 164 break; 165 case 0x70: 166 strcat(cpu_model, "/P54C"); 167 break; 168 case 0x80: 169 strcat(cpu_model, "/P55C (quarter-micron)"); 170 break; 171 default: 172 /* nothing */ 173 break; 174 } 175#if defined(I586_CPU) && !defined(NO_F00F_HACK) 176 /* 177 * XXX - If/when Intel fixes the bug, this 178 * should also check the version of the 179 * CPU, not just that it's a Pentium. 180 */ 181 has_f00f_bug = 1; 182#endif 183 break; 184 case 0x600: 185 /* Check the particular flavor of 686 */ 186 switch (cpu_id & 0xf0) { 187 case 0x00: 188 strcat(cpu_model, "Pentium Pro A-step"); 189 break; 190 case 0x10: 191 strcat(cpu_model, "Pentium Pro"); 192 break; 193 case 0x30: 194 strcat(cpu_model, "Pentium II"); 195 cpu = CPU_PII; 196 break; 197 case 0x50: 198 strcat(cpu_model, "Pentium II (quarter-micron)"); 199 cpu = CPU_PII; 200 break; 201 default: 202 strcat(cpu_model, "Unknown 80686"); 203 break; 204 } 205 break; 206 default: 207 strcat(cpu_model, "unknown"); 208 break; 209 } 210 211 switch (cpu_id & 0xff0) { 212 case 0x400: 213 strcat(cpu_model, "DX"); break; 214 case 0x410: 215 strcat(cpu_model, "DX"); break; 216 case 0x420: 217 strcat(cpu_model, "SX"); break; 218 case 0x430: 219 strcat(cpu_model, "DX2"); break; 220 case 0x440: 221 strcat(cpu_model, "SL"); break; 222 case 0x450: 223 strcat(cpu_model, "SX2"); break; 224 case 0x470: 225 strcat(cpu_model, "DX2 Write-Back Enhanced"); 226 break; 227 case 0x480: 228 strcat(cpu_model, "DX4"); break; 229 break; 230 } 231 } 232 } else if (strcmp(cpu_vendor,"AuthenticAMD") == 0) { 233 /* 234 * Values taken from AMD Processor Recognition 235 * http://www.amd.com/K6/k6docs/pdf/20734g.pdf 236 * (also describes ``Features'' encodings. 237 */ 238 strcpy(cpu_model, "AMD "); 239 switch (cpu_id & 0xFF0) { 240 case 0x410: 241 strcat(cpu_model, "Standard Am486DX"); 242 break; 243 case 0x430: 244 strcat(cpu_model, "Am486DX2/4 Write-Through"); 245 break; 246 case 0x470: 247 strcat(cpu_model, "Enhanced Am486DX4 Write-Back"); 248 break; 249 case 0x480: 250 strcat(cpu_model, "Enhanced Am486DX4 Write-Through"); 251 break; 252 case 0x490: 253 strcat(cpu_model, "Enhanced Am486DX4 Write-Back"); 254 break; 255 case 0x4E0: 256 strcat(cpu_model, "Am5x86 Write-Through"); 257 break; 258 case 0x4F0: 259 strcat(cpu_model, "Am5x86 Write-Back"); 260 break; 261 case 0x500: 262 strcat(cpu_model, "K5 model 0"); 263 break; 264 case 0x510: 265 strcat(cpu_model, "K5 model 1"); 266 break; 267 case 0x520: 268 strcat(cpu_model, "K5 PR166 (model 2)"); 269 break; 270 case 0x530: 271 strcat(cpu_model, "K5 PR200 (model 3)"); 272 break; 273 case 0x560: 274 strcat(cpu_model, "K6"); 275 break; 276 default: 277 strcat(cpu_model, "Unknown"); 278 break; 279 } 280 do_cpuid(0x80000000, regs); 281 nreg = regs[0]; 282 if (nreg >= 0x80000004) { 283 do_cpuid(0x80000002, regs); 284 memcpy(cpu_model, regs, sizeof regs); 285 do_cpuid(0x80000003, regs); 286 memcpy(cpu_model+16, regs, sizeof regs); 287 do_cpuid(0x80000004, regs); 288 memcpy(cpu_model+32, regs, sizeof regs); 289 } 290 } else if (strcmp(cpu_vendor,"CyrixInstead") == 0) { 291 strcpy(cpu_model, "Cyrix "); 292 switch (cpu_id & 0xff0) { 293 case 0x440: 294 strcat(cpu_model, "MediaGX"); 295 break; 296 case 0x520: 297 strcat(cpu_model, "6x86"); 298 break; 299 case 0x540: 300 cpu_class = CPUCLASS_586; 301 strcat(cpu_model, "GXm"); 302 break; 303 case 0x600: 304 strcat(cpu_model, "6x86MX"); 305 break; 306 default: 307 /* 308 * Even though CPU supports the cpuid 309 * instruction, it can be disabled. 310 * Therefore, this routine supports all Cyrix 311 * CPUs. 312 */ 313 switch (cyrix_did & 0xf0) { 314 case 0x00: 315 switch (cyrix_did & 0x0f) { 316 case 0x00: 317 strcat(cpu_model, "486SLC"); 318 break; 319 case 0x01: 320 strcat(cpu_model, "486DLC"); 321 break; 322 case 0x02: 323 strcat(cpu_model, "486SLC2"); 324 break; 325 case 0x03: 326 strcat(cpu_model, "486DLC2"); 327 break; 328 case 0x04: 329 strcat(cpu_model, "486SRx"); 330 break; 331 case 0x05: 332 strcat(cpu_model, "486DRx"); 333 break; 334 case 0x06: 335 strcat(cpu_model, "486SRx2"); 336 break; 337 case 0x07: 338 strcat(cpu_model, "486DRx2"); 339 break; 340 case 0x08: 341 strcat(cpu_model, "486SRu"); 342 break; 343 case 0x09: 344 strcat(cpu_model, "486DRu"); 345 break; 346 case 0x0a: 347 strcat(cpu_model, "486SRu2"); 348 break; 349 case 0x0b: 350 strcat(cpu_model, "486DRu2"); 351 break; 352 default: 353 strcat(cpu_model, "Unknown"); 354 break; 355 } 356 break; 357 case 0x10: 358 switch (cyrix_did & 0x0f) { 359 case 0x00: 360 strcat(cpu_model, "486S"); 361 break; 362 case 0x01: 363 strcat(cpu_model, "486S2"); 364 break; 365 case 0x02: 366 strcat(cpu_model, "486Se"); 367 break; 368 case 0x03: 369 strcat(cpu_model, "486S2e"); 370 break; 371 case 0x0a: 372 strcat(cpu_model, "486DX"); 373 break; 374 case 0x0b: 375 strcat(cpu_model, "486DX2"); 376 break; 377 case 0x0f: 378 strcat(cpu_model, "486DX4"); 379 break; 380 default: 381 strcat(cpu_model, "Unknown"); 382 break; 383 } 384 break; 385 case 0x20: 386 if ((cyrix_did & 0x0f) < 8) 387 strcat(cpu_model, "6x86"); /* Where did you get it? */ 388 else 389 strcat(cpu_model, "5x86"); 390 break; 391 case 0x30: 392 strcat(cpu_model, "6x86"); 393 break; 394 case 0x40: 395 if ((cyrix_did & 0xf000) == 0x3000) { 396 cpu_class = CPUCLASS_586; 397 strcat(cpu_model, "GXm"); 398 } else 399 strcat(cpu_model, "MediaGX"); 400 break; 401 case 0x50: 402 strcat(cpu_model, "6x86MX"); 403 break; 404 case 0xf0: 405 switch (cyrix_did & 0x0f) { 406 case 0x0d: 407 strcat(cpu_model, "Overdrive CPU"); 408 case 0x0e: 409 strcpy(cpu_model, "Texas Instruments 486SXL"); 410 break; 411 case 0x0f: 412 strcat(cpu_model, "486SLC/DLC"); 413 break; 414 default: 415 strcat(cpu_model, "Unknown"); 416 break; 417 } 418 break; 419 default: 420 strcat(cpu_model, "Unknown"); 421 break; 422 } 423 break; 424 } 425 } else if (strcmp(cpu_vendor,"IBM") == 0) 426 strcpy(cpu_model, "Blue Lightning CPU"); 427#endif 428 429 printf("%s (", cpu_model); 430 switch(cpu_class) { 431 case CPUCLASS_286: 432 printf("286"); 433 break; 434#if defined(I386_CPU) 435 case CPUCLASS_386: 436 printf("386"); 437 break; 438#endif 439#if defined(I486_CPU) 440 case CPUCLASS_486: 441 printf("486"); 442 bzero = i486_bzero; 443 break; 444#endif 445#if defined(I586_CPU) 446 case CPUCLASS_586: 447#ifndef SMP 448 printf("%d.%02d-MHz ", 449 (tsc_freq + 4999) / 1000000, 450 ((tsc_freq + 4999) / 10000) % 100); 451#endif 452 printf("586"); 453 break; 454#endif 455#if defined(I686_CPU) 456 case CPUCLASS_686: 457#ifndef SMP 458 printf("%d.%02d-MHz ", 459 (tsc_freq + 4999) / 1000000, 460 ((tsc_freq + 4999) / 10000) % 100); 461#endif 462 printf("686"); 463 break; 464#endif 465 default: 466 printf("unknown"); /* will panic below... */ 467 } 468 printf("-class CPU)\n"); 469#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 470 if(*cpu_vendor) 471 printf(" Origin = \"%s\"",cpu_vendor); 472 if(cpu_id) 473 printf(" Id = 0x%lx",cpu_id); 474 475 if (strcmp(cpu_vendor, "GenuineIntel") == 0 || 476 strcmp(cpu_vendor, "AuthenticAMD") == 0 || 477 ((strcmp(cpu_vendor, "CyrixInstead") == 0) && 478 ((cpu_id & 0xf00) > 5))) { 479 printf(" Stepping=%ld", cpu_id & 0xf); 480 if (strcmp(cpu_vendor, "CyrixInstead") == 0) 481 printf(" DIR=0x%04lx", cyrix_did); 482 if (cpu_high > 0) { 483 /* 484 * Here we should probably set up flags indicating 485 * whether or not various features are available. 486 * The interesting ones are probably VME, PSE, PAE, 487 * and PGE. The code already assumes without bothering 488 * to check that all CPUs >= Pentium have a TSC and 489 * MSRs. 490 */ 491 printf("\n Features=0x%b", cpu_feature, 492 "\020" 493 "\001FPU" 494 "\002VME" 495 "\003DE" 496 "\004PSE" 497 "\005TSC" 498 "\006MSR" 499 "\007PAE" 500 "\010MCE" 501 "\011CX8" 502 "\012APIC" 503 "\013oldMTRR" 504 "\014SEP" 505 "\015MTRR" 506 "\016PGE" 507 "\017MCA" 508 "\020CMOV" 509 "\021PAT" 510 "\022<b17>" 511 "\023<b18>" 512 "\024<b19>" 513 "\025<b20>" 514 "\026<b21>" 515 "\027<b22>" 516 "\030MMX" 517 "\031<b24>" 518 "\032<b25>" 519 "\033<b26>" 520 "\034<b27>" 521 "\035<b28>" 522 "\036<b29>" 523 "\037<b30>" 524 "\040<b31>" 525 ); 526 } 527 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) { 528 printf(" DIR=0x%04lx", cyrix_did); 529 printf(" Stepping=%ld", (cyrix_did & 0xf000) >> 12); 530 printf(" Revision=%ld", (cyrix_did & 0x0f00) >> 8); 531#ifndef CYRIX_CACHE_REALLY_WORKS 532 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700) 533 printf("\n CPU cache: write-through mode"); 534#endif 535 } 536 /* Avoid ugly blank lines: only print newline when we have to. */ 537 if (*cpu_vendor || cpu_id) 538 printf("\n"); 539 540#endif 541 if (!bootverbose) 542 return; 543 544 if (strcmp(cpu_vendor, "AuthenticAMD") == 0) 545 print_AMD_info(); 546#ifdef I686_CPU 547 /* 548 * XXX - Do PPro CPUID level=2 stuff here? 549 * 550 * No, but maybe in a print_Intel_info() function called from here. 551 */ 552#endif 553} 554 555void 556panicifcpuunsupported(void) 557{ 558 559 /* 560 * Now that we have told the user what they have, 561 * let them know if that machine type isn't configured. 562 */ 563 switch (cpu_class) { 564 case CPUCLASS_286: /* a 286 should not make it this far, anyway */ 565#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU) 566#error This kernel is not configured for one of the supported CPUs 567#endif 568#if !defined(I386_CPU) 569 case CPUCLASS_386: 570#endif 571#if !defined(I486_CPU) 572 case CPUCLASS_486: 573#endif 574#if !defined(I586_CPU) 575 case CPUCLASS_586: 576#endif 577#if !defined(I686_CPU) 578 case CPUCLASS_686: 579#endif 580 panic("CPU class not configured"); 581 default: 582 break; 583 } 584} 585 586 587static volatile u_int trap_by_rdmsr; 588 589/* 590 * Special exception 6 handler. 591 * The rdmsr instruction generates invalid opcodes fault on 486-class 592 * Cyrix CPU. Stacked eip register points the rdmsr instruction in the 593 * function identblue() when this handler is called. Stacked eip should 594 * be advanced. 595 */ 596inthand_t bluetrap6; 597__asm 598(" 599 .text 600 .p2align 2,0x90 601" __XSTRING(CNAME(bluetrap6)) ": 602 ss 603 movl $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) " 604 addl $2, (%esp) # I know rdmsr is a 2-bytes instruction. 605 iret 606"); 607 608/* 609 * Special exception 13 handler. 610 * Accessing non-existent MSR generates general protection fault. 611 */ 612inthand_t bluetrap13; 613__asm 614(" 615 .text 616 .p2align 2,0x90 617" __XSTRING(CNAME(bluetrap13)) ": 618 ss 619 movl $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) " 620 popl %eax # discard errorcode. 621 addl $2, (%esp) # I know rdmsr is a 2-bytes instruction. 622 iret 623"); 624 625/* 626 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not 627 * support cpuid instruction. This function should be called after 628 * loading interrupt descriptor table register. 629 * 630 * I don't like this method that handles fault, but I couldn't get 631 * information for any other methods. Does blue giant know? 632 */ 633static int 634identblue(void) 635{ 636 637 trap_by_rdmsr = 0; 638 639 /* 640 * Cyrix 486-class CPU does not support rdmsr instruction. 641 * The rdmsr instruction generates invalid opcode fault, and exception 642 * will be trapped by bluetrap6() on Cyrix 486-class CPU. The 643 * bluetrap6() set the magic number to trap_by_rdmsr. 644 */ 645 setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 646 647 /* 648 * Certain BIOS disables cpuid instructnion of Cyrix 6x86MX CPU. 649 * In this case, rdmsr generates general protection fault, and 650 * exception will be trapped by bluetrap13(). 651 */ 652 setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 653 654 rdmsr(0x1002); /* Cyrix CPU generates fault. */ 655 656 if (trap_by_rdmsr == 0xa8c1d) 657 return IDENTBLUE_CYRIX486; 658 else if (trap_by_rdmsr == 0xa89c4) 659 return IDENTBLUE_CYRIXM2; 660 return IDENTBLUE_IBMCPU; 661} 662 663 664/* 665 * identifycyrix() set lower 16 bits of cyrix_did as follows: 666 * 667 * F E D C B A 9 8 7 6 5 4 3 2 1 0 668 * +-------+-------+---------------+ 669 * | SID | RID | Device ID | 670 * | (DIR 1) | (DIR 0) | 671 * +-------+-------+---------------+ 672 */ 673static void 674identifycyrix(void) 675{ 676 u_long eflags; 677 int ccr2_test = 0, dir_test = 0; 678 u_char ccr2, ccr3; 679 680 eflags = read_eflags(); 681 disable_intr(); 682 683 ccr2 = read_cyrix_reg(CCR2); 684 write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW); 685 read_cyrix_reg(CCR2); 686 if (read_cyrix_reg(CCR2) != ccr2) 687 ccr2_test = 1; 688 write_cyrix_reg(CCR2, ccr2); 689 690 ccr3 = read_cyrix_reg(CCR3); 691 write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3); 692 read_cyrix_reg(CCR3); 693 if (read_cyrix_reg(CCR3) != ccr3) 694 dir_test = 1; /* CPU supports DIRs. */ 695 write_cyrix_reg(CCR3, ccr3); 696 697 if (dir_test) { 698 /* Device ID registers are available. */ 699 cyrix_did = read_cyrix_reg(DIR1) << 8; 700 cyrix_did += read_cyrix_reg(DIR0); 701 } else if (ccr2_test) 702 cyrix_did = 0x0010; /* 486S A-step */ 703 else 704 cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */ 705 706 write_eflags(eflags); 707} 708 709/* 710 * Final stage of CPU identification. -- Should I check TI? 711 */ 712void 713finishidentcpu(void) 714{ 715 int isblue = 0; 716 u_char ccr3; 717 u_long regs[4]; 718 719 if (strcmp(cpu_vendor, "CyrixInstead") == 0) { 720 if (cpu == CPU_486) { 721 /* 722 * These conditions are equivalent to: 723 * - CPU does not support cpuid instruction. 724 * - Cyrix/IBM CPU is detected. 725 */ 726 isblue = identblue(); 727 if (isblue == IDENTBLUE_IBMCPU) { 728 strcpy(cpu_vendor, "IBM"); 729 cpu = CPU_BLUE; 730 return; 731 } 732 } 733 switch (cpu_id & 0xf00) { 734 case 0x600: 735 /* 736 * Cyrix's datasheet does not describe DIRs. 737 * Therefor, I assume it does not have them 738 * and use the result of the cpuid instruction. 739 * XXX they seem to have it for now at least. -Peter 740 */ 741 identifycyrix(); 742 cpu = CPU_M2; 743 break; 744 default: 745 identifycyrix(); 746 /* 747 * This routine contains a trick. 748 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now. 749 */ 750 switch (cyrix_did & 0x00f0) { 751 case 0x00: 752 case 0xf0: 753 cpu = CPU_486DLC; 754 break; 755 case 0x10: 756 cpu = CPU_CY486DX; 757 break; 758 case 0x20: 759 if ((cyrix_did & 0x000f) < 8) 760 cpu = CPU_M1; 761 else 762 cpu = CPU_M1SC; 763 break; 764 case 0x30: 765 cpu = CPU_M1; 766 break; 767 case 0x40: 768 /* MediaGX CPU */ 769 cpu = CPU_M1SC; 770 break; 771 default: 772 /* M2 and later CPUs are treated as M2. */ 773 cpu = CPU_M2; 774 775 /* 776 * enable cpuid instruction. 777 */ 778 ccr3 = read_cyrix_reg(CCR3); 779 write_cyrix_reg(CCR3, CCR3_MAPEN0); 780 write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID); 781 write_cyrix_reg(CCR3, ccr3); 782 783 do_cpuid(0, regs); 784 cpu_high = regs[0]; /* eax */ 785 do_cpuid(1, regs); 786 cpu_id = regs[0]; /* eax */ 787 cpu_feature = regs[3]; /* edx */ 788 break; 789 } 790 } 791 } 792} 793 794/* 795 * This routine is called specifically to set up cpu_class before 796 * startrtclock() uses it. Probably this should be rearranged so that 797 * startrtclock() doesn't need to run until after identifycpu() has been 798 * called. Another alternative formulation would be for this routine 799 * to do all the identification work, and make identifycpu() into a 800 * printing-only routine. 801 */ 802void 803earlysetcpuclass(void) 804{ 805 806 cpu_class = i386_cpus[cpu].cpu_class; 807} 808 809static void 810print_AMD_assoc(int i) 811{ 812 if (i == 255) 813 printf(", fully associative\n"); 814 else 815 printf(", %d-way associative\n", i); 816} 817 818static void 819print_AMD_info(void) 820{ 821 u_long regs[4]; 822 823 do_cpuid(0x80000000, regs); 824 if (regs[0] >= 0x80000005) { 825 do_cpuid(0x80000005, regs); 826 printf("Data TLB: %d entries", (regs[1] >> 16) & 0xff); 827 print_AMD_assoc(regs[1] >> 24); 828 printf("Instruction TLB: %d entries", regs[1] & 0xff); 829 print_AMD_assoc((regs[1] >> 8) & 0xff); 830 printf("L1 data cache: %d kbytes", regs[2] >> 24); 831 printf(", %d bytes/line", regs[2] & 0xff); 832 printf(", %d lines/tag", (regs[2] >> 8) & 0xff); 833 print_AMD_assoc((regs[2] >> 16) & 0xff); 834 printf("L1 instruction cache: %d kbytes", regs[3] >> 24); 835 printf(", %d bytes/line", regs[3] & 0xff); 836 printf(", %d lines/tag", (regs[3] >> 8) & 0xff); 837 print_AMD_assoc((regs[3] >> 16) & 0xff); 838 } 839} 840