1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * This file is part of the Linux kernel. |
4 | * |
5 | * Copyright (c) 2011, Intel Corporation |
6 | * Authors: Fenghua Yu <fenghua.yu@intel.com>, |
7 | * H. Peter Anvin <hpa@linux.intel.com> |
8 | */ |
9 | #include <linux/printk.h> |
10 | |
11 | #include <asm/processor.h> |
12 | #include <asm/archrandom.h> |
13 | #include <asm/sections.h> |
14 | |
15 | /* |
16 | * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation. |
17 | * Run the instruction a few times as a sanity check. Also make sure |
18 | * it's not outputting the same value over and over, which has happened |
19 | * as a result of past CPU bugs. |
20 | * |
21 | * If it fails, it is simple to disable RDRAND and RDSEED here. |
22 | */ |
23 | |
24 | void x86_init_rdrand(struct cpuinfo_x86 *c) |
25 | { |
26 | enum { SAMPLES = 8, MIN_CHANGE = 5 }; |
27 | unsigned long sample, prev; |
28 | bool failure = false; |
29 | size_t i, changed; |
30 | |
31 | if (!cpu_has(c, X86_FEATURE_RDRAND)) |
32 | return; |
33 | |
34 | for (changed = 0, i = 0; i < SAMPLES; ++i) { |
35 | if (!rdrand_long(v: &sample)) { |
36 | failure = true; |
37 | break; |
38 | } |
39 | changed += i && sample != prev; |
40 | prev = sample; |
41 | } |
42 | if (changed < MIN_CHANGE) |
43 | failure = true; |
44 | |
45 | if (failure) { |
46 | clear_cpu_cap(c, X86_FEATURE_RDRAND); |
47 | clear_cpu_cap(c, X86_FEATURE_RDSEED); |
48 | pr_emerg("RDRAND is not reliable on this platform; disabling.\n" ); |
49 | } |
50 | } |
51 | |