xref: /linux/arch/x86/kernel/cpu/rdrand.c (revision 0526b56cbc3c489642bd6a5fe4b718dea7ef0ee8)
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 
10 #include <asm/processor.h>
11 #include <asm/archrandom.h>
12 #include <asm/sections.h>
13 
14 /*
15  * RDRAND has Built-In-Self-Test (BIST) that runs on every invocation.
16  * Run the instruction a few times as a sanity check. Also make sure
17  * it's not outputting the same value over and over, which has happened
18  * as a result of past CPU bugs.
19  *
20  * If it fails, it is simple to disable RDRAND and RDSEED here.
21  */
22 
23 void x86_init_rdrand(struct cpuinfo_x86 *c)
24 {
25 	enum { SAMPLES = 8, MIN_CHANGE = 5 };
26 	unsigned long sample, prev;
27 	bool failure = false;
28 	size_t i, changed;
29 
30 	if (!cpu_has(c, X86_FEATURE_RDRAND))
31 		return;
32 
33 	for (changed = 0, i = 0; i < SAMPLES; ++i) {
34 		if (!rdrand_long(&sample)) {
35 			failure = true;
36 			break;
37 		}
38 		changed += i && sample != prev;
39 		prev = sample;
40 	}
41 	if (changed < MIN_CHANGE)
42 		failure = true;
43 
44 	if (failure) {
45 		clear_cpu_cap(c, X86_FEATURE_RDRAND);
46 		clear_cpu_cap(c, X86_FEATURE_RDSEED);
47 		pr_emerg("RDRAND is not reliable on this platform; disabling.\n");
48 	}
49 }
50