Subject: port-i386/35430: Identify amd64 CPU on NetBSD/i386
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <tsutsui@ceres.dti.ne.jp>
List: netbsd-bugs
Date: 01/16/2007 11:40:00
>Number:         35430
>Category:       port-i386
>Synopsis:       Identify amd64 CPU on NetBSD/i386
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    port-i386-maintainer
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Tue Jan 16 11:40:00 +0000 2007
>Originator:     Izumi Tsutsui
>Release:        NetBSD 4.99.8
>Organization:
>Environment:
System: NetBSD 4.99.8
Architecture: i386
Machine: i386
with all amd64 (K8) based CPUs

>Description:
identifycpu() function during cpu attachment of NetBSD/i386
shows all amd64 (K8) based CPUs "Unknown K7 (Athlon)":
http://mail-index.netbsd.org/current-users/2006/12/06/0002.html

>How-To-Repeat:
Boot NetBSD/i386 on amd64 CPU systems.

>Fix:
The attached patch decodes CPUIDs for amd64 CPUs and show their names.


Index: arch/i386/i386/identcpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/identcpu.c,v
retrieving revision 1.52
diff -u -r1.52 identcpu.c
--- arch/i386/i386/identcpu.c	1 Jan 2007 20:56:58 -0000	1.52
+++ arch/i386/i386/identcpu.c	16 Jan 2007 11:16:46 -0000
@@ -148,6 +148,7 @@
 static void intel_family_new_probe(struct cpu_info *);
 
 static const char *intel_family6_name(struct cpu_info *);
+static const char *amd_amd64_name(struct cpu_info *);
 
 static void transmeta_cpu_info(struct cpu_info *);
 
@@ -339,7 +340,7 @@
 			{
 				0, 0, 0, 0, 0, 0, 0, 0,
 				0, 0, 0, 0, 0, 0, 0, 0,
-				"Unknown K7 (Athlon)"	/* Default */
+				"Unknown K8 (Athlon)"	/* Default */
 			},
 			NULL,
 			amd_family6_probe,
@@ -739,6 +740,131 @@
 	return ret;
 }
 
+/*
+ * Identify AMD64 CPU names from cpuid.
+ *
+ * Based on "Revision Guide for AMD Athlon 64 and AMD Opteron Processors"
+ * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25759.pdf
+ * miscellaneous reports.
+ */
+const char *
+amd_amd64_name(struct cpu_info *ci)
+{
+	int extfamily, extmodel, model;
+	const char *ret = NULL;
+
+	model = CPUID2MODEL(ci->ci_signature);
+	extfamily = CPUID2EXTFAMILY(ci->ci_signature);
+	extmodel  = CPUID2EXTMODEL(ci->ci_signature);
+
+	if (extfamily == 0x00) {
+		switch (model) {
+		case 0x1:
+			switch (extmodel) {
+			case 0x2:	/* rev JH-E1/E6 */
+				ret = "Dual-Core Opteron";
+				break;
+			}
+			break;
+		case 0x3:
+			switch (extmodel) {
+			case 0x2:	/* rev JH-E6 (Toledo) */
+				ret = "Dual-Core Opteron or Athlon 64 X2";
+				break;
+			case 0x4:	/* rev JH-F2 (Windsor) */
+				ret = "Athlon 64 FX or Athlon 64 X2";
+				break;
+			}
+			break;
+		case 0x4:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-B0/C0/CG (ClawHammer) */
+			case 0x1:	/* rev SH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev SH-E5 (Lancaster?) */
+				ret = "Mobile Athlon 64 or Turion 64";
+				break;
+			}
+			break;
+		case 0x5:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-B0/B3/C0/CG (SledgeHammer?) */
+				ret = "Opteron or Athlon 64 FX";
+				break;
+			case 0x1:	/* rev SH-D0 */
+			case 0x2:	/* rev SH-E4 */
+				ret = "Opteron";
+				break;
+			}
+			break;
+		case 0x7:
+			switch (extmodel) {
+			case 0x0:	/* rev SH-CG (ClawHammer) */
+			case 0x1:	/* rev SH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev DH-E4, SH-E4 */
+				ret = "Athlon 64 or Athlon 64 FX or Opteron";
+				break;
+			}
+			break;
+		case 0x8:
+			switch (extmodel) {
+			case 0x0:	/* rev CH-CG */
+			case 0x1:	/* rev CH-D0 */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		case 0xb:
+			switch (extmodel) {
+			case 0x0:	/* rev CH-CG */
+			case 0x1:	/* rev CH-D0 */
+				ret = "Athlon 64";
+				break;
+			case 0x2:	/* rev BH-E4 (Manchester) */
+			case 0x4:	/* rev BH-F2 (Windsor) */
+				ret = "Athlon 64 X2";
+				break;
+			}
+			break;
+		case 0xc:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle) */
+			case 0x1:	/* rev DH-D0 (Winchester) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			case 0x2:	/* rev DH-E3/E6 */
+				ret = "Sempron";
+				break;
+			}
+			break;
+		case 0xe:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle?) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		case 0xf:
+			switch (extmodel) {
+			case 0x0:	/* rev DH-CG (Newcastle/Paris) */
+			case 0x1:	/* rev DH-D0 (Winchester/Victoria) */
+			case 0x2:	/* rev DH-E3/E6 (Venice/Palermo) */
+			case 0x4:	/* rev DH-F2 (Orleans/Manila) */
+				ret = "Athlon 64 or Sempron";
+				break;
+			}
+			break;
+		default:
+			ret = "Unknown AMD64 CPU";
+		}
+	}
+
+	return ret;
+}
+
 static void
 cpu_probe_base_features(struct cpu_info *ci)
 {
@@ -1365,17 +1491,30 @@
 					     i386_intel_brand[ci->ci_brand_id];
 			}
 
