2 Arm Firmware TRNG interface library.
4 Copyright (c) 2021 - 2022, Arm Limited. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
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)
17 - TRNG - True Random Number Generator
22 #include <Library/ArmLib.h>
23 #include <Library/ArmMonitorLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/DebugLib.h>
27 #include "ArmTrngDefs.h"
29 /** Convert TRNG status codes to RETURN status codes.
31 @param [in] TrngStatus TRNG status code.
33 @retval RETURN_SUCCESS Success.
34 @retval RETURN_UNSUPPORTED Function not implemented or
36 @retval RETURN_INVALID_PARAMETER A parameter is invalid.
37 @retval RETURN_NOT_READY No Entropy available.
41 TrngStatusToReturnStatus (
46 case TRNG_STATUS_NOT_SUPPORTED
:
47 return RETURN_UNSUPPORTED
;
49 case TRNG_STATUS_INVALID_PARAMETER
:
50 return RETURN_INVALID_PARAMETER
;
52 case TRNG_STATUS_NO_ENTROPY
:
53 return RETURN_NOT_READY
;
55 case TRNG_STATUS_SUCCESS
:
56 return RETURN_SUCCESS
;
60 return RETURN_UNSUPPORTED
;
63 return RETURN_SUCCESS
;
67 /** Get the version of the Arm TRNG backend.
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.
73 @param [out] MajorRevision Major revision.
74 @param [out] MinorRevision Minor revision.
76 @retval RETURN_SUCCESS The function completed successfully.
77 @retval RETURN_INVALID_PARAMETER Invalid parameter.
78 @retval RETURN_UNSUPPORTED Backend not present.
83 OUT UINT16
*MajorRevision
,
84 OUT UINT16
*MinorRevision
88 ARM_MONITOR_ARGS Parameters
;
91 if ((MajorRevision
== NULL
) || (MinorRevision
== NULL
)) {
92 return RETURN_INVALID_PARAMETER
;
95 ZeroMem (&Parameters
, sizeof (Parameters
));
97 Parameters
.Arg0
= ARM_SMC_ID_TRNG_VERSION
;
98 ArmMonitorCall (&Parameters
);
100 Revision
= (INT32
)Parameters
.Arg0
;
101 Status
= TrngStatusToReturnStatus (Revision
);
102 if (RETURN_ERROR (Status
)) {
106 *MinorRevision
= (Revision
& TRNG_REV_MINOR_MASK
);
107 *MajorRevision
= ((Revision
>> TRNG_REV_MAJOR_SHIFT
) & TRNG_REV_MAJOR_MASK
);
108 return RETURN_SUCCESS
;
111 /** Get the features supported by the Arm TRNG backend.
113 The caller can determine if functions defined in the Arm TRNG ABI are
114 present in the ABI implementation.
116 @param [in] FunctionId Function Id.
117 @param [out] Capability Function specific capability if present.
119 @retval RETURN_SUCCESS The function completed successfully.
120 @retval RETURN_INVALID_PARAMETER Invalid parameter.
121 @retval RETURN_UNSUPPORTED Function not implemented.
127 IN CONST UINT32 FunctionId
,
128 OUT UINT32
*Capability OPTIONAL
131 ARM_MONITOR_ARGS Parameters
;
132 RETURN_STATUS Status
;
134 ZeroMem (&Parameters
, sizeof (Parameters
));
136 Parameters
.Arg0
= ARM_SMC_ID_TRNG_FEATURES
;
137 Parameters
.Arg1
= FunctionId
;
138 ArmMonitorCall (&Parameters
);
140 Status
= TrngStatusToReturnStatus (Parameters
.Arg0
);
141 if (RETURN_ERROR (Status
)) {
145 if (Capability
!= NULL
) {
146 *Capability
= (UINT32
)Parameters
.Arg0
;
149 return RETURN_SUCCESS
;
152 /** Get the UUID of the Arm TRNG backend.
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.
159 Note: The caller must not rely on the returned UUID as a trustworthy Arm TRNG
162 @param [out] Guid UUID of the Arm TRNG backend.
164 @retval RETURN_SUCCESS The function completed successfully.
165 @retval RETURN_INVALID_PARAMETER Invalid parameter.
166 @retval RETURN_UNSUPPORTED Function not implemented.
174 ARM_MONITOR_ARGS Parameters
;
177 return RETURN_INVALID_PARAMETER
;
180 ZeroMem (&Parameters
, sizeof (Parameters
));
182 Parameters
.Arg0
= ARM_SMC_ID_TRNG_GET_UUID
;
183 ArmMonitorCall (&Parameters
);
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
);
190 Guid
->Data1
= (Parameters
.Arg0
& MAX_UINT32
);
191 Guid
->Data2
= (Parameters
.Arg1
& MAX_UINT16
);
192 Guid
->Data3
= ((Parameters
.Arg1
>> 16) & MAX_UINT16
);
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
);
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
);
204 DEBUG ((DEBUG_INFO
, "FW-TRNG: UUID %g\n", Guid
));
206 return RETURN_SUCCESS
;
209 /** Returns maximum number of entropy bits that can be returned in a single
212 @return Returns the maximum number of Entropy bits that can be returned
213 in a single call to GetArmTrngEntropy().
217 GetArmTrngMaxSupportedEntropyBits (
221 return MAX_ENTROPY_BITS
;
224 /** Returns N bits of conditioned entropy.
226 See [2] Section 2.3.1 GetEntropy: An Interface to the Entropy Source
229 bits_of_entropy: the requested amount of entropy
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.
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.
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.
248 IN UINTN EntropyBits
,
253 RETURN_STATUS Status
;
254 ARM_MONITOR_ARGS Parameters
;
258 UINTN EntropyData
[3];
260 if ((EntropyBits
== 0) ||
261 (EntropyBits
> MAX_ENTROPY_BITS
) ||
264 return RETURN_INVALID_PARAMETER
;
267 EntropyBytes
= (EntropyBits
+ 7) >> 3;
268 if (EntropyBytes
> BufferSize
) {
269 return RETURN_BAD_BUFFER_SIZE
;
272 ZeroMem (Buffer
, BufferSize
);
273 ZeroMem (&Parameters
, sizeof (Parameters
));
275 Parameters
.Arg0
= ARM_SMC_ID_TRNG_RND
;
276 Parameters
.Arg1
= EntropyBits
;
277 ArmMonitorCall (&Parameters
);
279 Status
= TrngStatusToReturnStatus ((INT32
)Parameters
.Arg0
);
280 if (RETURN_ERROR (Status
)) {
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
;
291 CopyMem (Buffer
, EntropyData
, EntropyBytes
);
293 // Mask off any unused top bytes, in accordance with specification.
294 BytesToClear
= BufferSize
- EntropyBytes
;
295 if (BytesToClear
!= 0) {
296 ZeroMem (&Buffer
[EntropyBytes
], BytesToClear
);
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
));
308 /** The constructor checks that the FW-TRNG interface is supported
309 by the host firmware.
311 It will ASSERT() if FW-TRNG is not supported.
312 It will always return RETURN_SUCCESS.
314 @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.
318 ArmTrngLibConstructor (
322 ARM_MONITOR_ARGS Parameters
;
323 RETURN_STATUS Status
;
328 ZeroMem (&Parameters
, sizeof (Parameters
));
330 Parameters
.Arg0
= SMCCC_VERSION
;
331 ArmMonitorCall (&Parameters
);
332 Status
= TrngStatusToReturnStatus ((INT32
)Parameters
.Arg0
);
333 if (RETURN_ERROR (Status
)) {
334 ASSERT_RETURN_ERROR (Status
);
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
);
345 Status
= GetArmTrngVersion (&MajorRev
, &MinorRev
);
346 if (RETURN_ERROR (Status
)) {
347 ASSERT_RETURN_ERROR (Status
);
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
);
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
);
367 Status
= GetArmTrngUuid (&Guid
);
368 if (RETURN_ERROR (Status
)) {
369 ASSERT_RETURN_ERROR (Status
);
375 "FW-TRNG: Version %d.%d, GUID {%g}\n",
383 return RETURN_SUCCESS
;
386 DEBUG ((DEBUG_ERROR
, "ArmTrngLib could not be correctly initialized.\n"));
387 return RETURN_SUCCESS
;