blob: 53f3de8ad9e2ae1a25897fa5104b1df31fead401 [file] [log] [blame]
Martin Roth9b1b3352016-02-24 12:27:06 -08001/*
2 * MemTest86+ V5 Specific code (GPL V2.0)
3 * By Samuel DEMEULEMEESTER, sdemeule@memtest.org
4 * http://www.canardpc.com - http://www.memtest.org
5 * ------------------------------------------------
6 * init.c - MemTest-86 Version 3.6
7 *
8 * Released under version 2 of the Gnu Public License.
9 * By Chris Brady
10 */
11
12
13#include "stdin.h"
14#include "stddef.h"
15#include "test.h"
16#include "defs.h"
17#include "config.h"
18#include "cpuid.h"
19#include "smp.h"
20#include "io.h"
21#include "spd.h"
Martin Roth8cc1aeb2016-02-24 13:03:52 -080022#include "multiboot.h"
Martin Roth9b1b3352016-02-24 12:27:06 -080023
24extern struct tseq tseq[];
25extern short memsz_mode;
26extern int num_cpus;
27extern int act_cpus;
28extern int found_cpus;
29unsigned long imc_type = 0;
30extern int maxcpus;
31extern char cpu_mask[];
32extern void initialise_cpus();
33
34/* Here we store all of the cpuid data */
35extern struct cpu_ident cpu_id;
36
37int l1_cache=0, l2_cache=0, l3_cache=0;
38int tsc_invariable = 0;
39ulong extclock;
40
41ulong memspeed(ulong src, ulong len, int iter);
42static void cpu_type(void);
43static int cpuspeed(void);
44static void get_cache_size();
45static void cpu_cache_speed();
46void get_cpuid();
47int beepmode;
48extern short dmi_initialized;
49extern int dmi_err_cnts[MAX_DMI_MEMDEVS];
50
51/* Failsafe function */
52/* msec: number of ms to wait - scs: scancode expected to stop */
53/* bits: 0 = extended detection - 1: SMP - 2: Temp Check */
54/* 3: MP SMP - 4-7: RSVD */
55void failsafe(int msec, int scs)
56{
57 int i;
58 ulong sh, sl, l, h, t;
59 unsigned char c;
60 volatile char *pp;
61
62 for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<40; i++, pp+=2) {
63 *pp = 0x1E;
64 }
65 for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<3; i++, pp+=2) {
66 *pp = 0x9E;
67 }
68 for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(55*2)+1); i<3; i++, pp+=2) {
69 *pp = 0x9E;
70 }
71
72 cprint(18, 18, "==> Press F1 to enter Fail-Safe Mode <==");
73
74 if(v->fail_safe & 2)
75 {
76 cprint(19, 15, "==> Press F2 to force Multi-Threading (SMP) <==");
77 }
78
79 /* save the starting time */
80 asm __volatile__(
81 "rdtsc":"=a" (sl),"=d" (sh));
82
83 /* loop for n seconds */
84 while (1) {
85 asm __volatile__(
86 "rdtsc":"=a" (l),"=d" (h));
87 asm __volatile__ (
88 "subl %2,%0\n\t"
89 "sbbl %3,%1"
90 :"=a" (l), "=d" (h)
91 :"g" (sl), "g" (sh),
92 "0" (l), "1" (h));
93
94 t = h * ((unsigned)0xffffffff / v->clks_msec);
95 t += (l / v->clks_msec);
96
97 /* Is the time up? */
98 if (t >= msec) { break; }
99
100 /* Is expected Scan code pressed? */
101 c = get_key();
102 c &= 0x7f;
103
104 /* F1 */
105 if(c == scs) { v->fail_safe |= 1; break; }
106
107 /* F2 */
108 if(c == scs+1)
109 {
110 v->fail_safe ^= 2;
111 break;
112
113 }
114
115 /* F3 */
116 if(c == scs+2)
117 {
118 if(v->fail_safe & 2) { v->fail_safe ^= 2; }
119 v->fail_safe |= 8;
120 break;
121 }
122
123 }
124
125 cprint(18, 18, " ");
126 cprint(19, 15, " ");
127
128 for(i=0, pp=(char *)(SCREEN_ADR+(18*160)+(18*2)+1); i<40; i++, pp+=2) {
129 *pp = 0x17;
130 }
131
132}
133
134
135
136static void display_init(void)
137{
138 int i;
139 volatile char *pp;
140
141 /* Set HW cursor out of screen boundaries */
142 __outb(0x0F, 0x03D4);
143 __outb(0xFF, 0x03D5);
144
145 __outb(0x0E, 0x03D4);
146 __outb(0xFF, 0x03D5);
147
148
149 serial_echo_init();
150 serial_echo_print("INE_SCROLL;24r"); /* Set scroll area row 7-23 */
151 serial_echo_print(""); /* Clear Screen */
152 serial_echo_print("");
153 serial_echo_print("");
154 serial_echo_print("");
155
156 /* Clear screen & set background to blue */
157 for(i=0, pp=(char *)(SCREEN_ADR); i<80*24; i++) {
158 *pp++ = ' ';
159 *pp++ = 0x17;
160 }
161
162 /* Make the name background green */
163 for(i=0, pp=(char *)(SCREEN_ADR+1); i<TITLE_WIDTH; i++, pp+=2) {
164 *pp = 0x20;
165 }
166 cprint(0, 0, " Memtest86 5.01 ");
167
168 /* Set Blinking "+" */
169 for(i=0, pp=(char *)(SCREEN_ADR+1); i<2; i++, pp+=30) {
170 *pp = 0xA4;
171 }
172 cprint(0, 15, "+");
173
174 /* Do reverse video for the bottom display line */
175 for(i=0, pp=(char *)(SCREEN_ADR+1+(24 * 160)); i<80; i++, pp+=2) {
176 *pp = 0x71;
177 }
178
179 serial_echo_print("");
180}
181
182/*
183 * Initialize test, setup screen and find out how much memory there is.
184 */
185void init(void)
186{
187 int i;
188
189 outb(0x8, 0x3f2); /* Kill Floppy Motor */
190
191 /* Turn on cache */
192 set_cache(1);
193
194 /* Setup the display */
195 display_init();
196
197 cprint(5, 60, "| Time: 0:00:00");
198 cprint(1, COL_MID,"Pass %");
199 cprint(2, COL_MID,"Test %");
200 cprint(3, COL_MID,"Test #");
201 cprint(4, COL_MID,"Testing: ");
202 cprint(5, COL_MID,"Pattern: ");
203 cprint(1, 0, "CLK: (32b Mode)");
204 cprint(2, 0, "L1 Cache: Unknown ");
205 cprint(3, 0, "L2 Cache: Unknown ");
206 cprint(4, 0, "L3 Cache: None ");
207 cprint(5, 0, "Memory : ");
208 cprint(6, 0, "------------------------------------------------------------------------------");
209 cprint(7, 0, "Core#:");
210 cprint(8, 0, "State:");
211 cprint(9, 0, "Cores: Active / Total (Run: All) | Pass: 0 Errors: 0 ");
212 cprint(10, 0, "------------------------------------------------------------------------------");
213
214 /*
215 for(i=0, pp=(char *)(SCREEN_ADR+(5*160)+(53*2)+1); i<20; i++, pp+=2) {
216 *pp = 0x92;
217 }
218
219 for(i=0, pp=(char *)(SCREEN_ADR+0*160+1); i<80; i++, pp+=2) {
220 *pp = 0x47;
221 }
222 */
223
224 cprint(7, 39, "| Chipset : Unknown");
225 cprint(8, 39, "| Memory Type : Unknown");
226
227
228 for(i=0; i < 6; i++) {
229 cprint(i, COL_MID-2, "| ");
230 }
231
232 footer();
233
234 aprint(5, 10, v->test_pages);
235
236 v->pass = 0;
237 v->msg_line = 0;
238 v->ecount = 0;
239 v->ecc_ecount = 0;
240 v->testsel = -1;
241 v->msg_line = LINE_SCROLL-1;
242 v->scroll_start = v->msg_line * 160;
243 v->erri.low_addr.page = 0x7fffffff;
244 v->erri.low_addr.offset = 0xfff;
245 v->erri.high_addr.page = 0;
246 v->erri.high_addr.offset = 0;
247 v->erri.min_bits = 32;
248 v->erri.max_bits = 0;
249 v->erri.min_bits = 32;
250 v->erri.max_bits = 0;
251 v->erri.maxl = 0;
252 v->erri.cor_err = 0;
253 v->erri.ebits = 0;
254 v->erri.hdr_flag = 0;
255 v->erri.tbits = 0;
256 for (i=0; tseq[i].msg != NULL; i++) {
257 tseq[i].errors = 0;
258 }
259 if (dmi_initialized) {
260 for (i=0; i < MAX_DMI_MEMDEVS; i++){
261 if (dmi_err_cnts[i] > 0) {
262 dmi_err_cnts[i] = 0;
263 }
264 }
265 }
266
267 /* setup beep mode */
268 beepmode = BEEP_MODE;
269
270 /* Get the cpu and cache information */
271 get_cpuid();
272
273 /* setup pci */
274 pci_init();
275
276 get_cache_size();
277
278 cpu_type();
279
280 cpu_cache_speed();
281
282 /* Check fail safe */
283 failsafe(5000, 0x3B);
284
285 /* Initalize SMP */
286 initialise_cpus();
287
288 for (i = 0; i <num_cpus; i++) {
289 dprint(7, i+7, i%10, 1, 0);
290 cprint(8, i+7, "S");
291 }
292
293 dprint(9, 19, num_cpus, 2, 0);
294
295 if((v->fail_safe & 3) == 2)
296 {
297 cprint(LINE_CPU,9, "(SMP: Disabled)");
298 cprint(LINE_RAM,9, "Running...");
299 }
300 // dprint(10, 5, found_cpus, 2, 0);
301
302 /* Find Memory Specs */
303 if(v->fail_safe & 1)
304 {
305 cprint(LINE_CPU, COL_SPEC, " **** FAIL SAFE **** FAIL SAFE **** ");
306 cprint(LINE_RAM, COL_SPEC, " No detection, same reliability ");
307 } else {
308 find_controller();
309 get_spd_spec();
310 if(num_cpus <= 16 && !(v->fail_safe & 4)) { coretemp(); }
311 }
312
313 if(v->check_temp > 0 && !(v->fail_safe & 4))
314 {
315 cprint(LINE_CPU, 26, "| CPU Temp");
316 cprint(LINE_CPU+1, 26, "| øC");
317 }
318
319 beep(600);
320 beep(1000);
321
322 /* Record the start time */
323 asm __volatile__ ("rdtsc":"=a" (v->startl),"=d" (v->starth));
324 v->snapl = v->startl;
325 v->snaph = v->starth;
326 if (l1_cache == 0) { l1_cache = 64; }
327 if (l2_cache == 0) { l1_cache = 512; }
328 v->printmode=PRINTMODE_ADDRESSES;
329 v->numpatn=0;
330}
331
332/* Get cache sizes for most AMD and Intel CPUs, exceptions for old CPUs are
333 * handled in CPU detection */
334void get_cache_size()
335{
336 int i, j, n, size;
337 unsigned int v[4];
338 unsigned char *dp = (unsigned char *)v;
339 struct cpuid4_eax *eax = (struct cpuid4_eax *)&v[0];
340 struct cpuid4_ebx *ebx = (struct cpuid4_ebx *)&v[1];
341 struct cpuid4_ecx *ecx = (struct cpuid4_ecx *)&v[2];
342
343 switch(cpu_id.vend_id.char_array[0]) {
344 /* AMD Processors */
345 case 'A':
346 //l1_cache = cpu_id.cache_info.amd.l1_i_sz;
347 l1_cache = cpu_id.cache_info.amd.l1_d_sz;
348 l2_cache = cpu_id.cache_info.amd.l2_sz;
349 l3_cache = cpu_id.cache_info.amd.l3_sz;
350 l3_cache *= 512;
351 break;
352 case 'G':
353 /* Intel Processors */
354 l1_cache = 0;
355 l2_cache = 0;
356 l3_cache = 0;
357
358 /* Use CPUID(4) if it is available */
359 if (cpu_id.max_cpuid > 3) {
360
361 /* figure out how many cache leaves */
362 n = -1;
363 do
364 {
365 ++n;
366 /* Do cpuid(4) loop to find out num_cache_leaves */
367 cpuid_count(4, n, &v[0], &v[1], &v[2], &v[3]);
368 } while ((eax->ctype) != 0);
369
370 /* loop through all of the leaves */
371 for (i=0; i<n; i++)
372 {
373 cpuid_count(4, i, &v[0], &v[1], &v[2], &v[3]);
374
375 /* Check for a valid cache type */
376 if (eax->ctype == 1 || eax->ctype == 3)
377 {
378
379 /* Compute the cache size */
380 size = (ecx->number_of_sets + 1) *
381 (ebx->coherency_line_size + 1) *
382 (ebx->physical_line_partition + 1) *
383 (ebx->ways_of_associativity + 1);
384 size /= 1024;
385
386 switch (eax->level)
387 {
388 case 1:
389 l1_cache += size;
390 break;
391 case 2:
392 l2_cache += size;
393 break;
394 case 3:
395 l3_cache += size;
396 break;
397 }
398 }
399 }
400 return;
401 }
402
403 /* No CPUID(4) so we use the older CPUID(2) method */
404 /* Get number of times to iterate */
405 cpuid(2, &v[0], &v[1], &v[2], &v[3]);
406 n = v[0] & 0xff;
407 for (i=0 ; i<n ; i++) {
408 cpuid(2, &v[0], &v[1], &v[2], &v[3]);
409
410 /* If bit 31 is set, this is an unknown format */
411 for (j=0 ; j<3 ; j++) {
412 if (v[j] & (1 << 31)) {
413 v[j] = 0;
414 }
415 }
416
417 /* Byte 0 is level count, not a descriptor */
418 for (j = 1 ; j < 16 ; j++) {
419 switch(dp[j]) {
420 case 0x6:
421 case 0xa:
422 case 0x66:
423 l1_cache += 8;
424 break;
425 case 0x8:
426 case 0xc:
427 case 0xd:
428 case 0x60:
429 case 0x67:
430 l1_cache += 16;
431 break;
432 case 0xe:
433 l1_cache += 24;
434 break;
435 case 0x9:
436 case 0x2c:
437 case 0x30:
438 case 0x68:
439 l1_cache += 32;
440 break;
441 case 0x39:
442 case 0x3b:
443 case 0x41:
444 case 0x79:
445 l2_cache += 128;
446 break;
447 case 0x3a:
448 l2_cache += 192;
449 break;
450 case 0x21:
451 case 0x3c:
452 case 0x3f:
453 case 0x42:
454 case 0x7a:
455 case 0x82:
456 l2_cache += 256;
457 break;
458 case 0x3d:
459 l2_cache += 384;
460 break;
461 case 0x3e:
462 case 0x43:
463 case 0x7b:
464 case 0x7f:
465 case 0x80:
466 case 0x83:
467 case 0x86:
468 l2_cache += 512;
469 break;
470 case 0x44:
471 case 0x78:
472 case 0x7c:
473 case 0x84:
474 case 0x87:
475 l2_cache += 1024;
476 break;
477 case 0x45:
478 case 0x7d:
479 case 0x85:
480 l2_cache += 2048;
481 break;
482 case 0x48:
483 l2_cache += 3072;
484 break;
485 case 0x4e:
486 l2_cache += 6144;
487 break;
488 case 0x23:
489 case 0xd0:
490 l3_cache += 512;
491 break;
492 case 0xd1:
493 case 0xd6:
494 l3_cache += 1024;
495 break;
496 case 0x25:
497 case 0xd2:
498 case 0xd7:
499 case 0xdc:
500 case 0xe2:
501 l3_cache += 2048;
502 break;
503 case 0x29:
504 case 0x46:
505 case 0x49:
506 case 0xd8:
507 case 0xdd:
508 case 0xe3:
509 l3_cache += 4096;
510 break;
511 case 0x4a:
512 l3_cache += 6144;
513 break;
514 case 0x47:
515 case 0x4b:
516 case 0xde:
517 case 0xe4:
518 l3_cache += 8192;
519 break;
520 case 0x4c:
521 case 0xea:
522 l3_cache += 12288;
523 break;
524 case 0x4d:
525 l3_cache += 16384;
526 break;
527 case 0xeb:
528 l3_cache += 18432;
529 break;
530 case 0xec:
531 l3_cache += 24576;
532 break;
533 } /* end switch */
534 } /* end for 1-16 */
535 } /* end for 0 - n */
536 }
537}
538
539/*
540 * Find IMC type and set global variables accordingly
541 */
542void detect_imc(void)
543{
544 // Check AMD IMC
545 if(cpu_id.vend_id.char_array[0] == 'A' && cpu_id.vers.bits.family == 0xF)
546 {
547 switch(cpu_id.vers.bits.extendedFamily)
548 {
549 case 0x0:
550 imc_type = 0x0100; // Old K8
551 break;
552 case 0x1:
553 case 0x2:
554 imc_type = 0x0101; // K10 (Family 10h & 11h)
555 break;
556 case 0x3:
557 imc_type = 0x0102; // A-Series APU (Family 12h)
558 break;
559 case 0x5:
560 imc_type = 0x0103; // C- / E- / Z- Series APU (Family 14h)
561 break;
562 case 0x6:
563 imc_type = 0x0104; // FX Series (Family 15h)
564 break;
565 case 0x7:
566 imc_type = 0x0105; // Kabini & related (Family 16h)
567 break;
568 }
569 return;
570 }
571
572 // Check Intel IMC
573 if(cpu_id.vend_id.char_array[0] == 'G' && cpu_id.vers.bits.family == 6 && cpu_id.vers.bits.extendedModel)
574 {
575 switch(cpu_id.vers.bits.model)
576 {
577 case 0x5:
578 if(cpu_id.vers.bits.extendedModel == 2) { imc_type = 0x0003; } // Core i3/i5 1st Gen 45 nm (NHM)
579 if(cpu_id.vers.bits.extendedModel == 3) { v->fail_safe |= 4; } // Atom Clover Trail
580 if(cpu_id.vers.bits.extendedModel == 4) { imc_type = 0x0007; } // HSW-ULT
581 break;
582 case 0x6:
583 if(cpu_id.vers.bits.extendedModel == 3) {
584 imc_type = 0x0009; // Atom Cedar Trail
585 v->fail_safe |= 4; // Disable Core temp
586 }
587 break;
588 case 0xA:
589 switch(cpu_id.vers.bits.extendedModel)
590 {
591 case 0x1:
592 imc_type = 0x0001; // Core i7 1st Gen 45 nm (NHME)
593 break;
594 case 0x2:
595 imc_type = 0x0004; // Core 2nd Gen (SNB)
596 break;
597 case 0x3:
598 imc_type = 0x0006; // Core 3nd Gen (IVB)
599 break;
600 }
601 break;
602 case 0xC:
603 switch(cpu_id.vers.bits.extendedModel)
604 {
605 case 0x1:
606 if(cpu_id.vers.bits.stepping > 9) { imc_type = 0x0008; } // Atom PineView
607 v->fail_safe |= 4; // Disable Core temp
608 break;
609 case 0x2:
610 imc_type = 0x0002; // Core i7 1st Gen 32 nm (WMR)
611 break;
612 case 0x3:
613 imc_type = 0x0007; // Core 4nd Gen (HSW)
614 break;
615 }
616 break;
617 case 0xD:
618 imc_type = 0x0005; // SNB-E
619 break;
620 case 0xE:
621 imc_type = 0x0001; // Core i7 1st Gen 45 nm (NHM)
622 break;
623 }
624
625 if(imc_type) { tsc_invariable = 1; }
626 return;
627 }
628}
629
630void smp_default_mode(void)
631{
632 int i, result;
633 char *cpupsn = cpu_id.brand_id.char_array;
634 char *disabledcpu[] = { "Opteron", "Xeon", "Genuine Intel" };
635
636 for(i = 0; i < 3; i++)
637 {
638 result = strstr(cpupsn , disabledcpu[i]);
639 if(result != -1) { v->fail_safe |= 0b10; }
640 }
641
642 // For 5.01 release, SMP disabled by defualt by config.h toggle
643 if(CONSERVATIVE_SMP) { v->fail_safe |= 0b10; }
644
645}
646
647/*
648 * Find CPU type
649 */
650void cpu_type(void)
651{
652 /* If we can get a brand string use it, and we are done */
653 if (cpu_id.max_xcpuid >= 0x80000004) {
654 cprint(0, COL_MID, cpu_id.brand_id.char_array);
655 //If we have a brand string, maybe we have an IMC. Check that.
656 detect_imc();
657 smp_default_mode();
658 return;
659 }
660
661 /* The brand string is not available so we need to figure out
662 * CPU what we have */
663 switch(cpu_id.vend_id.char_array[0]) {
664 /* AMD Processors */
665 case 'A':
666 switch(cpu_id.vers.bits.family) {
667 case 4:
668 switch(cpu_id.vers.bits.model) {
669 case 3:
670 cprint(0, COL_MID, "AMD 486DX2");
671 break;
672 case 7:
673 cprint(0, COL_MID, "AMD 486DX2-WB");
674 break;
675 case 8:
676 cprint(0, COL_MID, "AMD 486DX4");
677 break;
678 case 9:
679 cprint(0, COL_MID, "AMD 486DX4-WB");
680 break;
681 case 14:
682 cprint(0, COL_MID, "AMD 5x86-WT");
683 break;
684 case 15:
685 cprint(0, COL_MID, "AMD 5x86-WB");
686 break;
687 }
688 /* Since we can't get CPU speed or cache info return */
689 return;
690 case 5:
691 switch(cpu_id.vers.bits.model) {
692 case 0:
693 case 1:
694 case 2:
695 case 3:
696 cprint(0, COL_MID, "AMD K5");
697 l1_cache = 8;
698 break;
699 case 6:
700 case 7:
701 cprint(0, COL_MID, "AMD K6");
702 break;
703 case 8:
704 cprint(0, COL_MID, "AMD K6-2");
705 break;
706 case 9:
707 cprint(0, COL_MID, "AMD K6-III");
708 break;
709 case 13:
710 cprint(0, COL_MID, "AMD K6-III+");
711 break;
712 }
713 break;
714 case 6:
715
716 switch(cpu_id.vers.bits.model) {
717 case 1:
718 cprint(0, COL_MID, "AMD Athlon (0.25)");
719 break;
720 case 2:
721 case 4:
722 cprint(0, COL_MID, "AMD Athlon (0.18)");
723 break;
724 case 6:
725 if (l2_cache == 64) {
726 cprint(0, COL_MID, "AMD Duron (0.18)");
727 } else {
728 cprint(0, COL_MID, "Athlon XP (0.18)");
729 }
730 break;
731 case 8:
732 case 10:
733 if (l2_cache == 64) {
734 cprint(0, COL_MID, "AMD Duron (0.13)");
735 } else {
736 cprint(0, COL_MID, "Athlon XP (0.13)");
737 }
738 break;
739 case 3:
740 case 7:
741 cprint(0, COL_MID, "AMD Duron");
742 /* Duron stepping 0 CPUID for L2 is broken */
743 /* (AMD errata T13)*/
744 if (cpu_id.vers.bits.stepping == 0) { /* stepping 0 */
745 /* Hard code the right L2 size */
746 l2_cache = 64;
747 } else {
748 }
749 break;
750 }
751 break;
752
753 /* All AMD family values >= 10 have the Brand ID
754 * feature so we don't need to find the CPU type */
755 }
756 break;
757
758 /* Intel or Transmeta Processors */
759 case 'G':
760 if ( cpu_id.vend_id.char_array[7] == 'T' ) { /* GenuineTMx86 */
761 if (cpu_id.vers.bits.family == 5) {
762 cprint(0, COL_MID, "TM 5x00");
763 } else if (cpu_id.vers.bits.family == 15) {
764 cprint(0, COL_MID, "TM 8x00");
765 }
766 l1_cache = cpu_id.cache_info.ch[3] + cpu_id.cache_info.ch[7];
767 l2_cache = (cpu_id.cache_info.ch[11]*256) + cpu_id.cache_info.ch[10];
768 } else { /* GenuineIntel */
769 if (cpu_id.vers.bits.family == 4) {
770 switch(cpu_id.vers.bits.model) {
771 case 0:
772 case 1:
773 cprint(0, COL_MID, "Intel 486DX");
774 break;
775 case 2:
776 cprint(0, COL_MID, "Intel 486SX");
777 break;
778 case 3:
779 cprint(0, COL_MID, "Intel 486DX2");
780 break;
781 case 4:
782 cprint(0, COL_MID, "Intel 486SL");
783 break;
784 case 5:
785 cprint(0, COL_MID, "Intel 486SX2");
786 break;
787 case 7:
788 cprint(0, COL_MID, "Intel 486DX2-WB");
789 break;
790 case 8:
791 cprint(0, COL_MID, "Intel 486DX4");
792 break;
793 case 9:
794 cprint(0, COL_MID, "Intel 486DX4-WB");
795 break;
796 }
797 /* Since we can't get CPU speed or cache info return */
798 return;
799 }
800
801
802 switch(cpu_id.vers.bits.family) {
803 case 5:
804 switch(cpu_id.vers.bits.model) {
805 case 0:
806 case 1:
807 case 2:
808 case 3:
809 case 7:
810 cprint(0, COL_MID, "Pentium");
811 if (l1_cache == 0) {
812 l1_cache = 8;
813 }
814 break;
815 case 4:
816 case 8:
817 cprint(0, COL_MID, "Pentium-MMX");
818 if (l1_cache == 0) {
819 l1_cache = 16;
820 }
821 break;
822 }
823 break;
824 case 6:
825 switch(cpu_id.vers.bits.model) {
826 case 0:
827 case 1:
828 cprint(0, COL_MID, "Pentium Pro");
829 break;
830 case 3:
831 case 4:
832 cprint(0, COL_MID, "Pentium II");
833 break;
834 case 5:
835 if (l2_cache == 0) {
836 cprint(0, COL_MID, "Celeron");
837 } else {
838 cprint(0, COL_MID, "Pentium II");
839 }
840 break;
841 case 6:
842 if (l2_cache == 128) {
843 cprint(0, COL_MID, "Celeron");
844 } else {
845 cprint(0, COL_MID, "Pentium II");
846 }
847 }
848 break;
849 case 7:
850 case 8:
851 case 11:
852 if (l2_cache == 128) {
853 cprint(0, COL_MID, "Celeron");
854 } else {
855 cprint(0, COL_MID, "Pentium III");
856 }
857 break;
858 case 9:
859 if (l2_cache == 512) {
860 cprint(0, COL_MID, "Celeron M (0.13)");
861 } else {
862 cprint(0, COL_MID, "Pentium M (0.13)");
863 }
864 break;
865 case 10:
866 cprint(0, COL_MID, "Pentium III Xeon");
867 break;
868 case 12:
869 l1_cache = 24;
870 cprint(0, COL_MID, "Atom (0.045)");
871 break;
872 case 13:
873 if (l2_cache == 1024) {
874 cprint(0, COL_MID, "Celeron M (0.09)");
875 } else {
876 cprint(0, COL_MID, "Pentium M (0.09)");
877 }
878 break;
879 case 14:
880 cprint(0, COL_MID, "Intel Core");
881 break;
882 case 15:
883 if (l2_cache == 1024) {
884 cprint(0, COL_MID, "Pentium E");
885 } else {
886 cprint(0, COL_MID, "Intel Core 2");
887 }
888 break;
889 }
890 break;
891 case 15:
892 switch(cpu_id.vers.bits.model) {
893 case 0:
894 case 1:
895 case 2:
896 if (l2_cache == 128) {
897 cprint(0, COL_MID, "Celeron");
898 } else {
899 cprint(0, COL_MID, "Pentium 4");
900 }
901 break;
902 case 3:
903 case 4:
904 if (l2_cache == 256) {
905 cprint(0, COL_MID, "Celeron (0.09)");
906 } else {
907 cprint(0, COL_MID, "Pentium 4 (0.09)");
908 }
909 break;
910 case 6:
911 cprint(0, COL_MID, "Pentium D (65nm)");
912 break;
913 default:
914 cprint(0, COL_MID, "Unknown Intel");
915 break;
916 break;
917 }
918
919 }
920 break;
921
922 /* VIA/Cyrix/Centaur Processors with CPUID */
923 case 'C':
924 if ( cpu_id.vend_id.char_array[1] == 'e' ) { /* CentaurHauls */
925 l1_cache = cpu_id.cache_info.ch[3] + cpu_id.cache_info.ch[7];
926 l2_cache = cpu_id.cache_info.ch[11];
927 switch(cpu_id.vers.bits.family){
928 case 5:
929 cprint(0, COL_MID, "Centaur 5x86");
930 break;
931 case 6: // VIA C3
932 switch(cpu_id.vers.bits.model){
933 default:
934 if (cpu_id.vers.bits.stepping < 8) {
935 cprint(0, COL_MID, "VIA C3 Samuel2");
936 } else {
937 cprint(0, COL_MID, "VIA C3 Eden");
938 }
939 break;
940 case 10:
941 cprint(0, COL_MID, "VIA C7 (C5J)");
942 l1_cache = 64;
943 l2_cache = 128;
944 break;
945 case 13:
946 cprint(0, COL_MID, "VIA C7 (C5R)");
947 l1_cache = 64;
948 l2_cache = 128;
949 break;
950 case 15:
951 cprint(0, COL_MID, "VIA Isaiah (CN)");
952 l1_cache = 64;
953 l2_cache = 128;
954 break;
955 }
956 }
957 } else { /* CyrixInstead */
958 switch(cpu_id.vers.bits.family) {
959 case 5:
960 switch(cpu_id.vers.bits.model) {
961 case 0:
962 cprint(0, COL_MID, "Cyrix 6x86MX/MII");
963 break;
964 case 4:
965 cprint(0, COL_MID, "Cyrix GXm");
966 break;
967 }
968 return;
969
970 case 6: // VIA C3
971 switch(cpu_id.vers.bits.model) {
972 case 6:
973 cprint(0, COL_MID, "Cyrix III");
974 break;
975 case 7:
976 if (cpu_id.vers.bits.stepping < 8) {
977 cprint(0, COL_MID, "VIA C3 Samuel2");
978 } else {
979 cprint(0, COL_MID, "VIA C3 Ezra-T");
980 }
981 break;
982 case 8:
983 cprint(0, COL_MID, "VIA C3 Ezra-T");
984 break;
985 case 9:
986 cprint(0, COL_MID, "VIA C3 Nehemiah");
987 break;
988 }
989 // L1 = L2 = 64 KB from Cyrix III to Nehemiah
990 l1_cache = 64;
991 l2_cache = 64;
992 break;
993 }
994 }
995 break;
996 /* Unknown processor */
997 default:
998 /* Make a guess at the family */
999 switch(cpu_id.vers.bits.family) {
1000 case 5:
1001 cprint(0, COL_MID, "586");
1002 case 6:
1003 cprint(0, COL_MID, "686");
1004 default:
1005 cprint(0, COL_MID, "Unidentified Processor");
1006 }
1007 }
1008}
1009
1010#define STEST_ADDR 0x100000 /* Measure memory speed starting at 1MB */
1011
1012/* Measure and display CPU and cache sizes and speeds */
1013void cpu_cache_speed()
1014{
1015 int i, off = 4;
1016 ulong speed;
1017
1018
1019 /* Print CPU speed */
1020 if ((speed = cpuspeed()) > 0) {
1021 if (speed < 999499) {
1022 speed += 50; /* for rounding */
1023 cprint(1, off, " . MHz");
1024 dprint(1, off+1, speed/1000, 3, 1);
1025 dprint(1, off+5, (speed/100)%10, 1, 0);
1026 } else {
1027 speed += 500; /* for rounding */
1028 cprint(1, off, " MHz");
1029 dprint(1, off, speed/1000, 5, 0);
1030 }
1031 extclock = speed;
1032 }
1033
1034 /* Print out L1 cache info */
1035 /* To measure L1 cache speed we use a block size that is 1/4th */
1036 /* of the total L1 cache size since half of it is for instructions */
1037 if (l1_cache) {
1038 cprint(2, 0, "L1 Cache: K ");
1039 dprint(2, 11, l1_cache, 3, 0);
1040 if ((speed=memspeed(STEST_ADDR, (l1_cache/2)*1024, 200))) {
1041 cprint(2, 16, " MB/s");
1042 dprint(2, 16, speed, 6, 0);
1043 }
1044 }
1045
1046 /* Print out L2 cache info */
1047 /* We measure the L2 cache speed by using a block size that is */
1048 /* the size of the L1 cache. We have to fudge if the L1 */
1049 /* cache is bigger than the L2 */
1050 if (l2_cache) {
1051 cprint(3, 0, "L2 Cache: K ");
1052 dprint(3, 10, l2_cache, 4, 0);
1053
1054 if (l2_cache < l1_cache) {
1055 i = l1_cache / 4 + l2_cache / 4;
1056 } else {
1057 i = l1_cache;
1058 }
1059 if ((speed=memspeed(STEST_ADDR, i*1024, 200))) {
1060 cprint(3, 16, " MB/s");
1061 dprint(3, 16, speed, 6, 0);
1062 }
1063 }
1064 /* Print out L3 cache info */
1065 /* We measure the L3 cache speed by using a block size that is */
1066 /* 2X the size of the L2 cache. */
1067
1068 if (l3_cache)
1069 {
1070 cprint(4, 0, "L3 Cache: K ");
1071 aprint(4, 10, l3_cache/4);
1072 //dprint(4, 10, l3_cache, 4, 0);
1073
1074 i = l2_cache*2;
1075
1076 if ((speed=memspeed(STEST_ADDR, i*1024, 150))) {
1077 cprint(4, 16, " MB/s");
1078 dprint(4, 16, speed, 6, 0);
1079 }
1080 }
1081}
1082
1083/* Measure and display memory speed, multitasked using all CPUs */
1084ulong spd[MAX_CPUS];
1085void get_mem_speed(int me, int ncpus)
1086{
1087 int i;
1088 ulong speed=0;
1089
1090 /* Determine memory speed. To find the memory speed we use
1091 * A block size that is the sum of all the L1, L2 & L3 caches
1092 * in all cpus * 6 */
1093 i = (l3_cache + l2_cache + l1_cache) * 4;
1094
1095 /* Make sure that we have enough memory to do the test */
1096 /* If not use all we have */
1097 if ((1 + (i * 2)) > (v->plim_upper << 2)) {
1098 i = ((v->plim_upper <<2) - 1) / 2;
1099 }
1100
1101 speed = memspeed(STEST_ADDR, i * 1024, 100);
1102 cprint(5, 16, " MB/s");
1103 dprint(5, 16, speed, 6, 0);
1104
1105}
1106
1107/* #define TICKS 5 * 11832 (count = 6376)*/
1108/* #define TICKS (65536 - 12752) */
1109#define TICKS 59659 /* 50 ms */
1110
1111/* Returns CPU clock in khz */
1112ulong stlow, sthigh;
1113static int cpuspeed(void)
1114{
1115 int loops;
1116 ulong end_low, end_high;
1117
1118 if (cpu_id.fid.bits.rdtsc == 0 ) {
1119 return(-1);
1120 }
1121
1122 /* Setup timer */
1123 outb((inb(0x61) & ~0x02) | 0x01, 0x61);
1124 outb(0xb0, 0x43);
1125 outb(TICKS & 0xff, 0x42);
1126 outb(TICKS >> 8, 0x42);
1127
1128 asm __volatile__ ("rdtsc":"=a" (stlow),"=d" (sthigh));
1129
1130 loops = 0;
1131 do {
1132 loops++;
1133 } while ((inb(0x61) & 0x20) == 0);
1134
1135 asm __volatile__ (
1136 "rdtsc\n\t" \
1137 "subl stlow,%%eax\n\t" \
1138 "sbbl sthigh,%%edx\n\t" \
1139 :"=a" (end_low), "=d" (end_high)
1140 );
1141
1142 /* Make sure we have a credible result */
1143 if (loops < 4 || end_low < 50000) {
1144 return(-1);
1145 }
1146 v->clks_msec = end_low/50;
1147
1148 if (tsc_invariable) end_low = correct_tsc(end_low);
1149
1150 return(v->clks_msec);
1151}
1152
1153/* Measure cache speed by copying a block of memory. */
1154/* Returned value is kbytes/second */
1155ulong memspeed(ulong src, ulong len, int iter)
1156{
1157 int i;
1158 ulong dst, wlen;
1159 ulong st_low, st_high;
1160 ulong end_low, end_high;
1161 ulong cal_low, cal_high;
1162
1163 if (cpu_id.fid.bits.rdtsc == 0 ) {
1164 return(-1);
1165 }
1166 if (len == 0) return(-2);
1167
1168 dst = src + len;
1169 wlen = len / 4; /* Length is bytes */
1170
1171 /* Calibrate the overhead with a zero word copy */
1172 asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1173 for (i=0; i<iter; i++) {
1174 asm __volatile__ (
1175 "movl %0,%%esi\n\t" \
1176 "movl %1,%%edi\n\t" \
1177 "movl %2,%%ecx\n\t" \
1178 "cld\n\t" \
1179 "rep\n\t" \
1180 "movsl\n\t" \
1181 :: "g" (src), "g" (dst), "g" (0)
1182 : "esi", "edi", "ecx"
1183 );
1184 }
1185 asm __volatile__ ("rdtsc":"=a" (cal_low),"=d" (cal_high));
1186
1187 /* Compute the overhead time */
1188 asm __volatile__ (
1189 "subl %2,%0\n\t"
1190 "sbbl %3,%1"
1191 :"=a" (cal_low), "=d" (cal_high)
1192 :"g" (st_low), "g" (st_high),
1193 "0" (cal_low), "1" (cal_high)
1194 );
1195
1196
1197 /* Now measure the speed */
1198 /* Do the first copy to prime the cache */
1199 asm __volatile__ (
1200 "movl %0,%%esi\n\t" \
1201 "movl %1,%%edi\n\t" \
1202 "movl %2,%%ecx\n\t" \
1203 "cld\n\t" \
1204 "rep\n\t" \
1205 "movsl\n\t" \
1206 :: "g" (src), "g" (dst), "g" (wlen)
1207 : "esi", "edi", "ecx"
1208 );
1209 asm __volatile__ ("rdtsc":"=a" (st_low),"=d" (st_high));
1210 for (i=0; i<iter; i++) {
1211 asm __volatile__ (
1212 "movl %0,%%esi\n\t" \
1213 "movl %1,%%edi\n\t" \
1214 "movl %2,%%ecx\n\t" \
1215 "cld\n\t" \
1216 "rep\n\t" \
1217 "movsl\n\t" \
1218 :: "g" (src), "g" (dst), "g" (wlen)
1219 : "esi", "edi", "ecx"
1220 );
1221 }
1222 asm __volatile__ ("rdtsc":"=a" (end_low),"=d" (end_high));
1223
1224 /* Compute the elapsed time */
1225 asm __volatile__ (
1226 "subl %2,%0\n\t"
1227 "sbbl %3,%1"
1228 :"=a" (end_low), "=d" (end_high)
1229 :"g" (st_low), "g" (st_high),
1230 "0" (end_low), "1" (end_high)
1231 );
1232 /* Subtract the overhead time */
1233 asm __volatile__ (
1234 "subl %2,%0\n\t"
1235 "sbbl %3,%1"
1236 :"=a" (end_low), "=d" (end_high)
1237 :"g" (cal_low), "g" (cal_high),
1238 "0" (end_low), "1" (end_high)
1239 );
1240
1241 /* Make sure that the result fits in 32 bits */
1242 //hprint(11,40,end_high);
1243 if (end_high) {
1244 return(-3);
1245 }
1246 end_low /= 2;
1247
1248 /* Convert to clocks/KB */
1249 end_low /= len;
1250 end_low *= 1024;
1251 end_low /= iter;
1252 if (end_low == 0) {
1253 return(-4);
1254 }
1255
1256 /* Convert to kbytes/sec */
1257
1258 if (tsc_invariable) end_low = correct_tsc(end_low);
1259
1260 return((v->clks_msec)/end_low);
1261}
1262
1263#define rdmsr(msr,val1,val2) \
1264 __asm__ __volatile__("rdmsr" \
1265 : "=a" (val1), "=d" (val2) \
1266 : "c" (msr))
1267
1268
1269ulong correct_tsc(ulong el_org)
1270{
1271 float coef_now, coef_max;
1272 int msr_lo, msr_hi, is_xe;
1273
1274 rdmsr(0x198, msr_lo, msr_hi);
1275 is_xe = (msr_lo >> 31) & 0x1;
1276
1277 if(is_xe){
1278 rdmsr(0x198, msr_lo, msr_hi);
1279 coef_max = ((msr_hi >> 8) & 0x1F);
1280 if ((msr_hi >> 14) & 0x1) { coef_max = coef_max + 0.5f; }
1281 } else {
1282 rdmsr(0x17, msr_lo, msr_hi);
1283 coef_max = ((msr_lo >> 8) & 0x1F);
1284 if ((msr_lo >> 14) & 0x1) { coef_max = coef_max + 0.5f; }
1285 }
1286
1287 if(cpu_id.fid.bits.eist) {
1288 rdmsr(0x198, msr_lo, msr_hi);
1289 coef_now = ((msr_lo >> 8) & 0x1F);
1290 if ((msr_lo >> 14) & 0x1) { coef_now = coef_now + 0.5f; }
1291 } else {
1292 rdmsr(0x2A, msr_lo, msr_hi);
1293 coef_now = (msr_lo >> 22) & 0x1F;
1294 }
1295 if(coef_max && coef_now) {
1296 el_org = (ulong)(el_org * coef_now / coef_max);
1297 }
1298 return el_org;
1299}
1300