From ca563604da92bdd1f6ee8d8de019ea7bd08b8e1f Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sat, 5 Sep 2009 08:36:27 +0200
Subject: [PATCH] VIA CPU support: Detect and enable CPU features (RNG, ACE etc.).

Taken from: FreeBSD
---
 sys/cpu/amd64/include/specialreg.h |   21 +++++++++
 sys/cpu/i386/include/specialreg.h  |   21 +++++++++
 sys/platform/pc32/i386/identcpu.c  |   55 +++++++++++++++++++----
 sys/platform/pc32/i386/initcpu.c   |   86 ++++++++++++++++++++++++++++++++++++
 sys/platform/pc64/amd64/initcpu.c  |   75 +++++++++++++++++++++++++++++++
 5 files changed, 248 insertions(+), 10 deletions(-)

diff --git a/sys/cpu/amd64/include/specialreg.h b/sys/cpu/amd64/include/specialreg.h
index 757c5bb..0a4be7b 100644
--- a/sys/cpu/amd64/include/specialreg.h
+++ b/sys/cpu/amd64/include/specialreg.h
@@ -462,4 +462,25 @@
 #define	MSR_TOP_MEM2	0xc001001d	/* boundary for ram above 4G */
 #define	MSR_K8_UCODE_UPDATE	0xc0010020	/* update microcode */
 
+/* VIA ACE crypto featureset: for via_feature_rng */
+#define	VIA_HAS_RNG		1	/* cpu has RNG */
+
+/* VIA ACE crypto featureset: for via_feature_xcrypt */
+#define	VIA_HAS_AES		1	/* cpu has AES */
+#define	VIA_HAS_SHA		2	/* cpu has SHA1 & SHA256 */
+#define	VIA_HAS_MM		4	/* cpu has RSA instructions */
+#define	VIA_HAS_AESCTR		8	/* cpu has AES-CTR instructions */
+
+/* Centaur Extended Feature flags */
+#define	VIA_CPUID_HAS_RNG	0x000004
+#define	VIA_CPUID_DO_RNG	0x000008
+#define	VIA_CPUID_HAS_ACE	0x000040
+#define	VIA_CPUID_DO_ACE	0x000080
+#define	VIA_CPUID_HAS_ACE2	0x000100
+#define	VIA_CPUID_DO_ACE2	0x000200
+#define	VIA_CPUID_HAS_PHE	0x000400
+#define	VIA_CPUID_DO_PHE	0x000800
+#define	VIA_CPUID_HAS_PMM	0x001000
+#define	VIA_CPUID_DO_PMM	0x002000
+
 #endif /* !_CPU_SPECIALREG_H_ */
diff --git a/sys/cpu/i386/include/specialreg.h b/sys/cpu/i386/include/specialreg.h
index e0207ec..b9301ce 100644
--- a/sys/cpu/i386/include/specialreg.h
+++ b/sys/cpu/i386/include/specialreg.h
@@ -363,6 +363,27 @@
 #define	AMD_WT_ALLOC_PRE	0x20000	/* programmable range enable */
 #define	AMD_WT_ALLOC_FRE	0x10000	/* fixed (A0000-FFFFF) range enable */
 
+/* VIA ACE crypto featureset: for via_feature_rng */
+#define	VIA_HAS_RNG		1	/* cpu has RNG */
+
+/* VIA ACE crypto featureset: for via_feature_xcrypt */
+#define	VIA_HAS_AES		1	/* cpu has AES */
+#define	VIA_HAS_SHA		2	/* cpu has SHA1 & SHA256 */
+#define	VIA_HAS_MM		4	/* cpu has RSA instructions */
+#define	VIA_HAS_AESCTR		8	/* cpu has AES-CTR instructions */
+
+/* Centaur Extended Feature flags */
+#define	VIA_CPUID_HAS_RNG	0x000004
+#define	VIA_CPUID_DO_RNG	0x000008
+#define	VIA_CPUID_HAS_ACE	0x000040
+#define	VIA_CPUID_DO_ACE	0x000080
+#define	VIA_CPUID_HAS_ACE2	0x000100
+#define	VIA_CPUID_DO_ACE2	0x000200
+#define	VIA_CPUID_HAS_PHE	0x000400
+#define	VIA_CPUID_DO_PHE	0x000800
+#define	VIA_CPUID_HAS_PMM	0x001000
+#define	VIA_CPUID_DO_PMM	0x002000
+
 #ifndef LOCORE
 
 #ifndef _SYS_TYPES_H_
diff --git a/sys/platform/pc32/i386/identcpu.c b/sys/platform/pc32/i386/identcpu.c
index 4b5e3d7..b95870c 100644
--- a/sys/platform/pc32/i386/identcpu.c
+++ b/sys/platform/pc32/i386/identcpu.c
@@ -80,6 +80,7 @@ static void print_AMD_features(void);
 static void print_AMD_info(void);
 static void print_AMD_assoc(int i);
 static void print_transmeta_info(void);
+static void print_via_padlock_info(void);
 static void setup_tmx86_longrun(void);
 
 int	cpu_class = CPUCLASS_386;
