]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseRngLibTimerLib/RngLibTimer.c
54d29d96f3d38699c2cf393eab771098377c2b2c
[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 // Calculate the minimum delay based on 1.5 microseconds divided by the hertz.
39 // We calculate the length of a cycle (1/CounterHz) and multiply it by 1.5 microseconds
40 // This ensures that the performance counter has increased by at least one
41 return (UINT32)(MAX (DivU64x64Remainder (1500000,CounterHz, NULL), 1));
42 }
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 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
72 RandPtr = (UINT8*)Rand;
73 // Get 2 bytes of random ish data
74 for (Index = 0; Index < sizeof(UINT16); Index ++) {
75 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
76 // Delay to give the performance counter a chance to change
77 MicroSecondDelay (DelayInMicroSeconds);
78 RandPtr++;
79 }
80 return TRUE;
81 }
82
83 /**
84 Generates a 32-bit random number.
85
86 if Rand is NULL, then ASSERT().
87
88 @param[out] Rand Buffer pointer to store the 32-bit random value.
89
90 @retval TRUE Random number generated successfully.
91 @retval FALSE Failed to generate the random number.
92
93 **/
94 BOOLEAN
95 EFIAPI
96 GetRandomNumber32 (
97 OUT UINT32 *Rand
98 )
99 {
100 UINT32 Index;
101 UINT8 *RandPtr;
102 UINT32 DelayInMicroSeconds;
103
104 ASSERT (Rand != NULL);
105
106 if (NULL == Rand) {
107 return FALSE;
108 }
109
110 RandPtr = (UINT8 *) Rand;
111 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
112 // Get 4 bytes of random ish data
113 for (Index = 0; Index < sizeof(UINT32); Index ++) {
114 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
115 // Delay to give the performance counter a chance to change
116 MicroSecondDelay (DelayInMicroSeconds);
117 RandPtr++;
118 }
119 return TRUE;
120 }
121
122 /**
123 Generates a 64-bit random number.
124
125 if Rand is NULL, then ASSERT().
126
127 @param[out] Rand Buffer pointer to store the 64-bit random value.
128
129 @retval TRUE Random number generated successfully.
130 @retval FALSE Failed to generate the random number.
131
132 **/
133 BOOLEAN
134 EFIAPI
135 GetRandomNumber64 (
136 OUT UINT64 *Rand
137 )
138 {
139 UINT32 Index;
140 UINT8 *RandPtr;
141 UINT32 DelayInMicroSeconds;
142
143 ASSERT (Rand != NULL);
144
145 if (NULL == Rand) {
146 return FALSE;
147 }
148
149 RandPtr = (UINT8 *)Rand;
150 DelayInMicroSeconds = CalculateMinimumDecentDelayInMicroseconds ();
151 // Get 8 bytes of random ish data
152 for (Index = 0; Index < sizeof(UINT64); Index ++) {
153 *RandPtr = (UINT8)(GetPerformanceCounter () & 0xFF);
154 // Delay to give the performance counter a chance to change
155 MicroSecondDelay (DelayInMicroSeconds);
156 RandPtr++;
157 }
158
159 return TRUE;
160 }
161
162 /**
163 Generates a 128-bit random number.
164
165 if Rand is NULL, then ASSERT().
166
167 @param[out] Rand Buffer pointer to store the 128-bit random value.
168
169 @retval TRUE Random number generated successfully.
170 @retval FALSE Failed to generate the random number.
171
172 **/
173 BOOLEAN
174 EFIAPI
175 GetRandomNumber128 (
176 OUT UINT64 *Rand
177 )
178 {
179 ASSERT (Rand != NULL);
180 // This should take around 80ms
181
182 // Read first 64 bits
183 if (!GetRandomNumber64 (Rand)) {
184 return FALSE;
185 }
186
187 // Read second 64 bits
188 return GetRandomNumber64 (++Rand);
189 }