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" \