1 /*
2 * Copyright (c) 1992 Terrence R. Lambert.
3 * Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
4 * Copyright (c) 1997 KATO Takenori.
5 * Copyright (c) 2001 Tamotsu Hattori.
6 * Copyright (c) 2001 Mitsuru IWASAKI.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * from: Id: machdep.c,v 1.193 1996/06/18 01:22:04 bde Exp
41 * $FreeBSD$
42 */
43
44 #include "opt_cpu.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/sysctl.h>
50
51 #include <machine/asmacros.h>
52 #include <machine/clock.h>
53 #include <machine/cputypes.h>
54 #include <machine/segments.h>
55 #include <machine/specialreg.h>
56 #include <machine/md_var.h>
57
58 #include <i386/isa/intr_machdep.h>
59
60 #define IDENTBLUE_CYRIX486 0
61 #define IDENTBLUE_IBMCPU 1
62 #define IDENTBLUE_CYRIXM2 2
63
64 /* XXX - should be in header file: */
65 void printcpuinfo(void);
66 void finishidentcpu(void);
67 #if defined(I586_CPU) && defined(CPU_WT_ALLOC)
68 void enable_K5_wt_alloc(void);
69 void enable_K6_wt_alloc(void);
70 void enable_K6_2_wt_alloc(void);
71 #endif
72 void panicifcpuunsupported(void);
73
74 static void identifycyrix(void);
75 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
76 static void print_AMD_features(void);
77 #endif
78 static void print_AMD_info(void);
79 static void print_AMD_assoc(int i);
80 static void print_transmeta_info(void);
81 static void setup_tmx86_longrun(void);
82
83 int cpu_class = CPUCLASS_386;
84 u_int cpu_exthigh; /* Highest arg to extended CPUID */
85 u_int cyrix_did; /* Device ID of Cyrix CPU */
86 char machine[] = "i386";
87 SYSCTL_STRING(_hw, HW_MACHINE, machine, CTLFLAG_RD,
88 machine, 0, "Machine class");
89
90 static char cpu_model[128];
91 SYSCTL_STRING(_hw, HW_MODEL, model, CTLFLAG_RD,
92 cpu_model, 0, "Machine model");
93
94 static char cpu_brand[48];
95
96 #define MAX_BRAND_INDEX 8
97
98 static const char *cpu_brandtable[MAX_BRAND_INDEX + 1] = {
99 NULL, /* No brand */
100 "Intel Celeron",
101 "Intel Pentium III",
102 "Intel Pentium III Xeon",
103 NULL,
104 NULL,
105 NULL,
106 NULL,
107 "Intel Pentium 4"
108 };
109
110 static struct cpu_nameclass i386_cpus[] = {
111 { "Intel 80286", CPUCLASS_286 }, /* CPU_286 */
112 { "i386SX", CPUCLASS_386 }, /* CPU_386SX */
113 { "i386DX", CPUCLASS_386 }, /* CPU_386 */
114 { "i486SX", CPUCLASS_486 }, /* CPU_486SX */
115 { "i486DX", CPUCLASS_486 }, /* CPU_486 */
116 { "Pentium", CPUCLASS_586 }, /* CPU_586 */
117 { "Cyrix 486", CPUCLASS_486 }, /* CPU_486DLC */
118 { "Pentium Pro", CPUCLASS_686 }, /* CPU_686 */
119 { "Cyrix 5x86", CPUCLASS_486 }, /* CPU_M1SC */
120 { "Cyrix 6x86", CPUCLASS_486 }, /* CPU_M1 */
121 { "Blue Lightning", CPUCLASS_486 }, /* CPU_BLUE */
122 { "Cyrix 6x86MX", CPUCLASS_686 }, /* CPU_M2 */
123 { "NexGen 586", CPUCLASS_386 }, /* CPU_NX586 (XXX) */
124 { "Cyrix 486S/DX", CPUCLASS_486 }, /* CPU_CY486DX */
125 { "Pentium II", CPUCLASS_686 }, /* CPU_PII */
126 { "Pentium III", CPUCLASS_686 }, /* CPU_PIII */
127 { "Pentium 4", CPUCLASS_686 }, /* CPU_P4 */
128 };
129
130 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
131 int has_f00f_bug = 0; /* Initialized so that it can be patched. */
132 #endif
133
134 void
135 printcpuinfo(void)
136 {
137 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
138 u_int regs[4], i;
139 #endif
140 char *brand;
141
142 cpu_class = i386_cpus[cpu].cpu_class;
143 printf("CPU: ");
144 strncpy(cpu_model, i386_cpus[cpu].cpu_name, sizeof (cpu_model));
145
146 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
147 /* Check for extended CPUID information and a processor name. */
148 if (cpu_high > 0 &&
149 (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
150 strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
151 strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
152 strcmp(cpu_vendor, "TransmetaCPU") == 0)) {
153 do_cpuid(0x80000000, regs);
154 if (regs[0] >= 0x80000000) {
155 cpu_exthigh = regs[0];
156 if (cpu_exthigh >= 0x80000004) {
157 brand = cpu_brand;
158 for (i = 0x80000002; i < 0x80000005; i++) {
159 do_cpuid(i, regs);
160 memcpy(brand, regs, sizeof(regs));
161 brand += sizeof(regs);
162 }
163 }
164 }
165 }
166
167 if (strcmp(cpu_vendor, "GenuineIntel") == 0) {
168 if ((cpu_id & 0xf00) > 0x300) {
169 u_int brand_index;
170
171 cpu_model[0] = '\0';
172
173 switch (cpu_id & 0x3000) {
174 case 0x1000:
175 strcpy(cpu_model, "Overdrive ");
176 break;
177 case 0x2000:
178 strcpy(cpu_model, "Dual ");
179 break;
180 }
181
182 switch (cpu_id & 0xf00) {
183 case 0x400:
184 strcat(cpu_model, "i486 ");
185 /* Check the particular flavor of 486 */
186 switch (cpu_id & 0xf0) {
187 case 0x00:
188 case 0x10:
189 strcat(cpu_model, "DX");
190 break;
191 case 0x20:
192 strcat(cpu_model, "SX");
193 break;
194 case 0x30:
195 strcat(cpu_model, "DX2");
196 break;
197 case 0x40:
198 strcat(cpu_model, "SL");
199 break;
200 case 0x50:
201 strcat(cpu_model, "SX2");
202 break;
203 case 0x70:
204 strcat(cpu_model,
205 "DX2 Write-Back Enhanced");
206 break;
207 case 0x80:
208 strcat(cpu_model, "DX4");
209 break;
210 }
211 break;
212 case 0x500:
213 /* Check the particular flavor of 586 */
214 strcat(cpu_model, "Pentium");
215 switch (cpu_id & 0xf0) {
216 case 0x00:
217 strcat(cpu_model, " A-step");
218 break;
219 case 0x10:
220 strcat(cpu_model, "/P5");
221 break;
222 case 0x20:
223 strcat(cpu_model, "/P54C");
224 break;
225 case 0x30:
226 strcat(cpu_model, "/P54T Overdrive");
227 break;
228 case 0x40:
229 strcat(cpu_model, "/P55C");
230 break;
231 case 0x70:
232 strcat(cpu_model, "/P54C");
233 break;
234 case 0x80:
235 strcat(cpu_model, "/P55C (quarter-micron)");
236 break;
237 default:
238 /* nothing */
239 break;
240 }
241 #if defined(I586_CPU) && !defined(NO_F00F_HACK)
242 /*
243 * XXX - If/when Intel fixes the bug, this
244 * should also check the version of the
245 * CPU, not just that it's a Pentium.
246 */
247 has_f00f_bug = 1;
248 #endif
249 break;
250 case 0x600:
251 /* Check the particular flavor of 686 */
252 switch (cpu_id & 0xf0) {
253 case 0x00:
254 strcat(cpu_model, "Pentium Pro A-step");
255 break;
256 case 0x10:
257 strcat(cpu_model, "Pentium Pro");
258 break;
259 case 0x30:
260 case 0x50:
261 case 0x60:
262 strcat(cpu_model,
263 "Pentium II/Pentium II Xeon/Celeron");
264 cpu = CPU_PII;
265 break;
266 case 0x70:
267 case 0x80:
268 case 0xa0:
269 case 0xb0:
270 strcat(cpu_model,
271 "Pentium III/Pentium III Xeon/Celeron");
272 cpu = CPU_PIII;
273 break;
274 default:
275 strcat(cpu_model, "Unknown 80686");
276 break;
277 }
278 break;
279 case 0xf00:
280 strcat(cpu_model, "Pentium 4");
281 cpu = CPU_P4;
282 break;
283 default:
284 strcat(cpu_model, "unknown");
285 break;
286 }
287
288 /*
289 * If we didn't get a brand name from the extended
290 * CPUID, try to look it up in the brand table.
291 */
292 if (cpu_high > 0 && *cpu_brand == '\0') {
293 brand_index = cpu_procinfo & CPUID_BRAND_INDEX;
294 if (brand_index <= MAX_BRAND_INDEX &&
295 cpu_brandtable[brand_index] != NULL)
296 strcpy(cpu_brand,
297 cpu_brandtable[brand_index]);
298 }
299 }
300 } else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
301 /*
302 * Values taken from AMD Processor Recognition
303 * http://www.amd.com/K6/k6docs/pdf/20734g.pdf
304 * (also describes ``Features'' encodings.
305 */
306 strcpy(cpu_model, "AMD ");
307 switch (cpu_id & 0xFF0) {
308 case 0x410:
309 strcat(cpu_model, "Standard Am486DX");
310 break;
311 case 0x430:
312 strcat(cpu_model, "Enhanced Am486DX2 Write-Through");
313 break;
314 case 0x470:
315 strcat(cpu_model, "Enhanced Am486DX2 Write-Back");
316 break;
317 case 0x480:
318 strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Through");
319 break;
320 case 0x490:
321 strcat(cpu_model, "Enhanced Am486DX4/Am5x86 Write-Back");
322 break;
323 case 0x4E0:
324 strcat(cpu_model, "Am5x86 Write-Through");
325 break;
326 case 0x4F0:
327 strcat(cpu_model, "Am5x86 Write-Back");
328 break;
329 case 0x500:
330 strcat(cpu_model, "K5 model 0");
331 tsc_is_broken = 1;
332 break;
333 case 0x510:
334 strcat(cpu_model, "K5 model 1");
335 break;
336 case 0x520:
337 strcat(cpu_model, "K5 PR166 (model 2)");
338 break;
339 case 0x530:
340 strcat(cpu_model, "K5 PR200 (model 3)");
341 break;
342 case 0x560:
343 strcat(cpu_model, "K6");
344 break;
345 case 0x570:
346 strcat(cpu_model, "K6 266 (model 1)");
347 break;
348 case 0x580:
349 strcat(cpu_model, "K6-2");
350 break;
351 case 0x590:
352 strcat(cpu_model, "K6-III");
353 break;
354 default:
355 strcat(cpu_model, "Unknown");
356 break;
357 }
358 #if defined(I586_CPU) && defined(CPU_WT_ALLOC)
359 if ((cpu_id & 0xf00) == 0x500) {
360 if (((cpu_id & 0x0f0) > 0)
361 && ((cpu_id & 0x0f0) < 0x60)
362 && ((cpu_id & 0x00f) > 3))
363 enable_K5_wt_alloc();
364 else if (((cpu_id & 0x0f0) > 0x80)
365 || (((cpu_id & 0x0f0) == 0x80)
366 && (cpu_id & 0x00f) > 0x07))
367 enable_K6_2_wt_alloc();
368 else if ((cpu_id & 0x0f0) > 0x50)
369 enable_K6_wt_alloc();
370 }
371 #endif
372 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
373 strcpy(cpu_model, "Cyrix ");
374 switch (cpu_id & 0xff0) {
375 case 0x440:
376 strcat(cpu_model, "MediaGX");
377 break;
378 case 0x520:
379 strcat(cpu_model, "6x86");
380 break;
381 case 0x540:
382 cpu_class = CPUCLASS_586;
383 strcat(cpu_model, "GXm");
384 break;
385 case 0x600:
386 strcat(cpu_model, "6x86MX");
387 break;
388 default:
389 /*
390 * Even though CPU supports the cpuid
391 * instruction, it can be disabled.
392 * Therefore, this routine supports all Cyrix
393 * CPUs.
394 */
395 switch (cyrix_did & 0xf0) {
396 case 0x00:
397 switch (cyrix_did & 0x0f) {
398 case 0x00:
399 strcat(cpu_model, "486SLC");
400 break;
401 case 0x01:
402 strcat(cpu_model, "486DLC");
403 break;
404 case 0x02:
405 strcat(cpu_model, "486SLC2");
406 break;
407 case 0x03:
408 strcat(cpu_model, "486DLC2");
409 break;
410 case 0x04:
411 strcat(cpu_model, "486SRx");
412 break;
413 case 0x05:
414 strcat(cpu_model, "486DRx");
415 break;
416 case 0x06:
417 strcat(cpu_model, "486SRx2");
418 break;
419 case 0x07:
420 strcat(cpu_model, "486DRx2");
421 break;
422 case 0x08:
423 strcat(cpu_model, "486SRu");
424 break;
425 case 0x09:
426 strcat(cpu_model, "486DRu");
427 break;
428 case 0x0a:
429 strcat(cpu_model, "486SRu2");
430 break;
431 case 0x0b:
432 strcat(cpu_model, "486DRu2");
433 break;
434 default:
435 strcat(cpu_model, "Unknown");
436 break;
437 }
438 break;
439 case 0x10:
440 switch (cyrix_did & 0x0f) {
441 case 0x00:
442 strcat(cpu_model, "486S");
443 break;
444 case 0x01:
445 strcat(cpu_model, "486S2");
446 break;
447 case 0x02:
448 strcat(cpu_model, "486Se");
449 break;
450 case 0x03:
451 strcat(cpu_model, "486S2e");
452 break;
453 case 0x0a:
454 strcat(cpu_model, "486DX");
455 break;
456 case 0x0b:
457 strcat(cpu_model, "486DX2");
458 break;
459 case 0x0f:
460 strcat(cpu_model, "486DX4");
461 break;
462 default:
463 strcat(cpu_model, "Unknown");
464 break;
465 }
466 break;
467 case 0x20:
468 if ((cyrix_did & 0x0f) < 8)
469 strcat(cpu_model, "6x86"); /* Where did you get it? */
470 else
471 strcat(cpu_model, "5x86");
472 break;
473 case 0x30:
474 strcat(cpu_model, "6x86");
475 break;
476 case 0x40:
477 if ((cyrix_did & 0xf000) == 0x3000) {
478 cpu_class = CPUCLASS_586;
479 strcat(cpu_model, "GXm");
480 } else
481 strcat(cpu_model, "MediaGX");
482 break;
483 case 0x50:
484 strcat(cpu_model, "6x86MX");
485 break;
486 case 0xf0:
487 switch (cyrix_did & 0x0f) {
488 case 0x0d:
489 strcat(cpu_model, "Overdrive CPU");
490 case 0x0e:
491 strcpy(cpu_model, "Texas Instruments 486SXL");
492 break;
493 case 0x0f:
494 strcat(cpu_model, "486SLC/DLC");
495 break;
496 default:
497 strcat(cpu_model, "Unknown");
498 break;
499 }
500 break;
501 default:
502 strcat(cpu_model, "Unknown");
503 break;
504 }
505 break;
506 }
507 } else if (strcmp(cpu_vendor, "RiseRiseRise") == 0) {
508 strcpy(cpu_model, "Rise ");
509 switch (cpu_id & 0xff0) {
510 case 0x500:
511 strcat(cpu_model, "mP6");
512 break;
513 default:
514 strcat(cpu_model, "Unknown");
515 }
516 } else if (strcmp(cpu_vendor, "CentaurHauls") == 0) {
517 switch (cpu_id & 0xff0) {
518 case 0x540:
519 strcpy(cpu_model, "IDT WinChip C6");
520 tsc_is_broken = 1;
521 break;
522 case 0x580:
523 strcpy(cpu_model, "IDT WinChip 2");
524 break;
525 case 0x660:
526 strcpy(cpu_model, "VIA C3 Samuel");
527 break;
528 case 0x670:
529 if (cpu_id & 0x8)
530 strcpy(cpu_model, "VIA C3 Ezra");
531 else
532 strcpy(cpu_model, "VIA C3 Samuel 2");
533 break;
534 case 0x680:
535 strcpy(cpu_model, "VIA C3 Ezra-T");
536 break;
537 case 0x690:
538 strcpy(cpu_model, "VIA C3 Nehemiah");
539 break;
540 default:
541 strcpy(cpu_model, "VIA/IDT Unknown");
542 }
543 } else if (strcmp(cpu_vendor, "IBM") == 0) {
544 strcpy(cpu_model, "Blue Lightning CPU");
545 }
546
547 /*
548 * Replace cpu_model with cpu_brand minus leading spaces if
549 * we have one.
550 */
551 brand = cpu_brand;
552 while (*brand == ' ')
553 ++brand;
554 if (*brand != '\0')
555 strcpy(cpu_model, brand);
556
557 #endif
558
559 printf("%s (", cpu_model);
560 switch(cpu_class) {
561 case CPUCLASS_286:
562 printf("286");
563 break;
564 #if defined(I386_CPU)
565 case CPUCLASS_386:
566 printf("386");
567 break;
568 #endif
569 #if defined(I486_CPU)
570 case CPUCLASS_486:
571 printf("486");
572 bzero = i486_bzero;
573 break;
574 #endif
575 #if defined(I586_CPU)
576 case CPUCLASS_586:
577 printf("%d.%02d-MHz ",
578 (tsc_freq + 4999) / 1000000,
579 ((tsc_freq + 4999) / 10000) % 100);
580 printf("586");
581 break;
582 #endif
583 #if defined(I686_CPU)
584 case CPUCLASS_686:
585 printf("%d.%02d-MHz ",
586 (tsc_freq + 4999) / 1000000,
587 ((tsc_freq + 4999) / 10000) % 100);
588 printf("686");
589 break;
590 #endif
591 default:
592 printf("Unknown"); /* will panic below... */
593 }
594 printf("-class CPU)\n");
595 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
596 if(*cpu_vendor)
597 printf(" Origin = \"%s\"",cpu_vendor);
598 if(cpu_id)
599 printf(" Id = 0x%x", cpu_id);
600
601 if (strcmp(cpu_vendor, "GenuineIntel") == 0 ||
602 strcmp(cpu_vendor, "AuthenticAMD") == 0 ||
603 strcmp(cpu_vendor, "RiseRiseRise") == 0 ||
604 strcmp(cpu_vendor, "CentaurHauls") == 0 ||
605 ((strcmp(cpu_vendor, "CyrixInstead") == 0) &&
606 ((cpu_id & 0xf00) > 0x500))) {
607 printf(" Stepping = %u", cpu_id & 0xf);
608 if (strcmp(cpu_vendor, "CyrixInstead") == 0)
609 printf(" DIR=0x%04x", cyrix_did);
610 if (cpu_high > 0) {
611 /*
612 * Here we should probably set up flags indicating
613 * whether or not various features are available.
614 * The interesting ones are probably VME, PSE, PAE,
615 * and PGE. The code already assumes without bothering
616 * to check that all CPUs >= Pentium have a TSC and
617 * MSRs.
618 */
619 printf("\n Features=0x%b", cpu_feature,
620 "\020"
621 "\001FPU" /* Integral FPU */
622 "\002VME" /* Extended VM86 mode support */
623 "\003DE" /* Debugging Extensions (CR4.DE) */
624 "\004PSE" /* 4MByte page tables */
625 "\005TSC" /* Timestamp counter */
626 "\006MSR" /* Machine specific registers */
627 "\007PAE" /* Physical address extension */
628 "\010MCE" /* Machine Check support */
629 "\011CX8" /* CMPEXCH8 instruction */
630 "\012APIC" /* SMP local APIC */
631 "\013oldMTRR" /* Previous implementation of MTRR */
632 "\014SEP" /* Fast System Call */
633 "\015MTRR" /* Memory Type Range Registers */
634 "\016PGE" /* PG_G (global bit) support */
635 "\017MCA" /* Machine Check Architecture */
636 "\020CMOV" /* CMOV instruction */
637 "\021PAT" /* Page attributes table */
638 "\022PSE36" /* 36 bit address space support */
639 "\023PN" /* Processor Serial number */
640 "\024CLFLUSH" /* Has the CLFLUSH instruction */
641 "\025<b20>"
642 "\026DTS" /* Debug Trace Store */
643 "\027ACPI" /* ACPI support */
644 "\030MMX" /* MMX instructions */
645 "\031FXSR" /* FXSAVE/FXRSTOR */
646 "\032SSE" /* Streaming SIMD Extensions */
647 "\033SSE2" /* Streaming SIMD Extensions #2 */
648 "\034SS" /* Self snoop */
649 "\035HTT" /* Hyperthreading (see EBX bit 16-23) */
650 "\036TM" /* Thermal Monitor clock slowdown */
651 "\037IA64" /* CPU can execute IA64 instructions */
652 "\040PBE" /* Pending Break Enable */
653 );
654
655 /*
656 * If this CPU supports hyperthreading then mention
657 * the number of logical CPU's it contains.
658 */
659 if (cpu_feature & CPUID_HTT &&
660 (cpu_procinfo & CPUID_HTT_CORES) >> 16 > 1)
661 printf("\n Hyperthreading: %d logical CPUs",
662 (cpu_procinfo & CPUID_HTT_CORES) >> 16);
663 }
664 if (strcmp(cpu_vendor, "AuthenticAMD") == 0 &&
665 cpu_exthigh >= 0x80000001)
666 print_AMD_features();
667 } else if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
668 printf(" DIR=0x%04x", cyrix_did);
669 printf(" Stepping=%u", (cyrix_did & 0xf000) >> 12);
670 printf(" Revision=%u", (cyrix_did & 0x0f00) >> 8);
671 #ifndef CYRIX_CACHE_REALLY_WORKS
672 if (cpu == CPU_M1 && (cyrix_did & 0xff00) < 0x1700)
673 printf("\n CPU cache: write-through mode");
674 #endif
675 }
676 /* Avoid ugly blank lines: only print newline when we have to. */
677 if (*cpu_vendor || cpu_id)
678 printf("\n");
679
680 #endif
681 if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
682 strcmp(cpu_vendor, "TransmetaCPU") == 0) {
683 setup_tmx86_longrun();
684 }
685
686 if (!bootverbose)
687 return;
688
689 if (strcmp(cpu_vendor, "AuthenticAMD") == 0)
690 print_AMD_info();
691 else if (strcmp(cpu_vendor, "GenuineTMx86") == 0 ||
692 strcmp(cpu_vendor, "TransmetaCPU") == 0)
693 print_transmeta_info();
694
695 #ifdef I686_CPU
696 /*
697 * XXX - Do PPro CPUID level=2 stuff here?
698 *
699 * No, but maybe in a print_Intel_info() function called from here.
700 */
701 #endif
702 }
703
704 void
705 panicifcpuunsupported(void)
706 {
707
708 #if !defined(I386_CPU) && !defined(I486_CPU) && !defined(I586_CPU) && !defined(I686_CPU)
709 #error This kernel is not configured for one of the supported CPUs
710 #endif
711 /*
712 * Now that we have told the user what they have,
713 * let them know if that machine type isn't configured.
714 */
715 switch (cpu_class) {
716 case CPUCLASS_286: /* a 286 should not make it this far, anyway */
717 #if !defined(I386_CPU)
718 case CPUCLASS_386:
719 #endif
720 #if !defined(I486_CPU)
721 case CPUCLASS_486:
722 #endif
723 #if !defined(I586_CPU)
724 case CPUCLASS_586:
725 #endif
726 #if !defined(I686_CPU)
727 case CPUCLASS_686:
728 #endif
729 panic("CPU class not configured");
730 default:
731 break;
732 }
733 }
734
735
736 static volatile u_int trap_by_rdmsr;
737
738 /*
739 * Special exception 6 handler.
740 * The rdmsr instruction generates invalid opcodes fault on 486-class
741 * Cyrix CPU. Stacked eip register points the rdmsr instruction in the
742 * function identblue() when this handler is called. Stacked eip should
743 * be advanced.
744 */
745 inthand_t bluetrap6;
746 __asm
747 (" \n\
748 .text \n\
749 .p2align 2,0x90 \n\
750 .type " __XSTRING(CNAME(bluetrap6)) ",@function \n\
751 " __XSTRING(CNAME(bluetrap6)) ": \n\
752 ss \n\
753 movl $0xa8c1d," __XSTRING(CNAME(trap_by_rdmsr)) " \n\
754 addl $2, (%esp) /* rdmsr is a 2-byte instruction */ \n\
755 iret \n\
756 ");
757
758 /*
759 * Special exception 13 handler.
760 * Accessing non-existent MSR generates general protection fault.
761 */
762 inthand_t bluetrap13;
763 __asm
764 (" \n\
765 .text \n\
766 .p2align 2,0x90 \n\
767 .type " __XSTRING(CNAME(bluetrap13)) ",@function \n\
768 " __XSTRING(CNAME(bluetrap13)) ": \n\
769 ss \n\
770 movl $0xa89c4," __XSTRING(CNAME(trap_by_rdmsr)) " \n\
771 popl %eax /* discard error code */ \n\
772 addl $2, (%esp) /* rdmsr is a 2-byte instruction */ \n\
773 iret \n\
774 ");
775
776 /*
777 * Distinguish IBM Blue Lightning CPU from Cyrix CPUs that does not
778 * support cpuid instruction. This function should be called after
779 * loading interrupt descriptor table register.
780 *
781 * I don't like this method that handles fault, but I couldn't get
782 * information for any other methods. Does blue giant know?
783 */
784 static int
785 identblue(void)
786 {
787
788 trap_by_rdmsr = 0;
789
790 /*
791 * Cyrix 486-class CPU does not support rdmsr instruction.
792 * The rdmsr instruction generates invalid opcode fault, and exception
793 * will be trapped by bluetrap6() on Cyrix 486-class CPU. The
794 * bluetrap6() set the magic number to trap_by_rdmsr.
795 */
796 setidt(6, bluetrap6, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
797
798 /*
799 * Certain BIOS disables cpuid instruction of Cyrix 6x86MX CPU.
800 * In this case, rdmsr generates general protection fault, and
801 * exception will be trapped by bluetrap13().
802 */
803 setidt(13, bluetrap13, SDT_SYS386TGT, SEL_KPL, GSEL(GCODE_SEL, SEL_KPL));
804
805 rdmsr(0x1002); /* Cyrix CPU generates fault. */
806
807 if (trap_by_rdmsr == 0xa8c1d)
808 return IDENTBLUE_CYRIX486;
809 else if (trap_by_rdmsr == 0xa89c4)
810 return IDENTBLUE_CYRIXM2;
811 return IDENTBLUE_IBMCPU;
812 }
813
814
815 /*
816 * identifycyrix() set lower 16 bits of cyrix_did as follows:
817 *
818 * F E D C B A 9 8 7 6 5 4 3 2 1 0
819 * +-------+-------+---------------+
820 * | SID | RID | Device ID |
821 * | (DIR 1) | (DIR 0) |
822 * +-------+-------+---------------+
823 */
824 static void
825 identifycyrix(void)
826 {
827 u_int eflags;
828 int ccr2_test = 0, dir_test = 0;
829 u_char ccr2, ccr3;
830
831 eflags = read_eflags();
832 disable_intr();
833
834 ccr2 = read_cyrix_reg(CCR2);
835 write_cyrix_reg(CCR2, ccr2 ^ CCR2_LOCK_NW);
836 read_cyrix_reg(CCR2);
837 if (read_cyrix_reg(CCR2) != ccr2)
838 ccr2_test = 1;
839 write_cyrix_reg(CCR2, ccr2);
840
841 ccr3 = read_cyrix_reg(CCR3);
842 write_cyrix_reg(CCR3, ccr3 ^ CCR3_MAPEN3);
843 read_cyrix_reg(CCR3);
844 if (read_cyrix_reg(CCR3) != ccr3)
845 dir_test = 1; /* CPU supports DIRs. */
846 write_cyrix_reg(CCR3, ccr3);
847
848 if (dir_test) {
849 /* Device ID registers are available. */
850 cyrix_did = read_cyrix_reg(DIR1) << 8;
851 cyrix_did += read_cyrix_reg(DIR0);
852 } else if (ccr2_test)
853 cyrix_did = 0x0010; /* 486S A-step */
854 else
855 cyrix_did = 0x00ff; /* Old 486SLC/DLC and TI486SXLC/SXL */
856
857 write_eflags(eflags);
858 }
859
860 /*
861 * Final stage of CPU identification. -- Should I check TI?
862 */
863 void
864 finishidentcpu(void)
865 {
866 int isblue = 0;
867 u_char ccr3;
868 u_int regs[4];
869
870 if (strcmp(cpu_vendor, "CyrixInstead") == 0) {
871 if (cpu == CPU_486) {
872 /*
873 * These conditions are equivalent to:
874 * - CPU does not support cpuid instruction.
875 * - Cyrix/IBM CPU is detected.
876 */
877 isblue = identblue();
878 if (isblue == IDENTBLUE_IBMCPU) {
879 strcpy(cpu_vendor, "IBM");
880 cpu = CPU_BLUE;
881 return;
882 }
883 }
884 switch (cpu_id & 0xf00) {
885 case 0x600:
886 /*
887 * Cyrix's datasheet does not describe DIRs.
888 * Therefor, I assume it does not have them
889 * and use the result of the cpuid instruction.
890 * XXX they seem to have it for now at least. -Peter
891 */
892 identifycyrix();
893 cpu = CPU_M2;
894 break;
895 default:
896 identifycyrix();
897 /*
898 * This routine contains a trick.
899 * Don't check (cpu_id & 0x00f0) == 0x50 to detect M2, now.
900 */
901 switch (cyrix_did & 0x00f0) {
902 case 0x00:
903 case 0xf0:
904 cpu = CPU_486DLC;
905 break;
906 case 0x10:
907 cpu = CPU_CY486DX;
908 break;
909 case 0x20:
910 if ((cyrix_did & 0x000f) < 8)
911 cpu = CPU_M1;
912 else
913 cpu = CPU_M1SC;
914 break;
915 case 0x30:
916 cpu = CPU_M1;
917 break;
918 case 0x40:
919 /* MediaGX CPU */
920 cpu = CPU_M1SC;
921 break;
922 default:
923 /* M2 and later CPUs are treated as M2. */
924 cpu = CPU_M2;
925
926 /*
927 * enable cpuid instruction.
928 */
929 ccr3 = read_cyrix_reg(CCR3);
930 write_cyrix_reg(CCR3, CCR3_MAPEN0);
931 write_cyrix_reg(CCR4, read_cyrix_reg(CCR4) | CCR4_CPUID);
932 write_cyrix_reg(CCR3, ccr3);
933
934 do_cpuid(0, regs);
935 cpu_high = regs[0]; /* eax */
936 do_cpuid(1, regs);
937 cpu_id = regs[0]; /* eax */
938 cpu_feature = regs[3]; /* edx */
939 break;
940 }
941 }
942 } else if (cpu == CPU_486 && *cpu_vendor == '\0') {
943 /*
944 * There are BlueLightning CPUs that do not change
945 * undefined flags by dividing 5 by 2. In this case,
946 * the CPU identification routine in locore.s leaves
947 * cpu_vendor null string and puts CPU_486 into the
948 * cpu.
949 */
950 isblue = identblue();
951 if (isblue == IDENTBLUE_IBMCPU) {
952 strcpy(cpu_vendor, "IBM");
953 cpu = CPU_BLUE;
954 return;
955 }
956 }
957 }
958
959 static void
960 print_AMD_assoc(int i)
961 {
962 if (i == 255)
963 printf(", fully associative\n");
964 else
965 printf(", %d-way associative\n", i);
966 }
967
968 static void
969 print_AMD_info(void)
970 {
971 quad_t amd_whcr;
972
973 if (cpu_exthigh >= 0x80000005) {
974 u_int regs[4];
975
976 do_cpuid(0x80000005, regs);
977 printf("Data TLB: %d entries", (regs[1] >> 16) & 0xff);
978 print_AMD_assoc(regs[1] >> 24);
979 printf("Instruction TLB: %d entries", regs[1] & 0xff);
980 print_AMD_assoc((regs[1] >> 8) & 0xff);
981 printf("L1 data cache: %d kbytes", regs[2] >> 24);
982 printf(", %d bytes/line", regs[2] & 0xff);
983 printf(", %d lines/tag", (regs[2] >> 8) & 0xff);
984 print_AMD_assoc((regs[2] >> 16) & 0xff);
985 printf("L1 instruction cache: %d kbytes", regs[3] >> 24);
986 printf(", %d bytes/line", regs[3] & 0xff);
987 printf(", %d lines/tag", (regs[3] >> 8) & 0xff);
988 print_AMD_assoc((regs[3] >> 16) & 0xff);
989 if (cpu_exthigh >= 0x80000006) { /* K6-III only */
990 do_cpuid(0x80000006, regs);
991 printf("L2 internal cache: %d kbytes", regs[2] >> 16);
992 printf(", %d bytes/line", regs[2] & 0xff);
993 printf(", %d lines/tag", (regs[2] >> 8) & 0x0f);
994 print_AMD_assoc((regs[2] >> 12) & 0x0f);
995 }
996 }
997 if (((cpu_id & 0xf00) == 0x500)
998 && (((cpu_id & 0x0f0) > 0x80)
999 || (((cpu_id & 0x0f0) == 0x80)
1000 && (cpu_id & 0x00f) > 0x07))) {
1001 /* K6-2(new core [Stepping 8-F]), K6-III or later */
1002 amd_whcr = rdmsr(0xc0000082);
1003 if (!(amd_whcr & (0x3ff << 22))) {
1004 printf("Write Allocate Disable\n");
1005 } else {
1006 printf("Write Allocate Enable Limit: %dM bytes\n",
1007 (u_int32_t)((amd_whcr & (0x3ff << 22)) >> 22) * 4);
1008 printf("Write Allocate 15-16M bytes: %s\n",
1009 (amd_whcr & (1 << 16)) ? "Enable" : "Disable");
1010 }
1011 } else if (((cpu_id & 0xf00) == 0x500)
1012 && ((cpu_id & 0x0f0) > 0x50)) {
1013 /* K6, K6-2(old core) */
1014 amd_whcr = rdmsr(0xc0000082);
1015 if (!(amd_whcr & (0x7f << 1))) {
1016 printf("Write Allocate Disable\n");
1017 } else {
1018 printf("Write Allocate Enable Limit: %dM bytes\n",
1019 (u_int32_t)((amd_whcr & (0x7f << 1)) >> 1) * 4);
1020 printf("Write Allocate 15-16M bytes: %s\n",
1021 (amd_whcr & 0x0001) ? "Enable" : "Disable");
1022 printf("Hardware Write Allocate Control: %s\n",
1023 (amd_whcr & 0x0100) ? "Enable" : "Disable");
1024 }
1025 }
1026 }
1027
1028 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
1029 static void
1030 print_AMD_features(void)
1031 {
1032 u_int regs[4];
1033
1034 /*
1035 * Values taken from AMD Processor Recognition
1036 * http://www.amd.com/products/cpg/athlon/techdocs/pdf/20734.pdf
1037 */
1038 do_cpuid(0x80000001, regs);
1039 printf("\n AMD Features=0x%b", regs[3] &~ cpu_feature,
1040 "\020" /* in hex */
1041 "\001FPU" /* Integral FPU */
1042 "\002VME" /* Extended VM86 mode support */
1043 "\003DE" /* Debug extensions */
1044 "\004PSE" /* 4MByte page tables */
1045 "\005TSC" /* Timestamp counter */
1046 "\006MSR" /* Machine specific registers */
1047 "\007PAE" /* Physical address extension */
1048 "\010MCE" /* Machine Check support */
1049 "\011CX8" /* CMPEXCH8 instruction */
1050 "\012APIC" /* SMP local APIC */
1051 "\013<b10>"
1052 "\014SYSCALL" /* SYSENTER/SYSEXIT instructions */
1053 "\015MTRR" /* Memory Type Range Registers */
1054 "\016PGE" /* PG_G (global bit) support */
1055 "\017MCA" /* Machine Check Architecture */
1056 "\020ICMOV" /* CMOV instruction */
1057 "\021PAT" /* Page attributes table */
1058 "\022PGE36" /* 36 bit address space support */
1059 "\023RSVD" /* Reserved, unknown */
1060 "\024MP" /* Multiprocessor Capable */
1061 "\025<b20>"
1062 "\026<b21>"
1063 "\027AMIE" /* AMD MMX Instruction Extensions */
1064 "\030MMX"
1065 "\031FXSAVE" /* FXSAVE/FXRSTOR */
1066 "\032<b25>"
1067 "\033<b26>"
1068 "\034<b27>"
1069 "\035<b28>"
1070 "\036<b29>"
1071 "\037DSP" /* AMD 3DNow! Instruction Extensions */
1072 "\0403DNow!"
1073 );
1074 }
1075 #endif
1076
1077 /*
1078 * Transmeta Crusoe LongRun Support by Tamotsu Hattori.
1079 */
1080
1081 #define MSR_TMx86_LONGRUN 0x80868010
1082 #define MSR_TMx86_LONGRUN_FLAGS 0x80868011
1083
1084 #define LONGRUN_MODE_MASK(x) ((x) & 0x000000007f)
1085 #define LONGRUN_MODE_RESERVED(x) ((x) & 0xffffff80)
1086 #define LONGRUN_MODE_WRITE(x, y) (LONGRUN_MODE_RESERVED(x) | LONGRUN_MODE_MASK(y))
1087
1088 #define LONGRUN_MODE_MINFREQUENCY 0x00
1089 #define LONGRUN_MODE_ECONOMY 0x01
1090 #define LONGRUN_MODE_PERFORMANCE 0x02
1091 #define LONGRUN_MODE_MAXFREQUENCY 0x03
1092 #define LONGRUN_MODE_UNKNOWN 0x04
1093 #define LONGRUN_MODE_MAX 0x04
1094
1095 union msrinfo {
1096 u_int64_t msr;
1097 u_int32_t regs[2];
1098 };
1099
1100 u_int32_t longrun_modes[LONGRUN_MODE_MAX][3] = {
1101 /* MSR low, MSR high, flags bit0 */
1102 { 0, 0, 0}, /* LONGRUN_MODE_MINFREQUENCY */
1103 { 0, 100, 0}, /* LONGRUN_MODE_ECONOMY */
1104 { 0, 100, 1}, /* LONGRUN_MODE_PERFORMANCE */
1105 { 100, 100, 1}, /* LONGRUN_MODE_MAXFREQUENCY */
1106 };
1107
1108 static u_int
1109 tmx86_get_longrun_mode(void)
1110 {
1111 u_long eflags;
1112 union msrinfo msrinfo;
1113 u_int low, high, flags, mode;
1114
1115 eflags = read_eflags();
1116 disable_intr();
1117
1118 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
1119 low = LONGRUN_MODE_MASK(msrinfo.regs[0]);
1120 high = LONGRUN_MODE_MASK(msrinfo.regs[1]);
1121 flags = rdmsr(MSR_TMx86_LONGRUN_FLAGS) & 0x01;
1122
1123 for (mode = 0; mode < LONGRUN_MODE_MAX; mode++) {
1124 if (low == longrun_modes[mode][0] &&
1125 high == longrun_modes[mode][1] &&
1126 flags == longrun_modes[mode][2]) {
1127 goto out;
1128 }
1129 }
1130 mode = LONGRUN_MODE_UNKNOWN;
1131 out:
1132 write_eflags(eflags);
1133 return (mode);
1134 }
1135
1136 static u_int
1137 tmx86_get_longrun_status(u_int * frequency, u_int * voltage, u_int * percentage)
1138 {
1139 u_long eflags;
1140 u_int regs[4];
1141
1142 eflags = read_eflags();
1143 disable_intr();
1144
1145 do_cpuid(0x80860007, regs);
1146 *frequency = regs[0];
1147 *voltage = regs[1];
1148 *percentage = regs[2];
1149
1150 write_eflags(eflags);
1151 return (1);
1152 }
1153
1154 static u_int
1155 tmx86_set_longrun_mode(u_int mode)
1156 {
1157 u_long eflags;
1158 union msrinfo msrinfo;
1159
1160 if (mode >= LONGRUN_MODE_UNKNOWN) {
1161 return (0);
1162 }
1163
1164 eflags = read_eflags();
1165 disable_intr();
1166
1167 /* Write LongRun mode values to Model Specific Register. */
1168 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN);
1169 msrinfo.regs[0] = LONGRUN_MODE_WRITE(msrinfo.regs[0],
1170 longrun_modes[mode][0]);
1171 msrinfo.regs[1] = LONGRUN_MODE_WRITE(msrinfo.regs[1],
1172 longrun_modes[mode][1]);
1173 wrmsr(MSR_TMx86_LONGRUN, msrinfo.msr);
1174
1175 /* Write LongRun mode flags to Model Specific Register. */
1176 msrinfo.msr = rdmsr(MSR_TMx86_LONGRUN_FLAGS);
1177 msrinfo.regs[0] = (msrinfo.regs[0] & ~0x01) | longrun_modes[mode][2];
1178 wrmsr(MSR_TMx86_LONGRUN_FLAGS, msrinfo.msr);
1179
1180 write_eflags(eflags);
1181 return (1);
1182 }
1183
1184 static u_int crusoe_longrun;
1185 static u_int crusoe_frequency;
1186 static u_int crusoe_voltage;
1187 static u_int crusoe_percentage;
1188 static struct sysctl_ctx_list crusoe_sysctl_ctx;
1189 static struct sysctl_oid *crusoe_sysctl_tree;
1190
1191 static int
1192 tmx86_longrun_sysctl(SYSCTL_HANDLER_ARGS)
1193 {
1194 u_int mode;
1195 int error;
1196
1197 crusoe_longrun = tmx86_get_longrun_mode();
1198 mode = crusoe_longrun;
1199 error = sysctl_handle_int(oidp, &mode, 0, req);
1200 if (error || !req->newptr) {
1201 return (error);
1202 }
1203 if (mode >= LONGRUN_MODE_UNKNOWN) {
1204 error = EINVAL;
1205 return (error);
1206 }
1207 if (crusoe_longrun != mode) {
1208 crusoe_longrun = mode;
1209 tmx86_set_longrun_mode(crusoe_longrun);
1210 }
1211
1212 return (error);
1213 }
1214
1215 static int
1216 tmx86_status_sysctl(SYSCTL_HANDLER_ARGS)
1217 {
1218 u_int val;
1219 int error;
1220
1221 tmx86_get_longrun_status(&crusoe_frequency,
1222 &crusoe_voltage, &crusoe_percentage);
1223 val = *(u_int *)oidp->oid_arg1;
1224 error = sysctl_handle_int(oidp, &val, 0, req);
1225 return (error);
1226 }
1227
1228 static void
1229 setup_tmx86_longrun(void)
1230 {
1231 static int done = 0;
1232
1233 if (done)
1234 return;
1235 done++;
1236
1237 sysctl_ctx_init(&crusoe_sysctl_ctx);
1238 crusoe_sysctl_tree = SYSCTL_ADD_NODE(&crusoe_sysctl_ctx,
1239 SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
1240 "crusoe", CTLFLAG_RD, 0,
1241 "Transmeta Crusoe LongRun support");
1242 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1243 OID_AUTO, "longrun", CTLTYPE_INT | CTLFLAG_RW,
1244 &crusoe_longrun, 0, tmx86_longrun_sysctl, "I",
1245 "LongRun mode [0-3]");
1246 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1247 OID_AUTO, "frequency", CTLTYPE_INT | CTLFLAG_RD,
1248 &crusoe_frequency, 0, tmx86_status_sysctl, "I",
1249 "Current frequency (MHz)");
1250 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1251 OID_AUTO, "voltage", CTLTYPE_INT | CTLFLAG_RD,
1252 &crusoe_voltage, 0, tmx86_status_sysctl, "I",
1253 "Current voltage (mV)");
1254 SYSCTL_ADD_PROC(&crusoe_sysctl_ctx, SYSCTL_CHILDREN(crusoe_sysctl_tree),
1255 OID_AUTO, "percentage", CTLTYPE_INT | CTLFLAG_RD,
1256 &crusoe_percentage, 0, tmx86_status_sysctl, "I",
1257 "Processing performance (%)");
1258 }
1259
1260 static void
1261 print_transmeta_info()
1262 {
1263 u_int regs[4], nreg = 0;
1264
1265 do_cpuid(0x80860000, regs);
1266 nreg = regs[0];
1267 if (nreg >= 0x80860001) {
1268 do_cpuid(0x80860001, regs);
1269 printf(" Processor revision %u.%u.%u.%u\n",
1270 (regs[1] >> 24) & 0xff,
1271 (regs[1] >> 16) & 0xff,
1272 (regs[1] >> 8) & 0xff,
1273 regs[1] & 0xff);
1274 }
1275 if (nreg >= 0x80860002) {
1276 do_cpuid(0x80860002, regs);
1277 printf(" Code Morphing Software revision %u.%u.%u-%u-%u\n",
1278 (regs[1] >> 24) & 0xff,
1279 (regs[1] >> 16) & 0xff,
1280 (regs[1] >> 8) & 0xff,
1281 regs[1] & 0xff,
1282 regs[2]);
1283 }
1284 if (nreg >= 0x80860006) {
1285 char info[65];
1286 do_cpuid(0x80860003, (u_int*) &info[0]);
1287 do_cpuid(0x80860004, (u_int*) &info[16]);
1288 do_cpuid(0x80860005, (u_int*) &info[32]);
1289 do_cpuid(0x80860006, (u_int*) &info[48]);
1290 info[64] = 0;
1291 printf(" %s\n", info);
1292 }
1293
1294 crusoe_longrun = tmx86_get_longrun_mode();
1295 tmx86_get_longrun_status(&crusoe_frequency,
1296 &crusoe_voltage, &crusoe_percentage);
1297 printf(" LongRun mode: %d <%dMHz %dmV %d%%>\n", crusoe_longrun,
1298 crusoe_frequency, crusoe_voltage, crusoe_percentage);
1299 }
1300
Cache object: ed725c5ab26bb73451f82dc682c09aa6
|