Branch data Line data Source code
1 : : /*
2 : : * RNG driver for VIA RNGs
3 : : *
4 : : * Copyright 2005 (c) MontaVista Software, Inc.
5 : : *
6 : : * with the majority of the code coming from:
7 : : *
8 : : * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
9 : : * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
10 : : *
11 : : * derived from
12 : : *
13 : : * Hardware driver for the AMD 768 Random Number Generator (RNG)
14 : : * (c) Copyright 2001 Red Hat Inc
15 : : *
16 : : * derived from
17 : : *
18 : : * Hardware driver for Intel i810 Random Number Generator (RNG)
19 : : * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
20 : : * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
21 : : *
22 : : * This file is licensed under the terms of the GNU General Public
23 : : * License version 2. This program is licensed "as is" without any
24 : : * warranty of any kind, whether express or implied.
25 : : */
26 : :
27 : : #include <crypto/padlock.h>
28 : : #include <linux/module.h>
29 : : #include <linux/kernel.h>
30 : : #include <linux/hw_random.h>
31 : : #include <linux/delay.h>
32 : : #include <asm/cpu_device_id.h>
33 : : #include <asm/io.h>
34 : : #include <asm/msr.h>
35 : : #include <asm/cpufeature.h>
36 : : #include <asm/fpu/api.h>
37 : :
38 : :
39 : :
40 : :
41 : : enum {
42 : : VIA_STRFILT_CNT_SHIFT = 16,
43 : : VIA_STRFILT_FAIL = (1 << 15),
44 : : VIA_STRFILT_ENABLE = (1 << 14),
45 : : VIA_RAWBITS_ENABLE = (1 << 13),
46 : : VIA_RNG_ENABLE = (1 << 6),
47 : : VIA_NOISESRC1 = (1 << 8),
48 : : VIA_NOISESRC2 = (1 << 9),
49 : : VIA_XSTORE_CNT_MASK = 0x0F,
50 : :
51 : : VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */
52 : : VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */
53 : : VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF,
54 : : VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */
55 : : VIA_RNG_CHUNK_2_MASK = 0xFFFF,
56 : : VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */
57 : : VIA_RNG_CHUNK_1_MASK = 0xFF,
58 : : };
59 : :
60 : : /*
61 : : * Investigate using the 'rep' prefix to obtain 32 bits of random data
62 : : * in one insn. The upside is potentially better performance. The
63 : : * downside is that the instruction becomes no longer atomic. Due to
64 : : * this, just like familiar issues with /dev/random itself, the worst
65 : : * case of a 'rep xstore' could potentially pause a cpu for an
66 : : * unreasonably long time. In practice, this condition would likely
67 : : * only occur when the hardware is failing. (or so we hope :))
68 : : *
69 : : * Another possible performance boost may come from simply buffering
70 : : * until we have 4 bytes, thus returning a u32 at a time,
71 : : * instead of the current u8-at-a-time.
72 : : *
73 : : * Padlock instructions can generate a spurious DNA fault, but the
74 : : * kernel doesn't use CR0.TS, so this doesn't matter.
75 : : */
76 : :
77 : 0 : static inline u32 xstore(u32 *addr, u32 edx_in)
78 : : {
79 : 0 : u32 eax_out;
80 : :
81 : 0 : asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
82 : : : "=m" (*addr), "=a" (eax_out), "+d" (edx_in), "+D" (addr));
83 : :
84 : 0 : return eax_out;
85 : : }
86 : :
87 : 0 : static int via_rng_data_present(struct hwrng *rng, int wait)
88 : : {
89 : 0 : char buf[16 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__
90 : : ((aligned(STACK_ALIGN)));
91 : 0 : u32 *via_rng_datum = (u32 *)PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT);
92 : 0 : u32 bytes_out;
93 : 0 : int i;
94 : :
95 : : /* We choose the recommended 1-byte-per-instruction RNG rate,
96 : : * for greater randomness at the expense of speed. Larger
97 : : * values 2, 4, or 8 bytes-per-instruction yield greater
98 : : * speed at lesser randomness.
99 : : *
100 : : * If you change this to another VIA_CHUNK_n, you must also
101 : : * change the ->n_bytes values in rng_vendor_ops[] tables.
102 : : * VIA_CHUNK_8 requires further code changes.
103 : : *
104 : : * A copy of MSR_VIA_RNG is placed in eax_out when xstore
105 : : * completes.
106 : : */
107 : :
108 [ # # ]: 0 : for (i = 0; i < 20; i++) {
109 : 0 : *via_rng_datum = 0; /* paranoia, not really necessary */
110 : 0 : bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1);
111 : 0 : bytes_out &= VIA_XSTORE_CNT_MASK;
112 [ # # ]: 0 : if (bytes_out || !wait)
113 : : break;
114 : 0 : udelay(10);
115 : : }
116 : 0 : rng->priv = *via_rng_datum;
117 : 0 : return bytes_out ? 1 : 0;
118 : : }
119 : :
120 : 0 : static int via_rng_data_read(struct hwrng *rng, u32 *data)
121 : : {
122 : 0 : u32 via_rng_datum = (u32)rng->priv;
123 : :
124 : 0 : *data = via_rng_datum;
125 : :
126 : 0 : return 1;
127 : : }
128 : :
129 : 0 : static int via_rng_init(struct hwrng *rng)
130 : : {
131 : 0 : struct cpuinfo_x86 *c = &cpu_data(0);
132 : 0 : u32 lo, hi, old_lo;
133 : :
134 : : /* VIA Nano CPUs don't have the MSR_VIA_RNG anymore. The RNG
135 : : * is always enabled if CPUID rng_en is set. There is no
136 : : * RNG configuration like it used to be the case in this
137 : : * register */
138 [ # # # # : 0 : if (((c->x86 == 6) && (c->x86_model >= 0x0f)) || (c->x86 > 6)){
# # ]
139 [ # # ]: 0 : if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) {
140 : 0 : pr_err(PFX "can't enable hardware RNG "
141 : : "if XSTORE is not enabled\n");
142 : 0 : return -ENODEV;
143 : : }
144 : : return 0;
145 : : }
146 : :
147 : : /* Control the RNG via MSR. Tread lightly and pay very close
148 : : * close attention to values written, as the reserved fields
149 : : * are documented to be "undefined and unpredictable"; but it
150 : : * does not say to write them as zero, so I make a guess that
151 : : * we restore the values we find in the register.
152 : : */
153 : 0 : rdmsr(MSR_VIA_RNG, lo, hi);
154 : :
155 : 0 : old_lo = lo;
156 : 0 : lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT);
157 : 0 : lo &= ~VIA_XSTORE_CNT_MASK;
158 : 0 : lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE);
159 : 0 : lo |= VIA_RNG_ENABLE;
160 : 0 : lo |= VIA_NOISESRC1;
161 : :
162 : : /* Enable secondary noise source on CPUs where it is present. */
163 : :
164 : : /* Nehemiah stepping 8 and higher */
165 [ # # # # ]: 0 : if ((c->x86_model == 9) && (c->x86_stepping > 7))
166 : 0 : lo |= VIA_NOISESRC2;
167 : :
168 : : /* Esther */
169 [ # # ]: 0 : if (c->x86_model >= 10)
170 : 0 : lo |= VIA_NOISESRC2;
171 : :
172 [ # # ]: 0 : if (lo != old_lo)
173 : 0 : wrmsr(MSR_VIA_RNG, lo, hi);
174 : :
175 : : /* perhaps-unnecessary sanity check; remove after testing if
176 : : unneeded */
177 : 0 : rdmsr(MSR_VIA_RNG, lo, hi);
178 [ # # ]: 0 : if ((lo & VIA_RNG_ENABLE) == 0) {
179 : 0 : pr_err(PFX "cannot enable VIA C3 RNG, aborting\n");
180 : 0 : return -ENODEV;
181 : : }
182 : :
183 : : return 0;
184 : : }
185 : :
186 : :
187 : : static struct hwrng via_rng = {
188 : : .name = "via",
189 : : .init = via_rng_init,
190 : : .data_present = via_rng_data_present,
191 : : .data_read = via_rng_data_read,
192 : : };
193 : :
194 : :
195 : 13 : static int __init mod_init(void)
196 : : {
197 : 13 : int err;
198 : :
199 [ - + ]: 13 : if (!boot_cpu_has(X86_FEATURE_XSTORE))
200 : : return -ENODEV;
201 : :
202 : 0 : pr_info("VIA RNG detected\n");
203 : 0 : err = hwrng_register(&via_rng);
204 [ # # ]: 0 : if (err) {
205 : 0 : pr_err(PFX "RNG registering failed (%d)\n",
206 : : err);
207 : 0 : goto out;
208 : : }
209 : 0 : out:
210 : : return err;
211 : : }
212 : :
213 : 0 : static void __exit mod_exit(void)
214 : : {
215 : 0 : hwrng_unregister(&via_rng);
216 : 0 : }
217 : :
218 : : module_init(mod_init);
219 : : module_exit(mod_exit);
220 : :
221 : : static struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = {
222 : : X86_FEATURE_MATCH(X86_FEATURE_XSTORE),
223 : : {}
224 : : };
225 : :
226 : : MODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock");
227 : : MODULE_LICENSE("GPL");
228 : : MODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id);
|