@@ -563,16 +564,13 @@ printcpuinfo(void)
 			break;
 		case 0x690:
 			strcpy(cpu_model, "VIA C3 Nehemiah");
-			do_cpuid(0xc0000000, regs);
-			if (regs[0] == 0xc0000001) {
-				do_cpuid(0xc0000001, regs);
-				if ((cpu_id & 0xf) >= 3)
-					if ((regs[3] & 0x0c) == 0x0c)
-						strcat(cpu_model, "+RNG");
-				if ((cpu_id & 0xf) >= 8)
-					if ((regs[3] & 0xc0) == 0xc0)
-						strcat(cpu_model, "+ACE");
-			}
+			break;
+		case 0x6a0:
+		case 0x6d0:
+			strcpy(cpu_model, "VIA C7 Esther");
+			break;
+		case 0x6f0:
+			strcpy(cpu_model, "VIA Nano");
 			break;
 		default:
 			strcpy(cpu_model, "VIA/IDT Unknown");
@@ -725,6 +723,9 @@ printcpuinfo(void)
 				);
 			}
 
+			if (strcmp(cpu_vendor, "CentaurHauls") == 0)
+				print_via_padlock_info();
+
 			/*
 			 * If this CPU supports hyperthreading then mention
 			 * the number of logical CPU's it contains.
@@ -1418,6 +1419,40 @@ print_transmeta_info(void)
 	       crusoe_frequency, crusoe_voltage, crusoe_percentage);
 }
 
+static void
+print_via_padlock_info(void)
+{
+	u_int regs[4];
+
+	/* Check for supported models. */
+	switch (cpu_id & 0xff0) {
+	case 0x690:
+		if ((cpu_id & 0xf) < 3)
+			return;
+	case 0x6a0:
+	case 0x6d0:
+	case 0x6f0:
+		break;
+	default:
+		return;
+	}
+
+	do_cpuid(0xc0000000, regs);
+	if (regs[0] >= 0xc0000001)
+		do_cpuid(0xc0000001, regs);
+	else
+		return;
+
+	kprintf("\n  VIA Padlock Features=0x%b", regs[3],
+	"\020"
+	"\003RNG"		/* RNG */
+	"\007AES"		/* ACE */
+	"\011AES-CTR"		/* ACE2 */
+	"\013SHA1,SHA256"	/* PHE */
+	"\015RSA"		/* PMM */
+	);
+}
+
 void
 additional_cpu_info(const char *line)
 {
diff --git a/sys/platform/pc32/i386/initcpu.c b/sys/platform/pc32/i386/initcpu.c
index bfc387f..7ddc65f 100644
--- a/sys/platform/pc32/i386/initcpu.c
+++ b/sys/platform/pc32/i386/initcpu.c
@@ -69,6 +69,14 @@ static int	hw_instruction_sse;
 SYSCTL_INT(_hw, OID_AUTO, instruction_sse, CTLFLAG_RD,
     &hw_instruction_sse, 0, "SIMD/MMX2 instructions available in CPU");
 
+u_int	via_feature_rng = 0;	/* VIA RNG features */
+u_int	via_feature_xcrypt = 0;	/* VIA ACE features */
+
+SYSCTL_UINT(_hw, OID_AUTO, via_feature_rng, CTLFLAG_RD,
+	&via_feature_rng, 0, "VIA C3/C7 RNG feature available in CPU");
+SYSCTL_UINT(_hw, OID_AUTO, via_feature_xcrypt, CTLFLAG_RD,
+	&via_feature_xcrypt, 0, "VIA C3/C7 xcrypt feature available in CPU");
+
 #ifndef CPU_DISABLE_SSE
 u_int	cpu_fxsr;		/* SSE enabled */
 #endif
@@ -495,6 +503,70 @@ init_mendocino(void)
 #endif /* CPU_PPRO2CELERON */
 }
 
