Subject: VIA C3 RNG support
To: None <port-i386@netbsd.org>
From: Allen Briggs <briggs@netbsd.org>
List: port-i386
Date: 08/09/2004 00:39:37
--xHFwDpU9dbj6ez1V
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi x86ers,

I'm not currently subscribed to this list, so please copy me on any
discussion.

I've now got a system with a VIA C3 "Nehemiah" CPU in it.  As you
may know, some of these have random number generators on board.
The attached patches allow me to use the on-board RNGs as an entropy
source for rnd(4).  I am not terribly familiar with the i386/x86-
specific bits, though, so I'm soliciting comments on these changes.
Does this method of plugging in the RNG make sense in the x86
universe?  If not, what would you suggest?

Thanks,
-allen

-- 
                  Use NetBSD!  http://www.netbsd.org/

--xHFwDpU9dbj6ez1V
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=via_rng_diff

Index: i386/i386/cpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/cpu.c,v
retrieving revision 1.19
diff -u -r1.19 cpu.c
--- i386/i386/cpu.c	30 Apr 2004 02:05:43 -0000	1.19
+++ i386/i386/cpu.c	9 Aug 2004 04:27:12 -0000
@@ -77,6 +77,7 @@
 #include "opt_multiprocessor.h"
 #include "opt_mpbios.h"		/* for MPDEBUG */
 #include "opt_mtrr.h"
+#include "opt_viapadlock.h"
 
 #include "lapic.h"
 #include "ioapic.h"
@@ -461,6 +462,12 @@
 		}
 	}
 #endif /* MTRR */
+#ifdef VIA_RNG
+	if (ci->ci_ext_features & CPUID_FEAT_VRNG) {
+		ci->ci_vp.vp_ci = ci;
+		via_rng_attach(&ci->ci_vp);
+	}
+#endif /* VIA_RNG */
 
 #ifdef MULTIPROCESSOR
 	ci->ci_flags |= CPUF_RUNNING;
Index: i386/i386/identcpu.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/identcpu.c,v
retrieving revision 1.16
diff -u -r1.16 identcpu.c
--- i386/i386/identcpu.c	8 Aug 2004 05:21:01 -0000	1.16
+++ i386/i386/identcpu.c	9 Aug 2004 04:27:13 -0000
@@ -1,7 +1,7 @@
 
 /*-
- * Copyright (c) 1999, 2000, 2001 The NetBSD Foundation, Inc.
+ * Copyright (c) 1999, 2000, 2001, 2004 The NetBSD Foundation, Inc.
  * All rights reserved.
  *
  * This code is derived from software contributed to The NetBSD Foundation
@@ -598,6 +598,8 @@
 void
 via_cpu_probe(struct cpu_info *ci)
 {
+	u_int model = CPUID2MODEL(ci->ci_signature);
+	u_int stepping = CPUID2STEPPING(ci->ci_signature);
 	u_int descs[4];
 	u_int lfunc;
 
@@ -614,6 +616,38 @@
 		CPUID(0x80000001, descs[0], descs[1], descs[2], descs[3]);
 		ci->ci_feature_flags |= descs[3];
 	}
+
+	if (model >= 0x9) {
+		/* Nehemiah or Esther */
+		CPUID(0xc0000000, descs[0], descs[1], descs[2], descs[3]);
+		lfunc = descs[0];
+		if (lfunc == 0xc0000001) {
+			CPUID(lfunc, descs[0], descs[1], descs[2], descs[3]);
+			lfunc = descs[3];
+			if (model > 0x9 || stepping >= 3)	/* RNG */
+				if ((lfunc & 0x0c) == 0x0c)
+					ci->ci_ext_features |= CPUID_FEAT_VRNG;
+			if (model > 0x9 || stepping >= 8) {	/* ACE */
+				if ((lfunc & 0xc0) == 0xc0) {
+					ci->ci_ext_features |= CPUID_FEAT_VACE;
+				}
+
+				/*
+				 * If we have the RNG and we're on Esther
+				 * or Nehemiah stepping >= 8, enable both
+				 * RNG sources.  Earlier steppings have
+				 * only one source.
+				 */
+				if (ci->ci_ext_features & CPUID_FEAT_VRNG) {
+					u_int msr;
+
+				    	msr = rdmsr(MSR_VIA_RNG) & ~0x1f;
+					wrmsr(MSR_VIA_RNG,
+						msr | MSR_VIA_RNG_2NOISE);
+				}
+			}
+		}
+	}
 }
 
 const char *
@@ -1236,6 +1270,12 @@
 		printf("%s: features2 %s\n", cpuname, buf);
 	}
 
