162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * RNG driver for VIA RNGs 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright 2005 (c) MontaVista Software, Inc. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * with the majority of the code coming from: 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) 962306a36Sopenharmony_ci * (c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * derived from 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * Hardware driver for the AMD 768 Random Number Generator (RNG) 1462306a36Sopenharmony_ci * (c) Copyright 2001 Red Hat Inc 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * derived from 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Hardware driver for Intel i810 Random Number Generator (RNG) 1962306a36Sopenharmony_ci * Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com> 2062306a36Sopenharmony_ci * Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com> 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 2362306a36Sopenharmony_ci * License version 2. This program is licensed "as is" without any 2462306a36Sopenharmony_ci * warranty of any kind, whether express or implied. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <crypto/padlock.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci#include <linux/kernel.h> 3062306a36Sopenharmony_ci#include <linux/hw_random.h> 3162306a36Sopenharmony_ci#include <linux/delay.h> 3262306a36Sopenharmony_ci#include <asm/cpu_device_id.h> 3362306a36Sopenharmony_ci#include <asm/io.h> 3462306a36Sopenharmony_ci#include <asm/msr.h> 3562306a36Sopenharmony_ci#include <asm/cpufeature.h> 3662306a36Sopenharmony_ci#include <asm/fpu/api.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum { 4262306a36Sopenharmony_ci VIA_STRFILT_CNT_SHIFT = 16, 4362306a36Sopenharmony_ci VIA_STRFILT_FAIL = (1 << 15), 4462306a36Sopenharmony_ci VIA_STRFILT_ENABLE = (1 << 14), 4562306a36Sopenharmony_ci VIA_RAWBITS_ENABLE = (1 << 13), 4662306a36Sopenharmony_ci VIA_RNG_ENABLE = (1 << 6), 4762306a36Sopenharmony_ci VIA_NOISESRC1 = (1 << 8), 4862306a36Sopenharmony_ci VIA_NOISESRC2 = (1 << 9), 4962306a36Sopenharmony_ci VIA_XSTORE_CNT_MASK = 0x0F, 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci VIA_RNG_CHUNK_8 = 0x00, /* 64 rand bits, 64 stored bits */ 5262306a36Sopenharmony_ci VIA_RNG_CHUNK_4 = 0x01, /* 32 rand bits, 32 stored bits */ 5362306a36Sopenharmony_ci VIA_RNG_CHUNK_4_MASK = 0xFFFFFFFF, 5462306a36Sopenharmony_ci VIA_RNG_CHUNK_2 = 0x02, /* 16 rand bits, 32 stored bits */ 5562306a36Sopenharmony_ci VIA_RNG_CHUNK_2_MASK = 0xFFFF, 5662306a36Sopenharmony_ci VIA_RNG_CHUNK_1 = 0x03, /* 8 rand bits, 32 stored bits */ 5762306a36Sopenharmony_ci VIA_RNG_CHUNK_1_MASK = 0xFF, 5862306a36Sopenharmony_ci}; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* 6162306a36Sopenharmony_ci * Investigate using the 'rep' prefix to obtain 32 bits of random data 6262306a36Sopenharmony_ci * in one insn. The upside is potentially better performance. The 6362306a36Sopenharmony_ci * downside is that the instruction becomes no longer atomic. Due to 6462306a36Sopenharmony_ci * this, just like familiar issues with /dev/random itself, the worst 6562306a36Sopenharmony_ci * case of a 'rep xstore' could potentially pause a cpu for an 6662306a36Sopenharmony_ci * unreasonably long time. In practice, this condition would likely 6762306a36Sopenharmony_ci * only occur when the hardware is failing. (or so we hope :)) 6862306a36Sopenharmony_ci * 6962306a36Sopenharmony_ci * Another possible performance boost may come from simply buffering 7062306a36Sopenharmony_ci * until we have 4 bytes, thus returning a u32 at a time, 7162306a36Sopenharmony_ci * instead of the current u8-at-a-time. 7262306a36Sopenharmony_ci * 7362306a36Sopenharmony_ci * Padlock instructions can generate a spurious DNA fault, but the 7462306a36Sopenharmony_ci * kernel doesn't use CR0.TS, so this doesn't matter. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline u32 xstore(u32 *addr, u32 edx_in) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci u32 eax_out; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci asm(".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */" 8262306a36Sopenharmony_ci : "=m" (*addr), "=a" (eax_out), "+d" (edx_in), "+D" (addr)); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return eax_out; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int via_rng_data_present(struct hwrng *rng, int wait) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci char buf[16 + PADLOCK_ALIGNMENT - STACK_ALIGN] __attribute__ 9062306a36Sopenharmony_ci ((aligned(STACK_ALIGN))); 9162306a36Sopenharmony_ci u32 *via_rng_datum = (u32 *)PTR_ALIGN(&buf[0], PADLOCK_ALIGNMENT); 9262306a36Sopenharmony_ci u32 bytes_out; 9362306a36Sopenharmony_ci int i; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* We choose the recommended 1-byte-per-instruction RNG rate, 9662306a36Sopenharmony_ci * for greater randomness at the expense of speed. Larger 9762306a36Sopenharmony_ci * values 2, 4, or 8 bytes-per-instruction yield greater 9862306a36Sopenharmony_ci * speed at lesser randomness. 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * If you change this to another VIA_CHUNK_n, you must also 10162306a36Sopenharmony_ci * change the ->n_bytes values in rng_vendor_ops[] tables. 10262306a36Sopenharmony_ci * VIA_CHUNK_8 requires further code changes. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * A copy of MSR_VIA_RNG is placed in eax_out when xstore 10562306a36Sopenharmony_ci * completes. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci for (i = 0; i < 20; i++) { 10962306a36Sopenharmony_ci *via_rng_datum = 0; /* paranoia, not really necessary */ 11062306a36Sopenharmony_ci bytes_out = xstore(via_rng_datum, VIA_RNG_CHUNK_1); 11162306a36Sopenharmony_ci bytes_out &= VIA_XSTORE_CNT_MASK; 11262306a36Sopenharmony_ci if (bytes_out || !wait) 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci udelay(10); 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci rng->priv = *via_rng_datum; 11762306a36Sopenharmony_ci return bytes_out ? 1 : 0; 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int via_rng_data_read(struct hwrng *rng, u32 *data) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci u32 via_rng_datum = (u32)rng->priv; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci *data = via_rng_datum; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return 1; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int via_rng_init(struct hwrng *rng) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct cpuinfo_x86 *c = &cpu_data(0); 13262306a36Sopenharmony_ci u32 lo, hi, old_lo; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* VIA Nano CPUs don't have the MSR_VIA_RNG anymore. The RNG 13562306a36Sopenharmony_ci * is always enabled if CPUID rng_en is set. There is no 13662306a36Sopenharmony_ci * RNG configuration like it used to be the case in this 13762306a36Sopenharmony_ci * register */ 13862306a36Sopenharmony_ci if (((c->x86 == 6) && (c->x86_model >= 0x0f)) || (c->x86 > 6)){ 13962306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XSTORE_EN)) { 14062306a36Sopenharmony_ci pr_err(PFX "can't enable hardware RNG " 14162306a36Sopenharmony_ci "if XSTORE is not enabled\n"); 14262306a36Sopenharmony_ci return -ENODEV; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci return 0; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* Control the RNG via MSR. Tread lightly and pay very close 14862306a36Sopenharmony_ci * attention to values written, as the reserved fields 14962306a36Sopenharmony_ci * are documented to be "undefined and unpredictable"; but it 15062306a36Sopenharmony_ci * does not say to write them as zero, so I make a guess that 15162306a36Sopenharmony_ci * we restore the values we find in the register. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci rdmsr(MSR_VIA_RNG, lo, hi); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci old_lo = lo; 15662306a36Sopenharmony_ci lo &= ~(0x7f << VIA_STRFILT_CNT_SHIFT); 15762306a36Sopenharmony_ci lo &= ~VIA_XSTORE_CNT_MASK; 15862306a36Sopenharmony_ci lo &= ~(VIA_STRFILT_ENABLE | VIA_STRFILT_FAIL | VIA_RAWBITS_ENABLE); 15962306a36Sopenharmony_ci lo |= VIA_RNG_ENABLE; 16062306a36Sopenharmony_ci lo |= VIA_NOISESRC1; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Enable secondary noise source on CPUs where it is present. */ 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Nehemiah stepping 8 and higher */ 16562306a36Sopenharmony_ci if ((c->x86_model == 9) && (c->x86_stepping > 7)) 16662306a36Sopenharmony_ci lo |= VIA_NOISESRC2; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci /* Esther */ 16962306a36Sopenharmony_ci if (c->x86_model >= 10) 17062306a36Sopenharmony_ci lo |= VIA_NOISESRC2; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (lo != old_lo) 17362306a36Sopenharmony_ci wrmsr(MSR_VIA_RNG, lo, hi); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* perhaps-unnecessary sanity check; remove after testing if 17662306a36Sopenharmony_ci unneeded */ 17762306a36Sopenharmony_ci rdmsr(MSR_VIA_RNG, lo, hi); 17862306a36Sopenharmony_ci if ((lo & VIA_RNG_ENABLE) == 0) { 17962306a36Sopenharmony_ci pr_err(PFX "cannot enable VIA C3 RNG, aborting\n"); 18062306a36Sopenharmony_ci return -ENODEV; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic struct hwrng via_rng = { 18862306a36Sopenharmony_ci .name = "via", 18962306a36Sopenharmony_ci .init = via_rng_init, 19062306a36Sopenharmony_ci .data_present = via_rng_data_present, 19162306a36Sopenharmony_ci .data_read = via_rng_data_read, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int __init via_rng_mod_init(void) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci int err; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci if (!boot_cpu_has(X86_FEATURE_XSTORE)) 20062306a36Sopenharmony_ci return -ENODEV; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci pr_info("VIA RNG detected\n"); 20362306a36Sopenharmony_ci err = hwrng_register(&via_rng); 20462306a36Sopenharmony_ci if (err) { 20562306a36Sopenharmony_ci pr_err(PFX "RNG registering failed (%d)\n", 20662306a36Sopenharmony_ci err); 20762306a36Sopenharmony_ci goto out; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ciout: 21062306a36Sopenharmony_ci return err; 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_cimodule_init(via_rng_mod_init); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void __exit via_rng_mod_exit(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci hwrng_unregister(&via_rng); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_cimodule_exit(via_rng_mod_exit); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic struct x86_cpu_id __maybe_unused via_rng_cpu_id[] = { 22162306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_XSTORE, NULL), 22262306a36Sopenharmony_ci {} 22362306a36Sopenharmony_ci}; 22462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, via_rng_cpu_id); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ciMODULE_DESCRIPTION("H/W RNG driver for VIA CPU with PadLock"); 22762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 228