+/*
+ * Initialize special VIA C3/C7 features
+ */
+static void
+init_via(void)
+{
+	u_int regs[4], val;
+	u_int64_t msreg;
+
+	do_cpuid(0xc0000000, regs);
+	val = regs[0];
+	if (val >= 0xc0000001) {
+		do_cpuid(0xc0000001, regs);
+		val = regs[3];
+	} else
+		val = 0;
+
+	/* Enable RNG if present and disabled */
+	if (val & VIA_CPUID_HAS_RNG) {
+		if (!(val & VIA_CPUID_DO_RNG)) {
+			msreg = rdmsr(0x110B);
+			msreg |= 0x40;
+			wrmsr(0x110B, msreg);
+		}
+		via_feature_rng = VIA_HAS_RNG;
+	}
+	/* Enable AES engine if present and disabled */
+	if (val & VIA_CPUID_HAS_ACE) {
+		if (!(val & VIA_CPUID_DO_ACE)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_AES;
+	}
+	/* Enable ACE2 engine if present and disabled */
+	if (val & VIA_CPUID_HAS_ACE2) {
+		if (!(val & VIA_CPUID_DO_ACE2)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_AESCTR;
+	}
+	/* Enable SHA engine if present and disabled */
+	if (val & VIA_CPUID_HAS_PHE) {
+		if (!(val & VIA_CPUID_DO_PHE)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28/**/);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_SHA;
+	}
+	/* Enable MM engine if present and disabled */
+	if (val & VIA_CPUID_HAS_PMM) {
+		if (!(val & VIA_CPUID_DO_PMM)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28/**/);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_MM;
+	}
+}
+
 #endif /* I686_CPU */
 
 /*
@@ -608,6 +680,20 @@ initializecpu(void)
 			}
 		} else if (strcmp(cpu_vendor, "AuthenticAMD") == 0) {
 			init_686_amd();
+		} else if (strcmp(cpu_vendor, "CentaurHauls") == 0) {
+			switch (cpu_id & 0xff0) {
+			case 0x690:
+				if ((cpu_id & 0xf) < 3)
+					break;
+				/* fall through. */
+			case 0x6a0:
+			case 0x6d0:
+			case 0x6f0:
+				init_via();
+				break;
+			default:
+				break;
+			}
 		}
 		break;
 #endif
diff --git a/sys/platform/pc64/amd64/initcpu.c b/sys/platform/pc64/amd64/initcpu.c
index 8c6771a..11f4b89 100644
--- a/sys/platform/pc64/amd64/initcpu.c
+++ b/sys/platform/pc64/amd64/initcpu.c
@@ -54,6 +54,8 @@ u_int	cpu_feature;		/* Feature flags */
 u_int	cpu_feature2;		/* Feature flags */
 u_int	amd_feature;		/* AMD feature flags */
 u_int	amd_feature2;		/* AMD feature flags */
+u_int	via_feature_rng;	/* VIA RNG features */
+u_int	via_feature_xcrypt;	/* VIA ACE features */
 u_int	cpu_high;		/* Highest arg to CPUID */
 u_int	cpu_exthigh;		/* Highest arg to extended CPUID */
 u_int	cpu_id;			/* Stepping ID */
@@ -64,6 +66,75 @@ u_int	cpu_vendor_id;		/* CPU vendor ID */
 u_int	cpu_fxsr;		/* SSE enabled */
 u_int	cpu_mxcsr_mask;		/* Valid bits in mxcsr */
 
+SYSCTL_UINT(_hw, OID_AUTO, via_feature_rng, CTLFLAG_RD,
+	&via_feature_rng, 0, "VIA C3/C7 RNG feature available in CPU");
+SYSCTL_UINT(_hw, OID_AUTO, via_feature_xcrypt, CTLFLAG_RD,
+	&via_feature_xcrypt, 0, "VIA C3/C7 xcrypt feature available in CPU");
+
+/*
+ * Initialize special VIA C3/C7 features
+ */
+static void
+init_via(void)
+{
+	u_int regs[4], val;
+	u_int64_t msreg;
+
+	do_cpuid(0xc0000000, regs);
+	val = regs[0];
+	if (val >= 0xc0000001) {
+		do_cpuid(0xc0000001, regs);
+		val = regs[3];
+	} else
+		val = 0;
+
+	/* Enable RNG if present and disabled */
+	if (val & VIA_CPUID_HAS_RNG) {
+		if (!(val & VIA_CPUID_DO_RNG)) {
+			msreg = rdmsr(0x110B);
+			msreg |= 0x40;
+			wrmsr(0x110B, msreg);
+		}
+		via_feature_rng = VIA_HAS_RNG;
+	}
+	/* Enable AES engine if present and disabled */
+	if (val & VIA_CPUID_HAS_ACE) {
+		if (!(val & VIA_CPUID_DO_ACE)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_AES;
+	}
+	/* Enable ACE2 engine if present and disabled */
+	if (val & VIA_CPUID_HAS_ACE2) {
+		if (!(val & VIA_CPUID_DO_ACE2)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_AESCTR;
+	}
+	/* Enable SHA engine if present and disabled */
+	if (val & VIA_CPUID_HAS_PHE) {
+		if (!(val & VIA_CPUID_DO_PHE)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28/**/);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_SHA;
+	}
+	/* Enable MM engine if present and disabled */
+	if (val & VIA_CPUID_HAS_PMM) {
+		if (!(val & VIA_CPUID_DO_PMM)) {
+			msreg = rdmsr(0x1107);
+			msreg |= (0x01 << 28/**/);
+			wrmsr(0x1107, msreg);
+		}
+		via_feature_xcrypt |= VIA_HAS_MM;
+	}
+}
+
 /*
  * Initialize CPU control registers
  */
@@ -83,4 +154,8 @@ initializecpu(void)
 		pg_nx = PG_NX;
 #endif
 	}
+	if (cpu_vendor_id == CPU_VENDOR_CENTAUR &&
+	    AMD64_CPU_FAMILY(cpu_id) == 0x6 &&
+	    AMD64_CPU_MODEL(cpu_id) >= 0xf)
+		init_via();
 }
-- 
1.6.2.5