-			if (vendor == CPUVENDOR_AMD && family == 6 &&
-			    model >= 6) {
-				if (ci->ci_brand_id == 1)
-					/* 
-					 * It's Duron. We override the 
-					 * name, since it might have been 
-					 * misidentified as Athlon.
+			if (vendor == CPUVENDOR_AMD) {
+				if (family == 6 && model >= 6) {
+					if (ci->ci_brand_id == 1)
+						/* 
+						 * It's Duron. We override the 
+						 * name, since it might have
+						 * been misidentified as Athlon.
+						 */
+						name =
+						    amd_brand[ci->ci_brand_id];
+					else
+						brand = amd_brand_name;
+				}
+				if (CPUID2FAMILY(ci->ci_signature) == 0xf) {
+					/*
+					 * Identify AMD64 CPU names.
+					 * Note family value is clipped by
+					 * CPU_MAXFAMILY.
 					 */
-					name = amd_brand[ci->ci_brand_id];
-				else
-					brand = amd_brand_name;
+					const char *tmp;
+					tmp = amd_amd64_name(ci);
+					if (tmp != NULL)
+						name = tmp;
+				}
 			}
 			
 			if (vendor == CPUVENDOR_IDT && family >= 6)
Index: arch/x86/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/specialreg.h,v
retrieving revision 1.13
diff -u -r1.13 specialreg.h
--- arch/x86/include/specialreg.h	11 Jan 2007 17:24:30 -0000	1.13
+++ arch/x86/include/specialreg.h	16 Jan 2007 11:16:46 -0000
@@ -169,9 +169,13 @@
 
 #define CPUID2_FLAGS "\20\1SSE3\4MONITOR\5DS-CPL\6VMX\10EST\11TM2\13CID\17xTPR"
 
-#define CPUID2FAMILY(cpuid)	(((cpuid) >> 8) & 15)
-#define CPUID2MODEL(cpuid)	(((cpuid) >> 4) & 15)
-#define CPUID2STEPPING(cpuid)	((cpuid) & 15)
+#define CPUID2FAMILY(cpuid)	(((cpuid) >> 8) & 0xf)
+#define CPUID2MODEL(cpuid)	(((cpuid) >> 4) & 0xf)
+#define CPUID2STEPPING(cpuid)	((cpuid) & 0xf)
+
+/* Extended family and model are defined on amd64 processors */
+#define CPUID2EXTFAMILY(cpuid)	(((cpuid) >> 20) & 0xff)
+#define CPUID2EXTMODEL(cpuid)	(((cpuid) >> 16) & 0xf)
 
 #define CPUID(code, eax, ebx, ecx, edx)                         \
 	__asm("cpuid"                                           \