1 /** @file
2   Random number generator services that uses RdRand instruction access
3   to provide high-quality random numbers.
4 
5 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 
13 //
14 // Bit mask used to determine if RdRand instruction is supported.
15 //
16 #define RDRAND_MASK                  BIT30
17 
18 //
19 // Limited retry number when valid random data is returned.
20 // Uses the recommended value defined in Section 7.3.17 of "Intel 64 and IA-32
21 // Architectures Software Developer's Mannual".
22 //
23 #define RDRAND_RETRY_LIMIT           10
24 
25 /**
26   The constructor function checks whether or not RDRAND instruction is supported
27   by the host hardware.
28 
29   The constructor function checks whether or not RDRAND instruction is supported.
30   It will ASSERT() if RDRAND instruction is not supported.
31   It will always return RETURN_SUCCESS.
32 
33   @retval RETURN_SUCCESS   The constructor always returns EFI_SUCCESS.
34 
35 **/
36 RETURN_STATUS
37 EFIAPI
BaseRngLibConstructor(VOID)38 BaseRngLibConstructor (
39   VOID
40   )
41 {
42   UINT32  RegEcx;
43 
44   //
45   // Determine RDRAND support by examining bit 30 of the ECX register returned by
46   // CPUID. A value of 1 indicates that processor support RDRAND instruction.
47   //
48   AsmCpuid (1, 0, 0, &RegEcx, 0);
49   ASSERT ((RegEcx & RDRAND_MASK) == RDRAND_MASK);
50 
51   return RETURN_SUCCESS;
52 }
53 
54 /**
55   Generates a 16-bit random number.
56 
57   if Rand is NULL, then ASSERT().
58 
59   @param[out] Rand     Buffer pointer to store the 16-bit random value.
60 
61   @retval TRUE         Random number generated successfully.
62   @retval FALSE        Failed to generate the random number.
63 
64 **/
65 BOOLEAN
66 EFIAPI
GetRandomNumber16(OUT UINT16 * Rand)67 GetRandomNumber16 (
68   OUT     UINT16                    *Rand
69   )
70 {
71   UINT32  Index;
72 
73   ASSERT (Rand != NULL);
74 
75   //
76   // A loop to fetch a 16 bit random value with a retry count limit.
77   //
78   for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
79     if (AsmRdRand16 (Rand)) {
80       return TRUE;
81     }
82   }
83 
84   return FALSE;
85 }
86 
87 /**
88   Generates a 32-bit random number.
89 
90   if Rand is NULL, then ASSERT().
91 
92   @param[out] Rand     Buffer pointer to store the 32-bit random value.
93 
94   @retval TRUE         Random number generated successfully.
95   @retval FALSE        Failed to generate the random number.
96 
97 **/
98 BOOLEAN
99 EFIAPI
GetRandomNumber32(OUT UINT32 * Rand)100 GetRandomNumber32 (
101   OUT     UINT32                    *Rand
102   )
103 {
104   UINT32  Index;
105 
106   ASSERT (Rand != NULL);
107 
108   //
109   // A loop to fetch a 32 bit random value with a retry count limit.
110   //
111   for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
112     if (AsmRdRand32 (Rand)) {
113       return TRUE;
114     }
115   }
116 
117   return FALSE;
118 }
119 
120 /**
121   Generates a 64-bit random number.
122 
123   if Rand is NULL, then ASSERT().
124 
125   @param[out] Rand     Buffer pointer to store the 64-bit random value.
126 
127   @retval TRUE         Random number generated successfully.
128   @retval FALSE        Failed to generate the random number.
129 
130 **/
131 BOOLEAN
132 EFIAPI
GetRandomNumber64(OUT UINT64 * Rand)133 GetRandomNumber64 (
134   OUT     UINT64                    *Rand
135   )
136 {
137   UINT32  Index;
138 
139   ASSERT (Rand != NULL);
140 
141   //
142   // A loop to fetch a 64 bit random value with a retry count limit.
143   //
144   for (Index = 0; Index < RDRAND_RETRY_LIMIT; Index++) {
145     if (AsmRdRand64 (Rand)) {
146       return TRUE;
147     }
148   }
149 
150   return FALSE;
151 }
152 
153 /**
154   Generates a 128-bit random number.
155 
156   if Rand is NULL, then ASSERT().
157 
158   @param[out] Rand     Buffer pointer to store the 128-bit random value.
159 
160   @retval TRUE         Random number generated successfully.
161   @retval FALSE        Failed to generate the random number.
162 
163 **/
164 BOOLEAN
165 EFIAPI
GetRandomNumber128(OUT UINT64 * Rand)166 GetRandomNumber128 (
167   OUT     UINT64                    *Rand
168   )
169 {
170   ASSERT (Rand != NULL);
171 
172   //
173   // Read first 64 bits
174   //
175   if (!GetRandomNumber64 (Rand)) {
176     return FALSE;
177   }
178 
179   //
180   // Read second 64 bits
181   //
182   return GetRandomNumber64 (++Rand);
183 }
184