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