[syslinux:master] cpuid: Improving Cyrix/NSC detection

syslinux-bot for Erwan Velu erwanaliasr1 at gmail.com
Mon Apr 25 15:29:08 PDT 2011


Commit-ID:  42018413878117f299c2baf54f5dce84f327244e
Gitweb:     http://syslinux.zytor.com/commit/42018413878117f299c2baf54f5dce84f327244e
Author:     Erwan Velu <erwanaliasr1 at gmail.com>
AuthorDate: Sat, 16 Apr 2011 08:06:01 +0200
Committer:  Erwan Velu <erwanaliasr1 at gmail.com>
CommitDate: Sat, 16 Apr 2011 08:06:01 +0200

cpuid: Improving Cyrix/NSC detection

This code add the specific detection code for Cyrix/NSC processor.
Code came from the Linux kernel.


---
 com32/gplinclude/cpuid.h |   37 +++++++++++++
 com32/gpllib/cpuid.c     |  126 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 163 insertions(+), 0 deletions(-)

diff --git a/com32/gplinclude/cpuid.h b/com32/gplinclude/cpuid.h
index 166e4f1..6a33e9c 100644
--- a/com32/gplinclude/cpuid.h
+++ b/com32/gplinclude/cpuid.h
@@ -22,6 +22,7 @@
 #include <cpufeature.h>
 #include <sys/bitops.h>
 #include <sys/cpu.h>
+#include <sys/io.h>
 #include <klibc/compiler.h>
 
 #define PAGE_SIZE 4096
@@ -191,6 +192,32 @@ extern bool get_cpu_flag_value_from_name(s_cpu *cpu, const char * flag);
 
 #define cpu_has(c, bit)                test_bit(bit, (c)->x86_capability)
 
+// Taken from asm/processor-flags.h
+// NSC/Cyrix CPU configuration register indexes
+#define CX86_CCR2       0xc2
+#define CX86_CCR3	0xc3
+#define CX86_DIR0       0xfe
+#define CX86_DIR1       0xff
+
+static const char Cx86_model[][9] = {
+	"Cx486", "Cx486", "5x86 ", "6x86", "MediaGX ", "6x86MX ",
+	"M II ", "Unknown"
+};
+
+static const char Cx486_name[][5] = {
+	"SLC", "DLC", "SLC2", "DLC2", "SRx", "DRx",
+	"SRx2", "DRx2"
+};
+
+static const char Cx486S_name[][4] = {
+	"S", "S2", "Se", "S2e"
+};
+
+static const char Cx486D_name[][4] = {
+	"DX", "DX2", "?", "?", "?", "DX4"
+};
+
+
 /*
  *  CPU type and hardware bug flags. Kept separately for each CPU.
  *  Members of this structure are referenced in head.S, so think twice
@@ -275,6 +302,16 @@ struct intel_mp_floating {
     uint8_t mpf_feature5;	/* Unused (0)                   */
 };
 
+static inline uint8_t getCx86(uint8_t reg) {
+	outb(reg, 0x22);
+	return inb(0x23);
+}
+
+static inline void setCx86(uint8_t reg, uint8_t data) {
+	outb(reg, 0x22);
+	outb(data, 0x23);
+}
+
 extern void get_cpu_vendor(struct cpuinfo_x86 *c);
 extern void detect_cpu(s_cpu * cpu);
 #endif
diff --git a/com32/gpllib/cpuid.c b/com32/gpllib/cpuid.c
index 471b716..ee82b6e 100644
--- a/com32/gpllib/cpuid.c
+++ b/com32/gpllib/cpuid.c
@@ -106,6 +106,38 @@ static struct cpu_dev unknown_cpu_dev = {
     .c_ident = {"Unknown CPU"}
 };
 
+/*
+ * Read NSC/Cyrix DEVID registers (DIR) to get more detailed info. about the CPU
+ */
+void do_cyrix_devid(unsigned char *dir0, unsigned char *dir1)
+{
+	unsigned char ccr2, ccr3;
+
+	/* we test for DEVID by checking whether CCR3 is writable */
+	ccr3 = getCx86(CX86_CCR3);
+	setCx86(CX86_CCR3, ccr3 ^ 0x80);
+	getCx86(0xc0);   /* dummy to change bus */
+
+	if (getCx86(CX86_CCR3) == ccr3) {       /* no DEVID regs. */
+		ccr2 = getCx86(CX86_CCR2);
+		setCx86(CX86_CCR2, ccr2 ^ 0x04);
+		getCx86(0xc0);  /* dummy */
+
+		if (getCx86(CX86_CCR2) == ccr2) /* old Cx486SLC/DLC */
+			*dir0 = 0xfd;
+		else {                          /* Cx486S A step */
+			setCx86(CX86_CCR2, ccr2);
+			*dir0 = 0xfe;
+		}
+	} else {
+		setCx86(CX86_CCR3, ccr3);  /* restore CCR3 */
+
+		/* read DIR0 and DIR1 CPU registers */
+		*dir0 = getCx86(CX86_DIR0);
+		*dir1 = getCx86(CX86_DIR1);
+	}
+}
+
 void init_cpu_devs(void)
 {
     cpu_devs[X86_VENDOR_INTEL] = &intel_cpu_dev;
@@ -212,6 +244,93 @@ void detect_cache(uint32_t xlvl, struct cpuinfo_x86 *c)
     c->x86_l2_cache_size = l2size;
 }
 