+	if (ci->ci_ext_features) {
+		bitmask_snprintf(ci->ci_ext_features,
+		    CPUID_FEAT_FLAGS, buf, sizeof(buf));
+		printf("%s: ext. features %s\n", cpuname, buf);
+	}
+
 	if (*cpu_brand_string != '\0')
 		printf("%s: \"%s\"\n", cpuname, cpu_brand_string);
 
Index: i386/include/cpu.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/include/cpu.h,v
retrieving revision 1.115
diff -u -r1.115 cpu.h
--- i386/include/cpu.h	16 May 2004 12:32:53 -0000	1.115
+++ i386/include/cpu.h	9 Aug 2004 04:27:13 -0000
@@ -53,6 +53,7 @@
 #include <machine/tss.h>
 #include <machine/intrdefs.h>
 #include <x86/cacheinfo.h>
+#include <x86/via_padlock.h>
 
 #include <sys/device.h>
 #include <sys/lock.h>			/* will also get LOCKDEBUG */
@@ -120,6 +121,7 @@
 	u_int32_t	ci_signature;	 /* X86 cpuid type */
 	u_int32_t	ci_feature_flags;/* X86 %edx CPUID feature bits */
 	u_int32_t	ci_feature2_flags;/* X86 %ecx CPUID feature bits */
+	u_int32_t	ci_ext_features; /* feature bits not in base CPUID */
 	u_int32_t	ci_cpu_class;	 /* CPU class */
 	u_int32_t	ci_brand_id;	 /* Intel brand id */
 	u_int32_t	ci_vendor[4];	 /* vendor string */
@@ -155,6 +157,8 @@
 	char *ci_ddbipi_stack;
 
 	struct evcnt ci_ipi_events[X86_NIPI];
+
+	struct via_padlock	ci_vp;	/* VIA PadLock private storage */
 };
 
 /*
Index: x86/conf/files.x86
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/conf/files.x86,v
retrieving revision 1.10
diff -u -r1.10 files.x86
--- x86/conf/files.x86	8 Oct 2003 17:30:00 -0000	1.10
+++ x86/conf/files.x86	9 Aug 2004 04:27:14 -0000
@@ -7,6 +7,9 @@
 # MTRR support
 defflag                 MTRR
 
+# VIA PadLock (RNG and crypto accelerator) support
+defflag opt_viapadlock.h VIA_RNG VIA_ACE
+
 define  mainbus { [apid = -1] }
 
 file	arch/x86/x86/apic.c		ioapic | lapic
@@ -20,6 +23,7 @@
 file	arch/x86/x86/lock_machdep.c	lockdebug
 file	arch/x86/x86/mtrr_i686.c	mtrr
 file	arch/x86/x86/softintr.c
+file	arch/x86/x86/via_padlock.c	via_rng | via_ace
 
 define lapic
 file	arch/x86/x86/lapic.c		lapic needs-flag
Index: x86/include/specialreg.h
===================================================================
RCS file: /cvsroot/src/sys/arch/x86/include/specialreg.h,v
retrieving revision 1.6
diff -u -r1.6 specialreg.h
--- x86/include/specialreg.h	17 May 2004 15:38:17 -0000	1.6
+++ x86/include/specialreg.h	9 Aug 2004 04:27:14 -0000
@@ -145,6 +145,16 @@
 				    "\0373DNOW2\0403DNOW"
 
 /*
+ * "Features" that are copied from elsewhere -- not necessarily tied to
+ * a specific CPUID response
+ */
+
+#define CPUID_FEAT_VRNG	0x00000001	/* VIA C3 Random Number Generator */
+#define CPUID_FEAT_VACE	0x00000002	/* VIA C3 AES Crypto Extension */
+
+#define CPUID_FEAT_FLAGS	"\20\01VRNG\02VACE"
+
+/*
  * CPUID "features" bits in %ecx
  */
 
@@ -264,6 +274,16 @@
 #define MSR_MC3_MISC		0x413
 
 /*
+ * VIA "Nehemiah" MSRs
+ */
+#define MSR_VIA_RNG		0x110b
+#define MSR_VIA_RNG_ENABLE	0x00000040
+#define MSR_VIA_RNG_NOISE_MASK	0x00000300
+#define MSR_VIA_RNG_NOISE_A	0x00000000
+#define MSR_VIA_RNG_NOISE_B	0x00000100
+#define MSR_VIA_RNG_2NOISE	0x00000300
+
+/*
  * AMD K6/K7 MSRs.
  */
 #define	MSR_K6_UWCCR		0xc0000085
