]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmTrngLib/ArmTrngLib.c
fdabc02cd39ceeb4a97743e68e9c5dc85b868036
[mirror_edk2.git] / ArmPkg / Library / ArmTrngLib / ArmTrngLib.c
1 /** @file
2 Arm Firmware TRNG interface library.
3
4 Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 @par Reference(s):
9 - [1] Arm True Random Number Generator Firmware, Interface 1.0,
10 Platform Design Document.
11 (https://developer.arm.com/documentation/den0098/latest/)
12 - [2] NIST Special Publication 800-90B, Recommendation for the Entropy
13 Sources Used for Random Bit Generation.
14 (https://csrc.nist.gov/publications/detail/sp/800-90b/final)
15
16 @par Glossary:
17 - TRNG - True Random Number Generator
18 - FID - Function ID
19 **/
20
21 #include <Base.h>
22 #include <Library/ArmLib.h>
23 #include <Library/ArmMonitorLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
26
27 #include "ArmTrngDefs.h"
28
29 /** Convert TRNG status codes to RETURN status codes.
30
31 @param [in] TrngStatus TRNG status code.
32
33 @retval RETURN_SUCCESS Success.
34 @retval RETURN_UNSUPPORTED Function not implemented or
35 negative return code.
36 @retval RETURN_INVALID_PARAMETER A parameter is invalid.
37 @retval RETURN_NOT_READY No Entropy available.
38 **/
39 STATIC
40 RETURN_STATUS
41 TrngStatusToReturnStatus (
42 IN INT32 TrngStatus
43 )
44 {
45 switch (TrngStatus) {
46 case TRNG_STATUS_NOT_SUPPORTED:
47 return RETURN_UNSUPPORTED;
48
49 case TRNG_STATUS_INVALID_PARAMETER:
50 return RETURN_INVALID_PARAMETER;
51
52 case TRNG_STATUS_NO_ENTROPY:
53 return RETURN_NOT_READY;
54
55 case TRNG_STATUS_SUCCESS:
56 return RETURN_SUCCESS;
57
58 default:
59 if (TrngStatus < 0) {
60 return RETURN_UNSUPPORTED;
61 }
62
63 return RETURN_SUCCESS;
64 }
65 }
66
67 /** Get the version of the Arm TRNG backend.
68
69 A TRNG may be implemented by the system firmware, in which case this
70 function shall return the version of the Arm TRNG backend.
71 The implementation must return NOT_SUPPORTED if a Back end is not present.
72
73 @param [out] MajorRevision Major revision.
74 @param [out] MinorRevision Minor revision.
75
76 @retval RETURN_SUCCESS The function completed successfully.
77 @retval RETURN_INVALID_PARAMETER Invalid parameter.
78 @retval RETURN_UNSUPPORTED Backend not present.
79 **/
80 RETURN_STATUS
81 EFIAPI
82 GetArmTrngVersion (
83 OUT UINT16 *MajorRevision,
84 OUT UINT16 *MinorRevision
85 )
86 {
87 RETURN_STATUS Status;
88 ARM_MONITOR_ARGS Parameters;
89 INT32 Revision;
90
91 if ((MajorRevision == NULL) || (MinorRevision == NULL)) {
92 return RETURN_INVALID_PARAMETER;
93 }
94
95 ZeroMem (&Parameters, sizeof (Parameters));
96
97 Parameters.Arg0 = ARM_SMC_ID_TRNG_VERSION;
98 ArmMonitorCall (&Parameters);
99
100 Revision = (INT32)Parameters.Arg0;
101 Status = TrngStatusToReturnStatus (Revision);
102 if (RETURN_ERROR (Status)) {
103 return Status;
104 }
105
106 *MinorRevision = (Revision & TRNG_REV_MINOR_MASK);
107 *MajorRevision = ((Revision >> TRNG_REV_MAJOR_SHIFT) & TRNG_REV_MAJOR_MASK);
108 return RETURN_SUCCESS;
109 }
110
111 /** Get the features supported by the Arm TRNG backend.
112
113 The caller can determine if functions defined in the Arm TRNG ABI are
114 present in the ABI implementation.
115
116 @param [in] FunctionId Function Id.
117 @param [out] Capability Function specific capability if present.
118
119 @retval RETURN_SUCCESS The function completed successfully.
120 @retval RETURN_INVALID_PARAMETER Invalid parameter.
121 @retval RETURN_UNSUPPORTED Function not implemented.
122 **/
123 STATIC
124 RETURN_STATUS
125 EFIAPI
126 GetArmTrngFeatures (
127 IN CONST UINT32 FunctionId,
128 OUT UINT32 *Capability OPTIONAL
129 )
130 {
131 ARM_MONITOR_ARGS Parameters;
132 RETURN_STATUS Status;
133
134 ZeroMem (&Parameters, sizeof (Parameters));
135
136 Parameters.Arg0 = ARM_SMC_ID_TRNG_FEATURES;
137 Parameters.Arg1 = FunctionId;
138 ArmMonitorCall (&Parameters);
139
140 Status = TrngStatusToReturnStatus (Parameters.Arg0);
141 if (RETURN_ERROR (Status)) {
142 return Status;
143 }
144
145 if (Capability != NULL) {
146 *Capability = (UINT32)Parameters.Arg0;
147 }
148
149 return RETURN_SUCCESS;
150 }
151
152 /** Get the UUID of the Arm TRNG backend.
153
154 A TRNG may be implemented by the system firmware, in which case this
155 function shall return the UUID of the TRNG backend.
156 Returning the Arm TRNG UUID is optional and if not implemented,
157 RETURN_UNSUPPORTED shall be returned.
158
159 Note: The caller must not rely on the returned UUID as a trustworthy Arm TRNG
160 Back end identity
161
162 @param [out] Guid UUID of the Arm TRNG backend.
163
164 @retval RETURN_SUCCESS The function completed successfully.
165 @retval RETURN_INVALID_PARAMETER Invalid parameter.
166 @retval RETURN_UNSUPPORTED Function not implemented.
167 **/
168 RETURN_STATUS
169 EFIAPI
170 GetArmTrngUuid (
171 OUT GUID *Guid
172 )
173 {
174 ARM_MONITOR_ARGS Parameters;
175
176 if (Guid == NULL) {
177 return RETURN_INVALID_PARAMETER;
178 }
179
180 ZeroMem (&Parameters, sizeof (Parameters));
181
182 Parameters.Arg0 = ARM_SMC_ID_TRNG_GET_UUID;
183 ArmMonitorCall (&Parameters);
184
185 // Only invalid value is TRNG_STATUS_NOT_SUPPORTED (-1).
186 if ((INT32)Parameters.Arg0 == TRNG_STATUS_NOT_SUPPORTED) {
187 return TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
188 }
189
190 Guid->Data1 = (Parameters.Arg0 & MAX_UINT32);
191 Guid->Data2 = (Parameters.Arg1 & MAX_UINT16);
192 Guid->Data3 = ((Parameters.Arg1 >> 16) & MAX_UINT16);
193
194 Guid->Data4[0] = (Parameters.Arg2 & MAX_UINT8);
195 Guid->Data4[1] = ((Parameters.Arg2 >> 8) & MAX_UINT8);
196 Guid->Data4[2] = ((Parameters.Arg2 >> 16) & MAX_UINT8);
197 Guid->Data4[3] = ((Parameters.Arg2 >> 24) & MAX_UINT8);
198
199 Guid->Data4[4] = (Parameters.Arg3 & MAX_UINT8);
200 Guid->Data4[5] = ((Parameters.Arg3 >> 8) & MAX_UINT8);
201 Guid->Data4[6] = ((Parameters.Arg3 >> 16) & MAX_UINT8);
202 Guid->Data4[7] = ((Parameters.Arg3 >> 24) & MAX_UINT8);
203
204 DEBUG ((DEBUG_INFO, "FW-TRNG: UUID %g\n", Guid));
205
206 return RETURN_SUCCESS;
207 }
208
209 /** Returns maximum number of entropy bits that can be returned in a single
210 call.
211
212 @return Returns the maximum number of Entropy bits that can be returned
213 in a single call to GetArmTrngEntropy().
214 **/
215 UINTN
216 EFIAPI
217 GetArmTrngMaxSupportedEntropyBits (
218 VOID
219 )
220 {
221 return MAX_ENTROPY_BITS;
222 }
223
224 /** Returns N bits of conditioned entropy.
225
226 See [2] Section 2.3.1 GetEntropy: An Interface to the Entropy Source
227 GetEntropy
228 Input:
229 bits_of_entropy: the requested amount of entropy
230 Output:
231 entropy_bitstring: The string that provides the requested entropy.
232 status: A Boolean value that is TRUE if the request has been satisfied,
233 and is FALSE otherwise.
234
235 @param [in] EntropyBits Number of entropy bits requested.
236 @param [in] BufferSize Size of the Buffer in bytes.
237 @param [out] Buffer Buffer to return the entropy bits.
238
239 @retval RETURN_SUCCESS The function completed successfully.
240 @retval RETURN_INVALID_PARAMETER Invalid parameter.
241 @retval RETURN_UNSUPPORTED Function not implemented.
242 @retval RETURN_BAD_BUFFER_SIZE Buffer size is too small.
243 @retval RETURN_NOT_READY No Entropy available.
244 **/
245 RETURN_STATUS
246 EFIAPI
247 GetArmTrngEntropy (
248 IN UINTN EntropyBits,
249 IN UINTN BufferSize,
250 OUT UINT8 *Buffer
251 )
252 {
253 RETURN_STATUS Status;
254 ARM_MONITOR_ARGS Parameters;
255 UINTN EntropyBytes;
256 UINTN LastValidBits;
257 UINTN BytesToClear;
258 UINTN EntropyData[3];
259
260 if ((EntropyBits == 0) ||
261 (EntropyBits > MAX_ENTROPY_BITS) ||
262 (Buffer == NULL))
263 {
264 return RETURN_INVALID_PARAMETER;
265 }
266
267 EntropyBytes = (EntropyBits + 7) >> 3;
268 if (EntropyBytes > BufferSize) {
269 return RETURN_BAD_BUFFER_SIZE;
270 }
271
272 ZeroMem (Buffer, BufferSize);
273 ZeroMem (&Parameters, sizeof (Parameters));
274
275 Parameters.Arg0 = ARM_SMC_ID_TRNG_RND;
276 Parameters.Arg1 = EntropyBits;
277 ArmMonitorCall (&Parameters);
278
279 Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
280 if (RETURN_ERROR (Status)) {
281 return Status;
282 }
283
284 // The entropy data is returned in the Parameters.Arg<3..1>
285 // With the lower order bytes in Parameters.Arg3 and the higher
286 // order bytes being stored in Parameters.Arg1.
287 EntropyData[0] = Parameters.Arg3;
288 EntropyData[1] = Parameters.Arg2;
289 EntropyData[2] = Parameters.Arg1;
290
291 CopyMem (Buffer, EntropyData, EntropyBytes);
292
293 // Mask off any unused top bytes, in accordance with specification.
294 BytesToClear = BufferSize - EntropyBytes;
295 if (BytesToClear != 0) {
296 ZeroMem (&Buffer[EntropyBytes], BytesToClear);
297 }
298
299 // Clear the unused MSB bits of the last byte.
300 LastValidBits = EntropyBits & 0x7;
301 if (LastValidBits != 0) {
302 Buffer[EntropyBytes - 1] &= (0xFF >> (8 - LastValidBits));
303 }
304
305 return Status;
306 }
307
308 /** The constructor checks that the FW-TRNG interface is supported
309 by the host firmware.
310
311 It will ASSERT() if FW-TRNG is not supported.
312 It will always return RETURN_SUCCESS.
313
314 @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.
315 **/
316 RETURN_STATUS
317 EFIAPI
318 ArmTrngLibConstructor (
319 VOID
320 )
321 {
322 ARM_MONITOR_ARGS Parameters;
323 RETURN_STATUS Status;
324 UINT16 MajorRev;
325 UINT16 MinorRev;
326 GUID Guid;
327
328 ZeroMem (&Parameters, sizeof (Parameters));
329
330 Parameters.Arg0 = SMCCC_VERSION;
331 ArmMonitorCall (&Parameters);
332 Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
333 if (RETURN_ERROR (Status)) {
334 ASSERT_RETURN_ERROR (Status);
335 goto ErrorHandler;
336 }
337
338 // Cf [1] s2.1.3 'Caller responsibilities',
339 // SMCCC version must be greater or equal than 1.1
340 if ((INT32)Parameters.Arg0 < 0x10001) {
341 ASSERT_RETURN_ERROR (RETURN_UNSUPPORTED);
342 goto ErrorHandler;
343 }
344
345 Status = GetArmTrngVersion (&MajorRev, &MinorRev);
346 if (RETURN_ERROR (Status)) {
347 ASSERT_RETURN_ERROR (Status);
348 goto ErrorHandler;
349 }
350
351 // Check that the required features are present.
352 Status = GetArmTrngFeatures (ARM_SMC_ID_TRNG_RND, NULL);
353 if (RETURN_ERROR (Status)) {
354 ASSERT_RETURN_ERROR (Status);
355 goto ErrorHandler;
356 }
357
358 // Check if TRNG UUID is supported and if so trace the GUID.
359 Status = GetArmTrngFeatures (ARM_SMC_ID_TRNG_GET_UUID, NULL);
360 if (RETURN_ERROR (Status)) {
361 ASSERT_RETURN_ERROR (Status);
362 goto ErrorHandler;
363 }
364
365 DEBUG_CODE_BEGIN ();
366
367 Status = GetArmTrngUuid (&Guid);
368 if (RETURN_ERROR (Status)) {
369 ASSERT_RETURN_ERROR (Status);
370 goto ErrorHandler;
371 }
372
373 DEBUG ((
374 DEBUG_INFO,
375 "FW-TRNG: Version %d.%d, GUID {%g}\n",
376 MajorRev,
377 MinorRev,
378 &Guid
379 ));
380
381 DEBUG_CODE_END ();
382
383 return RETURN_SUCCESS;
384
385 ErrorHandler:
386 DEBUG ((DEBUG_ERROR, "ArmTrngLib could not be correctly initialized.\n"));
387 return RETURN_SUCCESS;
388 }