xref: /linux/arch/x86/kernel/cpu/rdrand.c (revision 955abe0a1b41de5ba61fe4cd614ebc123084d499)
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(&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