Index: x86/include/via_padlock.h
===================================================================
--- /dev/null	2004-08-08 23:20:01.000000000 -0400
+++ x86/include/via_padlock.h	2004-08-09 00:22:59.000000000 -0400
@@ -0,0 +1,53 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _X86_VIA_PADLOCK_H_
+#define _X86_VIA_PADLOCK_H_
+
+#include <sys/callout.h>
+#include <sys/rnd.h>
+
+struct cpu_info;
+
+struct via_padlock {
+	struct cpu_info		*vp_ci;
+	struct callout		vp_rng_ch;
+	rndsource_element_t	vp_rng_src;
+	int			vp_freq;
+};
+
+void	via_rng_attach(struct via_padlock *vp);
+
+#endif	/* _X86_VIA_PADLOCK_H_ */
Index: x86/x86/via_padlock.c
===================================================================
--- /dev/null	2004-08-08 23:20:01.000000000 -0400
+++ x86/x86/via_padlock.c	2004-08-09 00:21:18.000000000 -0400
@@ -0,0 +1,154 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2004 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the NetBSD
+ *	Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include "opt_viapadlock.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/callout.h>
+#include <sys/device.h>
+#include <sys/rnd.h>
+
+#include <machine/cpu.h>
+#include <x86/specialreg.h>
+
+#ifdef VIA_RNG
+static inline int via_rng_get_4bytes(void *);
+
+/*
+ * Grab 4 bytes of random data.  Uses the "rate" code to get 4 bytes
+ * of data if at least 8 bytes of entropy are available.  This is a
+ * compromise between the most data we can get in one shot (8 bytes),
+ * and the best random data we can get in one shot (1 byte).
+ */
+static inline int
+via_rng_get_4bytes(void *buf)
+{
+	u_int32_t	rv=0;
+
+	__asm __volatile(
+		"movl $1, %%edx\n"
+		".byte	0x0f, 0xa7, 0xc0"
+		: "=a" (rv), "+D" (buf)
+		: 
+		: "memory", "%edx");
+
+	return (rv & 0x1f);
+}
+
+void via_rng_callout(void *v);
+
+void
+via_rng_attach(struct via_padlock *vp)
+{
+	int		cnt, total, n;
+	u_int32_t	rndbuf, cr0;
+
+	/*
+	 * Do some initial testing by pulling some arbitrary amount of
+	 * randomness off the top.  If we can't get at least 32 bytes,
+	 * then something is terribly wrong, so don't enable this as an
+	 * entropy source.  If we do get at least 32 bytes, then assume
+	 * we're working OK and start the callout.
+	 */
+	cr0 = rcr0();
+	lcr0(cr0 & ~(CR0_EM | CR0_TS));
+
+	for (cnt=0, total=0 ; cnt < 1000 && total < 32 ; cnt++, total += n) {
+		n = via_rng_get_4bytes(&rndbuf);
+		if (n == 0) {
+			delay(1);
+		}
+	}
+
+	lcr0(cr0);
+
+	if (total < 32) {
+		aprint_error("%s: RNG failed startup test\n",
+			vp->vp_ci->ci_dev->dv_xname);
+	} else {
+		/*
+		 * Got randomness.  Enable entropy source.
+		 * Frequency is at most 100 times / sec.
+		 */
+		vp->vp_freq = hz > 100 ? hz / 100 : 1;
+
+		callout_init(&vp->vp_rng_ch);
+		rnd_attach_source(&vp->vp_rng_src, vp->vp_ci->ci_dev->dv_xname,
+				  RND_TYPE_RNG, RND_FLAG_NO_ESTIMATE);
+		via_rng_callout(vp);
+
+		aprint_verbose("%s: on-board RNG attached\n",
+			vp->vp_ci->ci_dev->dv_xname);
+	}
+}
+
+void
+via_rng_callout(void *v)
+{
+	struct via_padlock *vp = (struct via_padlock *) v;
+	u_int32_t	*r, rndbuf[4], cr0;
+	int		nw, nb;
+
+	cr0 = rcr0();
+	lcr0(cr0 & ~(CR0_EM | CR0_TS));
+
+	/*
+	 * Pull 4-byte chunks as long as they're available, up to
+	 * 16 bytes total.  Why 16?  Because a (small) sample showed
+	 * me that, at least with a 1.2GHz Nehemiah, we would have to
+	 * wait for more data than that.
+	 */
+	for (nw=0, r = rndbuf; nw<4 && nb>0 ; ) {
+		nb = via_rng_get_4bytes(r);
+		if (nb == 4) {
+			r++; nw++;
+		}
+	}
+
+	lcr0(cr0);
+
+	if (nw) {
+		nb = nw * 4;
+		rnd_add_data(&vp->vp_rng_src, rndbuf, nb, nb * NBBY);
+	}
+
+	callout_reset(&vp->vp_rng_ch, vp->vp_freq, via_rng_callout, vp);
+}
+#endif /* VIA_RNG */

--xHFwDpU9dbj6ez1V--