diff options
Diffstat (limited to 'arch/x86/kernel/cpu/rdrand.c')
-rw-r--r-- | arch/x86/kernel/cpu/rdrand.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/rdrand.c b/arch/x86/kernel/cpu/rdrand.c new file mode 100644 index 0000000000..26a427fa84 --- /dev/null +++ b/arch/x86/kernel/cpu/rdrand.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * This file is part of the Linux kernel. + * + * Copyright (c) 2011, Intel Corporation + * Authors: Fenghua Yu <fenghua.yu@intel.com>, + * H. Peter Anvin <hpa@linux.intel.com> + */ + +#include <asm/processor.h> +#include <asm/archrandom.h> +#include <asm/sections.h> + +/* + * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation. + * Run the instruction a few times as a sanity check. Also make sure + * it's not outputting the same value over and over, which has happened + * as a result of past CPU bugs. + * + * If it fails, it is simple to disable RDRAND and RDSEED here. + */ + +void x86_init_rdrand(struct cpuinfo_x86 *c) +{ + enum { SAMPLES = 8, MIN_CHANGE = 5 }; + unsigned long sample, prev; + bool failure = false; + size_t i, changed; + + if (!cpu_has(c, X86_FEATURE_RDRAND)) + return; + + for (changed = 0, i = 0; i < SAMPLES; ++i) { + if (!rdrand_long(&sample)) { + failure = true; + break; + } + changed += i && sample != prev; + prev = sample; + } + if (changed < MIN_CHANGE) + failure = true; + + if (failure) { + clear_cpu_cap(c, X86_FEATURE_RDRAND); + clear_cpu_cap(c, X86_FEATURE_RDSEED); + pr_emerg("RDRAND is not reliable on this platform; disabling.\n"); + } +} |