From: Jeff Garzik <jgarzik@pobox.com>
To: lkml <linux-kernel@vger.kernel.org>,
Linus Torvalds <torvalds@transmeta.com>,
Alan Cox <alan@lxorguk.ukuu.org.uk>,
"Theodore Ts'o" <tytso@mit.edu>
Cc: Dave Jones <davej@codemonkey.org.uk>
Subject: [patch 3/3] add Via Nehemiah ("xstore") rng support
Date: Tue, 11 Mar 2003 22:27:05 -0500 [thread overview]
Message-ID: <3E6EA909.9020200@pobox.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 816 bytes --]
Via came up with a nifty feature on their "Nehemiah" generation of the
C3 CPU: the xstore instruction. If the 'rep' prefix is not present, the
instruction stores 0/1/2/4/8 bytes of random data to a memory location.
This xstore instruction forms the basis of this third patch, which adds
support for the Via RNG to the newly-modular hw_random driver.
Note that since xstore is a new instruction, GNU binutils does not
support it. We must use gcc inline asm to hand-code the machine
language instruction in hexidecimal. Eventually I will get around to
patching GNU binutils to support xstore natively, but even then we won't
want to force users to update their binutils to bleeding-edge-latest, I
don't think...
Review from x86 experts is especially appreciated here, as I am from an
x86 expert myself.
[-- Attachment #2: patch2 --]
[-- Type: text/plain, Size: 9338 bytes --]
# --------------------------------------------
# 03/03/11 jgarzik@redhat.com 1.1103
# [hw_random] add support for Via Nehemiah RNG ("xstore" insn)
# --------------------------------------------
#
diff -Nru a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
--- a/arch/i386/kernel/cpu/centaur.c Tue Mar 11 21:37:50 2003
+++ b/arch/i386/kernel/cpu/centaur.c Tue Mar 11 21:37:50 2003
@@ -248,6 +248,36 @@
}
#endif
+static void __init init_c3(struct cpuinfo_x86 *c)
+{
+ u32 lo, hi;
+
+ /* Test for Centaur Extended Feature Flags presence */
+ if (cpuid_eax(0xC0000000) >= 0xC0000001) {
+ set_bit(X86_FEATURE_CENTAUR_EFF, c->x86_capability);
+
+ /* test for on-chip RNG */
+ if (cpuid_edx(0xC0000001) & (1 << 2))
+ set_bit(X86_FEATURE_XSTORE, c->x86_capability);
+ }
+
+ switch (c->x86_model) {
+ case 6 ... 8: /* Cyrix III family */
+ rdmsr (MSR_VIA_FCR, lo, hi);
+ lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */
+ wrmsr (MSR_VIA_FCR, lo, hi);
+
+ set_bit(X86_FEATURE_CX8, c->x86_capability);
+ set_bit(X86_FEATURE_3DNOW, c->x86_capability);
+
+ case 9: /* Nehemiah */
+ default:
+ get_model_name(c);
+ display_cacheinfo(c);
+ break;
+ }
+}
+
static void __init init_centaur(struct cpuinfo_x86 *c)
{
enum {
@@ -386,21 +416,7 @@
break;
case 6:
- switch (c->x86_model) {
- case 6 ... 8: /* Cyrix III family */
- rdmsr (MSR_VIA_FCR, lo, hi);
- lo |= (1<<1 | 1<<7); /* Report CX8 & enable PGE */
- wrmsr (MSR_VIA_FCR, lo, hi);
-
- set_bit(X86_FEATURE_CX8, c->x86_capability);
- set_bit(X86_FEATURE_3DNOW, c->x86_capability);
-
- case 9: /* Nehemiah */
- default:
- get_model_name(c);
- display_cacheinfo(c);
- break;
- }
+ init_c3(c);
break;
}
}
diff -Nru a/arch/i386/kernel/cpu/proc.c b/arch/i386/kernel/cpu/proc.c
--- a/arch/i386/kernel/cpu/proc.c Tue Mar 11 21:37:50 2003
+++ b/arch/i386/kernel/cpu/proc.c Tue Mar 11 21:37:50 2003
@@ -37,7 +37,8 @@
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
/* Other (Linux-defined) */
- "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr", NULL, NULL, NULL, NULL,
+ "cxmmx", "k6_mtrr", "cyrix_arr", "centaur_mcr",
+ "centaur_eff", "xstore", NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig
--- a/drivers/char/Kconfig Tue Mar 11 21:37:50 2003
+++ b/drivers/char/Kconfig Tue Mar 11 21:37:50 2003
@@ -710,7 +710,7 @@
If you're not sure, say N.
config HW_RANDOM
- tristate "Intel/AMD H/W Random Number Generator support"
+ tristate "Intel/AMD/Via H/W Random Number Generator support"
depends on (X86 || IA64) && PCI
---help---
This driver provides kernel-side support for the Random Number
diff -Nru a/drivers/char/hw_random.c b/drivers/char/hw_random.c
--- a/drivers/char/hw_random.c Tue Mar 11 21:37:50 2003
+++ b/drivers/char/hw_random.c Tue Mar 11 21:37:50 2003
@@ -1,5 +1,5 @@
/*
- Hardware driver for the Intel/AMD Random Number Generators (RNG)
+ Hardware driver for the Intel/AMD/Via Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
derived from
@@ -35,6 +35,11 @@
#include <linux/mm.h>
#include <linux/delay.h>
+#ifdef __i386__
+#include <asm/msr.h>
+#include <asm/cpufeature.h>
+#endif
+
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -88,6 +93,11 @@
static unsigned int amd_data_present (void);
static u32 amd_data_read (void);
+static int __init via_init(struct pci_dev *dev);
+static void __exit via_cleanup(void);
+static unsigned int via_data_present (void);
+static u32 via_data_read (void);
+
struct rng_operations {
int (*init) (struct pci_dev *dev);
void (*cleanup) (void);
@@ -117,6 +127,7 @@
rng_hw_none,
rng_hw_intel,
rng_hw_amd,
+ rng_hw_via,
};
static struct rng_operations rng_vendor_ops[] __initdata = {
@@ -129,6 +140,9 @@
/* rng_hw_amd */
{ amd_init, amd_cleanup, amd_data_present, amd_data_read, 4 },
+
+ /* rng_hw_via */
+ { via_init, via_cleanup, via_data_present, via_data_read, 1 },
};
/*
@@ -332,6 +346,127 @@
/***********************************************************************
*
+ * Via RNG operations
+ *
+ */
+
+enum {
+ VIA_STRFILT_CNT_SHIFT = 16,
+ VIA_STRFILT_FAIL = (1 << 15),
+ VIA_STRFILT_ENABLE = (1 << 14),
+ VIA_RAWBITS_ENABLE = (1 << 13),
+ VIA_RNG_ENABLE = (1 << 6),
+ VIA_XSTORE_CNT_MASK = 0x0F,
+
+ VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
+ VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF,
+ VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_2_MASK = 0xFFFF,
+ VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */
+ VIA_RNG_CHUNK_1_MASK = 0xFF,
+};
+
+u32 via_rng_datum;
+
+/*
+ * Investigate using the 'rep' prefix to obtain 32 bits of random data
+ * in one insn. The upside is potentially better performance. The
+ * downside is that the instruction becomes no longer atomic. Due to
+ * this, just like familiar issues with /dev/random itself, the worst
+ * case of a 'rep xstore' could potentially pause a cpu for an
+ * unreasonably long time. In practice, this condition would likely
+ * only occur when the hardware is failing. (or so we hope :))
+ *
+ * Another possible performance boost may come from simply buffering
+ * until we have 4 bytes, thus returning a u32 at a time,
+ * instead of the current u8-at-a-time.
+ */
+
+static inline u32 xstore(u32 *addr, u32 edx_in)
+{
+ u32 eax_out;
+
+ asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
+ :"=m"(*addr), "=a"(eax_out)
+ :"D"(addr), "d"(edx_in));
+
+ return eax_out;
+}
+
+static unsigned int via_data_present(void)
+{
+ u32 bytes_out;
+
+ /* We choose the recommended 1-byte-per-instruction RNG rate,
+ * for greater randomness at the expense of speed. Larger
+ * values 2, 4, or 8 bytes-per-instruction yield greater
+ * speed at lesser randomness.
+ *
+ * If you change this to another VIA_CHUNK_n, you must also
+ * change the ->n_bytes values in rng_vendor_ops[] tables.
+ * VIA_CHUNK_8 requires further code changes.
+ *
+ * A copy of MSR_VIA_RNG is placed in eax_out when xstore
+ * completes.
+ */
+ via_rng_datum = 0; /* paranoia, not really necessary */
+ bytes_out = xstore(&via_rng_datum, VIA_RNG_CHUNK_1) & VIA_XSTORE_CNT_MASK;
+ if (bytes_out == 0)
+ return 0;
+
+ return 1;
+}
+
+static u32 via_data_read(void)
+{
+ return via_rng_datum;
+}
+
+static int __init via_init(struct pci_dev *dev)
+{
+ u32 lo, hi, old_lo;
+
+ /* Control the RNG via MSR. Tread lightly and pay very close
+ * close attention to values written, as the reserved fields
+ * are documented to be "undefined and unpredictable"; but it
+ * does not say to write them as zero, so I make a guess that
+ * we restore the values we find in the register.
+ */
+ rdmsr(MSR_VIA_RNG, lo, hi);
+
+ old_lo = lo;
+ lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
+ lo &= ~VIA_XSTORE_CNT_MASK;
+ lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
+ lo |= VIA_RNG_ENABLE;
+
+ if (lo != old_lo)
+ wrmsr(MSR_VIA_RNG, lo, hi);
+
+ /* perhaps-unnecessary sanity check; remove after testing if
+ unneeded */
+ rdmsr(MSR_VIA_RNG, lo, hi);
+ if ((lo & VIA_RNG_ENABLE) == 0) {
+ printk(KERN_ERR PFX "cannot enable Via C3 RNG, aborting\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void __exit via_cleanup(void)
+{
+ u32 lo, hi;
+
+ rdmsr(MSR_VIA_RNG, lo, hi);
+ lo &= ~VIA_RNG_ENABLE;
+ wrmsr(MSR_VIA_RNG, lo, hi);
+}
+
+
+/***********************************************************************
+ *
* /dev/hwrandom character device handling (major 10, minor 183)
*
*/
@@ -470,6 +605,15 @@
goto match;
}
}
+
+#ifdef __i386__
+ /* Probe for Via RNG */
+ if (cpu_has_xstore) {
+ rng_ops = &rng_vendor_ops[rng_hw_via];
+ pdev = NULL;
+ goto match;
+ }
+#endif
DPRINTK ("EXIT, returning -ENODEV\n");
return -ENODEV;
diff -Nru a/include/asm-i386/cpufeature.h b/include/asm-i386/cpufeature.h
--- a/include/asm-i386/cpufeature.h Tue Mar 11 21:37:50 2003
+++ b/include/asm-i386/cpufeature.h Tue Mar 11 21:37:50 2003
@@ -63,6 +63,8 @@
#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
+#define X86_FEATURE_CENTAUR_EFF (3*32+ 4) /* Centaur Extended Feature Flags */
+#define X86_FEATURE_XSTORE (3*32+ 5) /* on-CPU RNG present (xstore insn) */
#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
@@ -87,6 +89,7 @@
#define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR)
#define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR)
#define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
+#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE)
#endif /* __ASM_I386_CPUFEATURE_H */
diff -Nru a/include/asm-i386/msr.h b/include/asm-i386/msr.h
--- a/include/asm-i386/msr.h Tue Mar 11 21:37:50 2003
+++ b/include/asm-i386/msr.h Tue Mar 11 21:37:50 2003
@@ -218,6 +218,7 @@
/* VIA Cyrix defined MSRs*/
#define MSR_VIA_FCR 0x1107
#define MSR_VIA_LONGHAUL 0x110a
+#define MSR_VIA_RNG 0x110b
#define MSR_VIA_BCR2 0x1147
/* Transmeta defined MSRs */
next reply other threads:[~2003-03-12 3:16 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2003-03-12 3:27 Jeff Garzik [this message]
2003-03-12 3:31 ` [patch 3/3] add Via Nehemiah ("xstore") rng support Jeff Garzik
2003-03-12 12:55 ` Dave Jones
2003-03-12 15:16 ` Linus Torvalds
2003-03-12 16:21 ` H. Peter Anvin
2003-03-12 17:56 ` Dave Jones
[not found] <200303120427.UAA00323@cesium.transmeta.com>
2003-03-12 5:16 ` Jeff Garzik
2003-03-12 5:19 ` H. Peter Anvin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3E6EA909.9020200@pobox.com \
--to=jgarzik@pobox.com \
--cc=alan@lxorguk.ukuu.org.uk \
--cc=davej@codemonkey.org.uk \
--cc=linux-kernel@vger.kernel.org \
--cc=torvalds@transmeta.com \
--cc=tytso@mit.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.