+void detect_cyrix(struct cpuinfo_x86 *c) {
+	unsigned char dir0, dir0_msn, dir0_lsn, dir1 = 0;
+        char *buf = c->x86_model_id;
+	char Cx86_cb[] = "?.5x Core/Bus Clock";
+	const char cyrix_model_mult1[] = "12??43";
+	const char cyrix_model_mult2[] = "12233445";
+        const char *p = NULL;
+
+	do_cyrix_devid(&dir0, &dir1);
+	dir0_msn = dir0 >> 4; /* identifies CPU "family"   */
+	dir0_lsn = dir0 & 0xf;                /* model or clock multiplier */
+	c->x86_model = (dir1 >> 4) + 1;
+        c->x86_mask = dir1 & 0xf;
+	switch (dir0_msn) {
+		unsigned char tmp;
+
+	        case 0: /* Cx486SLC/DLC/SRx/DRx */
+                	 p = Cx486_name[dir0_lsn & 7];
+			 break;
+	
+		case 1: /* Cx486S/DX/DX2/DX4 */
+	                 p = (dir0_lsn & 8) ? Cx486D_name[dir0_lsn & 5] : Cx486S_name[dir0_lsn & 3];
+			 break;
+
+	         case 2: /* 5x86 */
+	                 Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+			 p = Cx86_cb+2;
+			 break;
+
+		case 3: /* 6x86/6x86L */
+			   Cx86_cb[1] = ' ';
+			   Cx86_cb[2] = cyrix_model_mult1[dir0_lsn & 5];
+			   if (dir1 > 0x21) { /* 686L */
+				   Cx86_cb[0] = 'L';
+				   p = Cx86_cb;
+				   (c->x86_model)++;
+			   } else             /* 686 */
+				   p = Cx86_cb+1;
+			   
+			   c->coma_bug = 1;
+			   break;
+		case 4:
+	                   c->x86_l1_data_cache_size = 16; /* Yep 16K integrated cache thats it */
+			   if (c->cpuid_level != 2) { /* Media GX */
+				   Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
+				   p = Cx86_cb+2;
+			   }
+			   break;
+		
+		case 5: /* 6x86MX/M II */
+			   if (dir1 > 7) {
+				   dir0_msn++;  /* M II */
+			   } else {
+	                           c->coma_bug = 1;      /* 6x86MX, it has the bug. */
+			   }
+
+			   tmp = (!(dir0_lsn & 7) || dir0_lsn & 1) ? 2 : 0;
+			   Cx86_cb[tmp] = cyrix_model_mult2[dir0_lsn & 7];
+			   p = Cx86_cb+tmp;
+			   if (((dir1 & 0x0f) > 4) || ((dir1 & 0xf0) == 0x20))
+				   (c->x86_model)++;
+			   break;
+		
+		case 0xf:  /* Cyrix 486 without DEVID registers */
+			   switch (dir0_lsn) {
+				   case 0xd:  /* either a 486SLC or DLC w/o DEVID */
+					   dir0_msn = 0; 
+					   p = Cx486_name[(c->hard_math) ? 1 : 0];
+					   break;
+				   
+				   case 0xe:  /* a 486S A step */
+					   dir0_msn = 0;
+					   p = Cx486S_name[0];
+					   break;
+			   }
+			   break;
+			   
+		default:
+			   dir0_msn = 7;
+			   break;
+	}
+	
+	strcpy(buf, Cx86_model[dir0_msn & 7]);
+
+	if (p) strcat(buf, p);
+}
+
 void generic_identify(struct cpuinfo_x86 *c)
 {
     uint32_t tfms, xlvl;
@@ -257,6 +376,13 @@ void generic_identify(struct cpuinfo_x86 *c)
 	    get_model_name(c);	/* Default name */
     }
 
+    /* Specific detection code */
+    switch (c->x86_vendor) {
+	    case X86_VENDOR_CYRIX:
+	    case X86_VENDOR_NSC: detect_cyrix(c); break;
+	    default: break;
+    }
+
     /* Detecting the number of cores */
     switch (c->x86_vendor) {
     case X86_VENDOR_AMD:



More information about the Syslinux-commits mailing list