]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseRngLibTimerLib/RngLibTimer.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdePkg / Library / BaseRngLibTimerLib / RngLibTimer.c
1 /** @file
2 BaseRng Library that uses the TimerLib to provide reasonably random numbers.
3 Do not use this on a production system.
4
5 Copyright (c) Microsoft Corporation.
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7 **/
8
9 #include <Base.h>
10 #include <Library/BaseLib.h>
11 #include <Library/DebugLib.h>
12 #include <Library/TimerLib.h>
13
14 #define DEFAULT_DELAY_TIME_IN_MICROSECONDS 10
15
16 /**
17 Using the TimerLib GetPerformanceCounterProperties() we delay
18 for enough time for the PerformanceCounter to increment.
19
20 If the return value from GetPerformanceCounterProperties (TimerLib)
21 is zero, this function will return 10 and attempt to assert.
22 **/
23 STATIC
24 UINT32
25 CalculateMinimumDecentDelayInMicroseconds (
26 VOID
27 )
28 {
29 UINT64 CounterHz;
30
31 // Get the counter properties
32 CounterHz = GetPerformanceCounterProperties (NULL, NULL);
33 // Make sure we won't divide by zero
34 if (CounterHz == 0) {
35 ASSERT (CounterHz != 0); // Assert so the developer knows something is wrong
36 return DEFAULT_DELAY_TIME_IN_MICROSECONDS;
37 }
38
39 // Calculate the minimum delay based on 1.5 microseconds divided by the hertz.
40 // We calculate the length of a cycle (1/CounterHz) and multiply it by 1.5 microseconds
41 // This ensures that the performance counter has increased by at least one
42 return (UINT32)(MAX (DivU64x64Remainder (1500000, CounterHz, NULL), 1));
43 }
44
45 /**
46 Generates a 16-bit random number.
47
48 if Rand is NULL, then ASSERT().
49
50 @param[out] Rand Buffer pointer to store the 16-bit random value.
51
52 @retval TRUE Random number generated successfully.
53 @retval FALSE Failed to generate the random number.
54
55 **/
56 BOOLEAN
57 EFIAPI
58 GetRandomNumber16 (
59 OUT UINT16 *Rand
60 )
61 {
62 UINT32 Index;
63 UINT8 *RandPtr;
64 UINT32 DelayInMicroSeconds;
65
66 ASSERT (Rand != NULL);
67
68 if (Rand == NULL) {
69 return FALSE;
70 }
71
72 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
73 RandPtr = (UINT8 *)Rand;
74 // Get 2 bytes of random ish data
75 for (Index = 0; Index < sizeof (UINT16); Index++) {
76 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
77 // Delay to give the performance counter a chance to change
78 MicroSecondDelay (DelayInMicroSeconds);
79 RandPtr++;
80 }
81
82 return TRUE;
83 }
84
85 /**
86 Generates a 32-bit random number.
87
88 if Rand is NULL, then ASSERT().
89
90 @param[out] Rand Buffer pointer to store the 32-bit random value.
91
92 @retval TRUE Random number generated successfully.
93 @retval FALSE Failed to generate the random number.
94
95 **/
96 BOOLEAN
97 EFIAPI
98 GetRandomNumber32 (
99 OUT UINT32 *Rand
100 )
101 {
102 UINT32 Index;
103 UINT8 *RandPtr;
104 UINT32 DelayInMicroSeconds;
105
106 ASSERT (Rand != NULL);
107
108 if (NULL == Rand) {
109 return FALSE;
110 }
111
112 RandPtr = (UINT8 *)Rand;
113 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
114 // Get 4 bytes of random ish data
115 for (Index = 0; Index < sizeof (UINT32); Index++) {
116 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
117 // Delay to give the performance counter a chance to change
118 MicroSecondDelay (DelayInMicroSeconds);
119 RandPtr++;
120 }
121
122 return TRUE;
123 }
124
125 /**
126 Generates a 64-bit random number.
127
128 if Rand is NULL, then ASSERT().
129
130 @param[out] Rand Buffer pointer to store the 64-bit random value.
131
132 @retval TRUE Random number generated successfully.
133 @retval FALSE Failed to generate the random number.
134
135 **/
136 BOOLEAN
137 EFIAPI
138 GetRandomNumber64 (
139 OUT UINT64 *Rand
140 )
141 {
142 UINT32 Index;
143 UINT8 *RandPtr;
144 UINT32 DelayInMicroSeconds;
145
146 ASSERT (Rand != NULL);
147
148 if (NULL == Rand) {
149 return FALSE;
150 }
151
152 RandPtr = (UINT8 *)Rand;
153 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
154 // Get 8 bytes of random ish data
155 for (Index = 0; Index < sizeof (UINT64); Index++) {
156 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
157 // Delay to give the performance counter a chance to change
158 MicroSecondDelay (DelayInMicroSeconds);
159 RandPtr++;
160 }
161
162 return TRUE;
163 }
164
165 /**
166 Generates a 128-bit random number.
167
168 if Rand is NULL, then ASSERT().
169
170 @param[out] Rand Buffer pointer to store the 128-bit random value.
171
172 @retval TRUE Random number generated successfully.
173 @retval FALSE Failed to generate the random number.
174
175 **/
176 BOOLEAN
177 EFIAPI
178 GetRandomNumber128 (
179 OUT UINT64 *Rand
180 )
181 {
182 ASSERT (Rand != NULL);
183 // This should take around 80ms
184
185 // Read first 64 bits
186 if (!GetRandomNumber64 (Rand)) {
187 return FALSE;
188 }
189
190 // Read second 64 bits
191 return GetRandomNumber64 (++Rand);
192 }