VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/MdePkg/Library/BaseRngLib/Rand/RdRand.c

Last change on this file was 108794, checked in by vboxsync, 5 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 5.2 KB
Line 
1/** @file
2 Random number generator services that uses RdRand instruction access
3 to provide high-quality random numbers.
4
5Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
6Copyright (c) 2023, Arm Limited. All rights reserved.<BR>
7Copyright (c) 2022, Pedro Falcato. All rights reserved.<BR>
8Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
9Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
10
11SPDX-License-Identifier: BSD-2-Clause-Patent
12
13**/
14
15#include <Uefi.h>
16#include <Library/BaseLib.h>
17#include <Library/BaseMemoryLib.h>
18#include <Library/DebugLib.h>
19
20#include "BaseRngLibInternals.h"
21
22//
23// Bit mask used to determine if RdRand instruction is supported.
24//
25#define RDRAND_MASK BIT30
26
27//
28// Intel SDM says 10 tries is good enough for reliable RDRAND usage.
29//
30#define RDRAND_RETRIES 10
31
32#define RDRAND_TEST_SAMPLES 8
33
34#define RDRAND_MIN_CHANGE 5
35
36//
37// Add a define for native-word RDRAND, just for the test.
38//
39#ifdef MDE_CPU_X64
40#define ASM_RDRAND AsmRdRand64
41#else
42#define ASM_RDRAND AsmRdRand32
43#endif
44
45/**
46 Tests RDRAND for broken implementations.
47
48 @retval TRUE RDRAND is reliable (and hopefully safe).
49 @retval FALSE RDRAND is unreliable and should be disabled, despite CPUID.
50
51**/
52STATIC
53BOOLEAN
54TestRdRand (
55 VOID
56 )
57{
58 //
59 // Test for notoriously broken rdrand implementations that always return the same
60 // value, like the Zen 3 uarch (all-1s) or other several AMD families on suspend/resume (also all-1s).
61 // Note that this should be expanded to extensively test for other sorts of possible errata.
62 //
63
64 //
65 // Our algorithm samples rdrand $RDRAND_TEST_SAMPLES times and expects
66 // a different result $RDRAND_MIN_CHANGE times for reliable RDRAND usage.
67 //
68 UINTN Prev;
69 UINT8 Idx;
70 UINT8 TestIteration;
71 UINT32 Changed;
72
73 Changed = 0;
74
75 for (TestIteration = 0; TestIteration < RDRAND_TEST_SAMPLES; TestIteration++) {
76 UINTN Sample;
77 //
78 // Note: We use a retry loop for rdrand. Normal users get this in BaseRng.c
79 // Any failure to get a random number will assume RDRAND does not work.
80 //
81 for (Idx = 0; Idx < RDRAND_RETRIES; Idx++) {
82 if (ASM_RDRAND (&Sample)) {
83 break;
84 }
85 }
86
87 if (Idx == RDRAND_RETRIES) {
88 DEBUG ((DEBUG_ERROR, "BaseRngLib/x86: CPU BUG: Failed to get an RDRAND random number - disabling\n"));
89 return FALSE;
90 }
91
92 if (TestIteration != 0) {
93 Changed += Sample != Prev;
94 }
95
96 Prev = Sample;
97 }
98
99 if (Changed < RDRAND_MIN_CHANGE) {
100 DEBUG ((DEBUG_ERROR, "BaseRngLib/x86: CPU BUG: RDRAND not reliable - disabling\n"));
101 return FALSE;
102 }
103
104 return TRUE;
105}
106
107#undef ASM_RDRAND
108
109/**
110 The constructor function checks whether or not RDRAND instruction is supported
111 by the host hardware.
112
113 The constructor function checks whether or not RDRAND instruction is supported.
114 It will ASSERT() if RDRAND instruction is not supported.
115 It will always return EFI_SUCCESS.
116
117 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
118
119**/
120EFI_STATUS
121EFIAPI
122BaseRngLibConstructor (
123 VOID
124 )
125{
126 return EFI_SUCCESS;
127}
128
129/**
130 Generates a 16-bit random number.
131
132 @param[out] Rand Buffer pointer to store the 16-bit random value.
133
134 @retval TRUE Random number generated successfully.
135 @retval FALSE Failed to generate the random number.
136
137**/
138BOOLEAN
139EFIAPI
140ArchGetRandomNumber16 (
141 OUT UINT16 *Rand
142 )
143{
144 return AsmRdRand16 (Rand);
145}
146
147/**
148 Generates a 32-bit random number.
149
150 @param[out] Rand Buffer pointer to store the 32-bit random value.
151
152 @retval TRUE Random number generated successfully.
153 @retval FALSE Failed to generate the random number.
154
155**/
156BOOLEAN
157EFIAPI
158ArchGetRandomNumber32 (
159 OUT UINT32 *Rand
160 )
161{
162 return AsmRdRand32 (Rand);
163}
164
165/**
166 Generates a 64-bit random number.
167
168 @param[out] Rand Buffer pointer to store the 64-bit random value.
169
170 @retval TRUE Random number generated successfully.
171 @retval FALSE Failed to generate the random number.
172
173**/
174BOOLEAN
175EFIAPI
176ArchGetRandomNumber64 (
177 OUT UINT64 *Rand
178 )
179{
180 return AsmRdRand64 (Rand);
181}
182
183/**
184 Checks whether RDRAND is supported.
185
186 @retval TRUE RDRAND is supported.
187 @retval FALSE RDRAND is not supported.
188
189**/
190BOOLEAN
191EFIAPI
192ArchIsRngSupported (
193 VOID
194 )
195{
196 BOOLEAN RdRandSupported;
197 UINT32 RegEcx;
198
199 //
200 // Determine RDRAND support by examining bit 30 of the ECX register returned by
201 // CPUID. A value of 1 indicates that processor support RDRAND instruction.
202 //
203 AsmCpuid (1, 0, 0, &RegEcx, 0);
204
205 RdRandSupported = ((RegEcx & RDRAND_MASK) == RDRAND_MASK);
206
207 if (RdRandSupported) {
208 RdRandSupported = TestRdRand ();
209 }
210
211 return RdRandSupported;
212}
213
214/**
215 Get a GUID identifying the RNG algorithm implementation.
216
217 @param [out] RngGuid If success, contains the GUID identifying
218 the RNG algorithm implementation.
219
220 @retval EFI_SUCCESS Success.
221 @retval EFI_UNSUPPORTED Not supported.
222 @retval EFI_INVALID_PARAMETER Invalid parameter.
223**/
224EFI_STATUS
225EFIAPI
226GetRngGuid (
227 GUID *RngGuid
228 )
229{
230 if (RngGuid == NULL) {
231 return EFI_INVALID_PARAMETER;
232 }
233
234 CopyMem (RngGuid, &gEfiRngAlgorithmSp80090Ctr256Guid, sizeof (*RngGuid));
235 return EFI_SUCCESS;
236}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette