identcpu.c revision 25083
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 * 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 39 * $Id: identcpu.c,v 1.14 1997/03/22 18:51:57 kato Exp $ 40 */ 41 42#include "opt_cpu.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/sysproto.h> 47#include <sys/kernel.h> 48#include <sys/sysctl.h> 49 50#include <machine/asmacros.h> 51#include <machine/cpu.h> 52#include <machine/reg.h> 53#include <machine/psl.h> 54#include <machine/clock.h> 55#include <machine/specialreg.h> 56#include <machine/sysarch.h> 57#include <machine/md_var.h> 58 59#include <i386/isa/isa_device.h> 60 61/* XXX - should be in header file */ 62void i486_bzero __P((void *buf, size_t len)); 63 64void printcpuinfo(void); /* XXX should be in different header file */ 65void finishidentcpu(void); 66void earlysetcpuclass(void); 67void panicifcpuunsupported(void); 68static void identifycyrix(void); 69 70u_long cyrix_did; /* Device ID of Cyirx CPU */ 71int cpu_class = CPUCLASS_386; /* least common denominator */ 72char machine[] = "i386"; 73SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD, machine, 0, ""); 74 75static char cpu_model[128]; 76SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD, cpu_model, 0, ""); 77 78static struct cpu_nameclass i386_cpus[] = { 79 { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */ 80 { "i386SX", CPUCLASS_386 }, /* CPU_386SX */ 81 { "i386DX", CPUCLASS_386 }, /* CPU_386 */ 82 { "i486SX", CPUCLASS_486 }, /* CPU_486SX */ 83 { "i486DX", CPUCLASS_486 }, /* CPU_486 */ 84 { "Pentium", CPUCLASS_586 }, /* CPU_586 */ 85 { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */ 86 { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */ 87 { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */ 88 { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */ 89 { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */ 90 { "Cyrix 6x86 MMX", CPUCLASS_586 }, /* CPU_M2 (XXX) */ 91 { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */ 92}; 93 94void 95printcpuinfo(void) 96{ 97 98 cpu_class = i386_cpus[cpu].cpu_class; 99 printf("CPU: "); 100 strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof cpu_model); 101 102#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 103 if (strcmp(cpu_vendor,"GenuineIntel") == 0) { 104 if ((cpu_id & 0xf00) > 3) { 105 cpu_model[0] = '\0'; 106 107 switch (cpu_id & 0x3000) { 108 case 0x1000: 109 strcpy(cpu_model, "Overdrive "); 110 break; 111 case 0x2000: 112 strcpy(cpu_model, "Dual "); 113 break; 114 } 115 116 switch (cpu_id & 0xf00) { 117 case 0x400: 118 strcat(cpu_model, "i486 "); 119 break; 120 case 0x500: 121 strcat(cpu_model, "Pentium"); /* nb no space */ 122 break; 123 case 0x600: 124 strcat(cpu_model, "Pentium Pro"); 125 break; 126 default: 127 strcat(cpu_model, "unknown"); 128 break; 129 } 130 131 switch (cpu_id & 0xff0) { 132 case 0x400: 133 strcat(cpu_model, "DX"); break; 134 case 0x410: 135 strcat(cpu_model, "DX"); break; 136 case 0x420: 137 strcat(cpu_model, "SX"); break; 138 case 0x430: 139 strcat(cpu_model, "DX2"); break; 140 case 0x440: 141 strcat(cpu_model, "SL"); break; 142 case 0x450: 143 strcat(cpu_model, "SX2"); break; 144 case 0x470: 145 strcat(cpu_model, "DX2 Write-Back Enhanced"); 146 break; 147 case 0x480: 148 strcat(cpu_model, "DX4"); break; 149 break; 150 } 151 } 152 } else if (strcmp(cpu_vendor,"AuthenticAMD") == 0) { 153 /* 154 * Values taken from AMD Processor Recognition 155 * http://www.amd.com/html/products/pcd/techdocs/appnotes/20734c.pdf 156 */ 157 strcpy(cpu_model, "AMD "); 158 switch (cpu_id & 0xFF0) { 159 case 0x4E0: 160 strcat(cpu_model, "Am5x86 Write-Through"); 161 break; 162 case 0x4F0: 163 strcat(cpu_model, "Am5x86 Write-Back"); 164 break; 165 case 0x500: 166 strcat(cpu_model, "K5 model 0"); 167 break; 168 case 0x510: 169 strcat(cpu_model, "K5 model 1"); 170 break; 171 case 0x560: 172 strcat(cpu_model, "K6"); 173 break; 174 default: 175 strcat(cpu_model, "Unknown"); 176 break; 177 } 178 } else if (strcmp(cpu_vendor,"CyrixInstead") == 0) { 179 strcpy(cpu_model, "Cyrix "); 180 switch (cyrix_did & 0xf0) { 181 case 0x00: 182 switch (cyrix_did & 0x0f) { 183 case 0x00: 184 strcat(cpu_model, "486SLC"); 185 break; 186 case 0x01: 187 strcat(cpu_model, "486DLC"); 188 break; 189 case 0x02: 190 strcat(cpu_model, "486SLC2"); 191 break; 192 case 0x03: 193 strcat(cpu_model, "486DLC2"); 194 break; 195 case 0x04: 196 strcat(cpu_model, "486SRx"); 197 break; 198 case 0x05: 199 strcat(cpu_model, "486DRx"); 200 break; 201 case 0x06: 202 strcat(cpu_model, "486SRx2"); 203 break; 204 case 0x07: 205 strcat(cpu_model, "486DRx2"); 206 break; 207 case 0x08: 208 strcat(cpu_model, "486SRu"); 209 break; 210 case 0x09: 211 strcat(cpu_model, "486DRu"); 212 break; 213 case 0x0a: 214 strcat(cpu_model, "486SRu2"); 215 break; 216 case 0x0b: 217 strcat(cpu_model, "486DRu2"); 218 break; 219 default: 220 strcat(cpu_model, "Unknown"); 221 break; 222 } 223 break; 224 case 0x10: 225 switch (cyrix_did & 0x0f) { 226 case 0x00: 227 strcat(cpu_model, "486S"); 228 break; 229 case 0x01: 230 strcat(cpu_model, "486S2"); 231 break; 232 case 0x02: 233 strcat(cpu_model, "486Se"); 234 break; 235 case 0x03: 236 strcat(cpu_model, "486S2e"); 237 break; 238 case 0x0a: 239 strcat(cpu_model, "486DX"); 240 break; 241 case 0x0b: 242 strcat(cpu_model, "486DX2"); 243 break; 244 case 0x0f: 245 strcat(cpu_model, "486DX4"); 246 break; 247 default: 248 strcat(cpu_model, "Unknown"); 249 break; 250 } 251 break; 252 case 0x20: 253 if ((cyrix_did & 0x0f) < 8) 254 strcat(cpu_model, "6x86"); /* Where did you get it? */ 255 else 256 strcat(cpu_model, "5x86"); 257 break; 258 case 0x30: 259 strcat(cpu_model, "6x86"); 260 break; 261 case 0x40: 262 /* XXX */ 263 strcat(cpu_model, "Gx86"); 264 break; 265 case 0x50: 266 strcat(cpu_model, "Enhanced 6x86 with MMX"); 267 break; 268 case 0xf0: 269 switch (cyrix_did & 0x0f) { 270 case 0x0d: 271 strcat(cpu_model, "Overdrive CPU"); 272 case 0x0e: 273 strcpy(cpu_model, "Texas Instruments 486SXL"); 274 break; 275 case 0x0f: 276 strcat(cpu_model, "486SLC/DLC"); 277 break; 278 default: 279 strcat(cpu_model, "Unknown"); 280 break; 281 } 282 break; 283 default: 284 strcat(cpu_model, "Unknown"); 285 break; 286 } 287 } else if (strcmp(cpu_vendor,"IBM") == 0) 288 strcpy(cpu_model, "Blue Lightning CPU"); 289#endif 290 291 printf("%s (", cpu_model); 292 switch(cpu_class) { 293 case CPUCLASS_286: 294 printf("286"); 295 break; 296#if defined(I386_CPU) 297 case CPUCLASS_386: 298 printf("386"); 299 break; 300#endif 301#if defined(I486_CPU) 302 case CPUCLASS_486: 303 printf("486"); 304 bzero = i486_bzero; 305 break; 306#endif 307#if defined(I586_CPU) 308 case CPUCLASS_586: 309 printf("%d.%02d-MHz ", 310 (i586_ctr_freq + 4999) / 1000000, 311 ((i586_ctr_freq + 4999) / 10000) % 100); 312 printf("586"); 313 break; 314#endif 315#if defined(I686_CPU) 316 case CPUCLASS_686: 317 printf("%d.%02d-MHz ", 318 (i586_ctr_freq + 4999) / 1000000, 319 ((i586_ctr_freq + 4999) / 10000) % 100); 320 printf("686"); 321 break; 322#endif 323 default: 324 printf("unknown"); /* will panic below... */ 325 } 326 printf("-class CPU)\n"); 327#if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU) 328 if(*cpu_vendor) 329 printf(" Origin = \"%s\"",cpu_vendor); 330 if(cpu_id) 331 printf(" Id = 0x%lx",cpu_id); 332 333 if (strcmp(cpu_vendor, "GenuineIntel") == 0 || 334 strcmp(cpu_vendor, "AuthenticAMD") == 0) { 335 printf(" Stepping=%ld", cpu_id & 0xf); 336 if (cpu_high > 0) { 337 /* 338 * Here we should probably set up flags indicating 339 * whether or not various features are available. 340 * The interesting ones are probably VME, PSE, PAE, 341 * and PGE. The code already assumes without bothering 342 * to check that all CPUs >= Pentium have a TSC and 343 * MSRs. 344 */ 345 printf("\n Features=0x%b", cpu_feature, 346 "\020" 347 "\001FPU" 348 "\002VME" 349 "\003DE" 350 "\004PSE" 351 "\005TSC" 352 "\006MSR" 353 "\007PAE" 354 "\010MCE" 355 "\011CX8" 356 "\012APIC" 357 "\013<b10>" 358 "\014<b11>" 359 "\015MTRR" 360 "\016PGE" 361 "\017MCA" 362 "\020CMOV" 363 ); 364 } 365 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) { 366 printf(" Device ID = 0x%lx", cyrix_did); 367 printf(" Stepping=%ld", (cyrix_did & 0xf000) >> 12); 368 printf(" Revision=%ld", (cyrix_did & 0x0fff) >> 8); 369#ifndef CYRIX_CACHE_REALLY_WORKS 370 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700) 371 printf("\n CPU cache: write-through mode"); 372#endif 373 } 374 /* Avoid ugly blank lines: only print newline when we have to. */ 375 if (*cpu_vendor || cpu_id) 376 printf("\n"); 377#endif 378#ifdef I686_CPU 379 /* 380 * XXX - Do PPro CPUID level=2 stuff here? 381 */ 382#endif 383} 384 385void 386panicifcpuunsupported(void) 387{ 388 389 /* 390 * Now that we have told the user what they have, 391 * let them know if that machine type isn't configured. 392 */ 393 switch (cpu_class) { 394 case CPUCLASS_286: /* a 286 should not make it this far, anyway */ 395#if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU) 396#error This kernel is not configured for one of the supported CPUs 397#endif 398#if !defined(I386_CPU) 399 case CPUCLASS_386: 400#endif 401#if !defined(I486_CPU) 402 case CPUCLASS_486: 403#endif 404#if !defined(I586_CPU) 405 case CPUCLASS_586: 406#endif 407#if !defined(I686_CPU) 408 case CPUCLASS_686: 409#endif 410 panic("CPU class not configured"); 411 default: 412 break; 413 } 414} 415 416 417static volatile u_int trap_by_wrmsr; 418 419/* 420 * Special exception 16 handler. 421 * The wrmsr instruction generates invalid opcodes fault on 486-class 422 * Cyrix CPU. Stacked eip register points the wrmsr instruction in the 423 * function identblue() when this handler is called. Stacked eip should 424 * be advanced. 425 */ 426inthand_t bluetrap; 427asm 428(" 429 .text 430 .p2align 2,0x90 431" __XSTRING(CNAME(bluetrap)) ": 432 ss 433 movl $0xa8c1d," __XSTRING(CNAME(trap_by_wrmsr)) " # Don't ask meaning of the number :-). 434 addl $2, (%esp) # I know wrmsr is a 2-bytes instruction. 435 iret 436"); 437 438/* 439 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not 440 * support cpuid instruction. This function should be called after 441 * loading interrupt descriptor table register. 442 * 443 * I don't like this method that handles fault, but I couldn't get 444 * information for any other methods. Does blue giant know? 445 */ 446static int 447identblue(void) 448{ 449 450 trap_by_wrmsr = 0; 451 /* 452 * Cyrix 486-class CPU does not support wrmsr instruction. 453 * The wrmsr instruction causes invalid opcode fault, and exception 454 * will be trapped by bluetrap() on Cyrix 486-class CPU. The bluetrap() 455 * set the magic number to tra_by_wrmsr. 456 */ 457 setidt(6, bluetrap, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL)); 458 wrmsr(0x1002, 0x03000000LL); /* Fault on Cyrix 486-class CPU. */ 459 460 if (trap_by_wrmsr == 0xa8c1d) 461 return 0; /* Cyrix CPU sets the magic number. */ 462 463 return 1; /* IBM Blue Lightnig CPU */ 464} 465 466 467/* 468 * identifycyrix() set lower 16 bits of cyrix_did as follows: 469 * 470 * F E D C B A 9 8 7 6 5 4 3 2 1 0 471 * +-------+-------+---------------+ 472 * | SID | RID | Device ID | 473 * | (DIR 1) | (DIR 0) | 474 * +-------+-------+---------------+ 475 */ 476static void 477identifycyrix(void) 478{ 479 u_long eflags; 480 int ccr2_test = 0, dir_test = 0; 481 u_char ccr2, ccr3; 482 483 eflags = read_eflags(); 484 disable_intr(); 485 486 ccr2 = read_cyrix_reg(CCR2); 487 write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW); 488 read_cyrix_reg(CCR2); 489 if (read_cyrix_reg(CCR2) != ccr2) 490 ccr2_test = 1; 491 write_cyrix_reg(CCR2, ccr2); 492 493 ccr3 = read_cyrix_reg(CCR3); 494 write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3); 495 read_cyrix_reg(CCR3); 496 if (read_cyrix_reg(CCR3) != ccr3) 497 dir_test = 1; /* CPU supports DIRs. */ 498 write_cyrix_reg(CCR3, ccr3); 499 500 if (dir_test) { 501 /* Device ID registers are available. */ 502 cyrix_did = read_cyrix_reg(DIR1) << 8; 503 cyrix_did += read_cyrix_reg(DIR0); 504 } else if (ccr2_test) 505 cyrix_did = 0x0010; /* 486S A-step */ 506 else 507 cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */ 508 509 write_eflags(eflags); 510} 511 512/* 513 * Final stage of CPU identification. -- Should I check TI? 514 */ 515void 516finishidentcpu(void) 517{ 518 519 if (strcmp(cpu_vendor, "CyrixInstead") == 0) { 520 if (cpu == CPU_486) { 521 /* 522 * These conditions are equivalent to: 523 * - CPU does not support cpuid instruction. 524 * - Cyrix/IBM CPU is detected. 525 */ 526 if (identblue()) { 527 strcpy(cpu_vendor, "IBM"); 528 cpu = CPU_BLUE; 529 return; 530 } 531 } 532 identifycyrix(); 533 /* 534 * This routine contains a trick. 535 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now. 536 */ 537 switch (cyrix_did & 0x00f0) { 538 case 0x00: 539 case 0x10: 540 case 0xf0: 541 cpu = CPU_486DLC; 542 break; 543 case 0x20: 544 if ((cyrix_did & 0x00f0) < 8) 545 cpu = CPU_M1; 546 else 547 cpu = CPU_M1SC; 548 break; 549 case 0x30: 550 cpu = CPU_M1; 551 break; 552 case 0x40: 553 cpu = CPU_M1SC; 554 break; 555 default: 556 /* M2 and later CPUs are treated as M2. */ 557 cpu = CPU_M2; 558 break; 559 } 560 } 561} 562 563/* 564 * This routine is called specifically to set up cpu_class before 565 * startrtclock() uses it. Probably this should be rearranged so that 566 * startrtclock() doesn't need to run until after identifycpu() has been 567 * called. Another alternative formulation would be for this routine 568 * to do all the identification work, and make identifycpu() into a 569 * printing-only routine. 570 */ 571void 572earlysetcpuclass(void) 573{ 574 575 cpu_class = i386_cpus[cpu].cpu_class; 576} 577