Re: [PATCH v2 3/8] ArmPkg: Add Arm Firmware TRNG library


Sami Mujawar
 

Hi Leif,

Thank you for the feedback.

Please find my response inline marked [SAMI].

Regards,

Sami Mujawar


On 24/11/2021 01:01 PM, Leif Lindholm wrote:
Hi Sami,

On Tue, Nov 16, 2021 at 11:32:55 +0000, Sami Mujawar wrote:
Bugzilla: 3668 (https://bugzilla.tianocore.org/show_bug.cgi?id=3668)

The Arm True Random Number Generator Firmware, Interface 1.0,
Platform Design Document
(https://developer.arm.com/documentation/den0098/latest/)
defines an interface between an Operating System (OS) executing
at EL1 and Firmware (FW) exposing a conditioned entropy source
that is provided by a TRNG back end.

The conditioned entropy, that is provided by the TRNG FW interface,
is commonly used to seed deterministic random number generators.

This patch adds a TrngLib library that implements the Arm TRNG
firmware interface.

Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
---

Notes:
v2:
- MdePkg\Include\Library\TrngLib.h is base type [LIMING]
library. It can use RETURN_STATUS instead of
EFI_STATUS.
- Replaced EFI_STATUS with RETURN_STATUS. [SAMI]
- MdePkg\Include\Library\TrngLib.h API parameter [LIMING]
doesn't require CONST. CONST means the value
specified by the input pointer will not be
changed in API implementation.
- Removed the use of constant pointers in the [SAMI]
TRNG API.

ArmPkg/ArmPkg.dsc | 1 +
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h | 64 +++
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c | 483 ++++++++++++++++++++
ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf | 34 ++
4 files changed, 582 insertions(+)

diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 59fd8f295d4f614cc68ee1021e691f94e279ab81..23df68c5eb53df11de5d96bde4949f3c833c9b2c 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -156,6 +156,7 @@ [Components.common]
ArmPkg/Drivers/ArmCrashDumpDxe/ArmCrashDumpDxe.inf
ArmPkg/Drivers/ArmScmiDxe/ArmScmiDxe.inf
+ ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf
ArmPkg/Universal/Smbios/ProcessorSubClassDxe/ProcessorSubClassDxe.inf
ArmPkg/Universal/Smbios/SmbiosMiscDxe/SmbiosMiscDxe.inf
ArmPkg/Universal/Smbios/OemMiscLibNull/OemMiscLibNull.inf
diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h
new file mode 100644
index 0000000000000000000000000000000000000000..42236e743d972df0df205b1565496afeff5785f3
--- /dev/null
+++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngDefs.h
@@ -0,0 +1,64 @@
+/** @file
+ Arm Firmware TRNG definitions.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - [1] Arm True Random Number Generator Firmware, Interface 1.0,
+ Platform Design Document.
+ (https://developer.arm.com/documentation/den0098/latest/)
+
+ @par Glossary:
+ - TRNG - True Random Number Generator
+ - FID - Function ID
+**/
+
+#ifndef ARM_FW_TRNG_DEFS_H_
+#define ARM_FW_TRNG_DEFS_H_
+
+// Firmware TRNG interface Function IDs
+#define FID_TRNG_VERSION 0x84000050
+#define FID_TRNG_FEATURES 0x84000051
+#define FID_TRNG_GET_UUID 0x84000052
+#define FID_TRNG_RND_AARCH32 0x84000053
+#define FID_TRNG_RND_AARCH64 0xC4000053
Do these belong in ArmStdSmc.h?
[SAMI] I will fix this in the next version.

+
+// Firmware TRNG revision mask and shift
+#define TRNG_REV_MAJOR_MASK 0x7FFF
+#define TRNG_REV_MINOR_MASK 0xFFFF
+#define TRNG_REV_MAJOR_SHIFT 16
+#define TRNG_REV_MINOR_SHIFT 0
+
+// Firmware TRNG status codes
+#define TRNG_STATUS_SUCCESS (INT32)(0)
+#define TRNG_NOT_SUPPORTED (INT32)(-1)
+#define TRNG_INVALID_PARAMETER (INT32)(-2)
+#define TRNG_NO_ENTROPY (INT32)(-3)
And the rest of the stuff to here, really?
[SAMI] I will fix this in the next version.

+#if defined (MDE_CPU_ARM)
+/** FID to use on AArch32 platform to request entropy.
+*/
+#define FID_TRNG_RND FID_TRNG_RND_AARCH32
+
+/** Maximum bits of entropy supported on AArch32.
+*/
+#define MAX_ENTROPY_BITS 96
+#elif defined (MDE_CPU_AARCH64)
+/** FID to use on AArch64 platform to request entropy.
+*/
+#define FID_TRNG_RND FID_TRNG_RND_AARCH64
+
+/** Maximum bits of entropy supported on AArch64.
+*/
+#define MAX_ENTROPY_BITS 192
+#else
+#error "Firmware TRNG not supported. Unknown chipset."
+#endif
+
+/** Typedef for SMC or HVC arguments.
+*/
+typedef ARM_SMC_ARGS ARM_MONITOR_ARGS;
+
+#endif // ARM_FW_TRNG_DEFS_H_
diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c
new file mode 100644
index 0000000000000000000000000000000000000000..314e7ffbc232ae90bbb77306f9c7113ce63012c8
--- /dev/null
+++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.c
@@ -0,0 +1,483 @@
+/** @file
+ Arm Firmware TRNG interface library.
+
+ Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+ @par Reference(s):
+ - [1] Arm True Random Number Generator Firmware, Interface 1.0,
+ Platform Design Document.
+ (https://developer.arm.com/documentation/den0098/latest/)
+ - [2] NIST Special Publication 800-90A Revision 1, June 2015, Recommendation
+ for Random Number Generation Using Deterministic Random Bit Generators.
+ (https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
+ - [3] NIST Special Publication 800-90B, Recommendation for the Entropy
+ Sources Used for Random Bit Generation.
+ (https://csrc.nist.gov/publications/detail/sp/800-90b/final)
+ - [4] (Second Draft) NIST Special Publication 800-90C, Recommendation for
+ Random Bit Generator (RBG) Constructions.
+ (https://csrc.nist.gov/publications/detail/sp/800-90c/draft)
+
+ @par Glossary:
+ - TRNG - True Random Number Generator
+ - FID - Function ID
+**/
+
+#include <Base.h>
+#include <Library/ArmHvcLib.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#include "ArmFwTrngDefs.h"
+
+/** Convert TRNG status codes to EFI status codes.
+
+ @param [in] TrngStatus TRNG status code.
+
+ @retval RETURN_SUCCESS Success.
+ @retval RETURN_UNSUPPORTED Function not implemented.
+ @retval RETURN_INVALID_PARAMETER A parameter is invalid.
+ @retval RETURN_NOT_READY No Entropy available.
+**/
+STATIC
+RETURN_STATUS
+TrngStatusToEfiStatus (
+ IN INT32 TrngStatus
+ )
+{
+ switch (TrngStatus) {
+ case TRNG_NOT_SUPPORTED:
+ return RETURN_UNSUPPORTED;
+
+ case TRNG_INVALID_PARAMETER:
+ return RETURN_INVALID_PARAMETER;
+
+ case TRNG_NO_ENTROPY:
+ return RETURN_NOT_READY;
+
+ case TRNG_STATUS_SUCCESS:
+ default:
+ return RETURN_SUCCESS;
+ }
+}
+
+/** Invoke the monitor call using the appropriate conduit.
+ If PcdMonitorConduitHvc is TRUE use the HVC conduit else use SMC conduit.
+
+ @param [in, out] Args Arguments passed to and returned from the monitor.
+
+ @return VOID
+**/
+STATIC
+VOID
+ArmCallMonitor (
+ IN OUT ARM_MONITOR_ARGS *Args
+ )
+{
+ if (FeaturePcdGet (PcdMonitorConduitHvc)) {
+ ArmCallHvc ((ARM_HVC_ARGS*)Args);
+ } else {
+ ArmCallSmc ((ARM_SMC_ARGS*)Args);
+ }
+}
Should this be in (a potentially renamed) ArmSmcLib?
[SAMI] Looking at ArmSmcLib and ArmHvcLib libraries there is not much difference in the code other than the SMC/HVC call. Please let me know if I should submit a patch to unify these in ArmMonitorLib?
The ArmCall<Smc|Hvc> APIs would still remain the same but moved to ArmMonitorLib.

+
+/** Get the version of the TRNG backend.
+
+ A TRNG may be implemented by the system firmware, in which case this
+ function shall return the version of the TRNG backend.
+ The implementation must return NOT_SUPPORTED if a Back end is not present.
+
+ @param [out] MajorRevision Major revision.
+ @param [out] MinorRevision Minor revision.
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval RETURN_INVALID_PARAMETER Invalid parameter.
+ @retval RETURN_UNSUPPORTED Backend not present.
+**/
+RETURN_STATUS
+EFIAPI
+GetTrngVersion (
+ OUT UINT16 *MajorRevision,
+ OUT UINT16 *MinorRevision
+ )
+{
+ RETURN_STATUS Status;
+ ARM_MONITOR_ARGS Parameters;
+ INT32 Revision;
+
+ if ((MajorRevision == NULL) || (MinorRevision == NULL)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ ZeroMem (&Parameters, sizeof (Parameters));
+
+ /*
+ Cf. [1], 2.1 TRNG_VERSION
+ Function ID (W0) 0x8400_0050
+ Parameters
+ W1-W7 Reserved (MBZ)
+ Returns
+ Success (W0 > 0) W0[31] MBZ
+ W0[30:16] Major revision
+ W0[15:0] Minor revision
+ W1 - W3 Reserved (MBZ)
+ Error (W0 < 0)
+ NOT_SUPPORTED Function not implemented
+ */
I have a comment on the placement of API descriptions further down.

+ Parameters.Arg0 = FID_TRNG_VERSION;
+ ArmCallMonitor (&Parameters);
+
+ Revision = (INT32)Parameters.Arg0;
+ // Convert status codes to EFI status codes.
+ Status = TrngStatusToEfiStatus (Revision);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *MinorRevision = (Revision & TRNG_REV_MINOR_MASK);
+ *MajorRevision = ((Revision >> TRNG_REV_MAJOR_SHIFT) & TRNG_REV_MAJOR_MASK);
+ return RETURN_SUCCESS;
+}
+
+#ifndef MDEPKG_NDEBUG
+/** Get the features supported by the TRNG backend.
+
+ The caller can determine if functions defined in the TRNG ABI are
+ present in the ABI implementation.
+
+ @param [in] FunctionId Function Id.
+ @param [out] Capability Function specific capability if present
+ otherwise Zero is returned.
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval RETURN_INVALID_PARAMETER Invalid parameter.
+ @retval RETURN_UNSUPPORTED Function not implemented.
+**/
+STATIC
+RETURN_STATUS
+EFIAPI
+GetTrngFeatures (
+ IN CONST UINT32 FunctionId,
+ OUT UINT32 *Capability OPTIONAL
+ )
+{
+ ARM_MONITOR_ARGS Parameters;
+
+ ZeroMem (&Parameters, sizeof (Parameters));
+
+ /*
+ Cf. [1], Section 2.2 TRNG_FEATURES
+ Function ID (W0) 0x8400_0051
+ Parameters
+ W1 trng_func_id
+ W2-W7 Reserved (MBZ)
+ Returns
+ Success (W0 >= 0)
+ SUCCESS Function is implemented.
+ > 0 Function is implemented and
+ has specific capabilities,
+ see function definition.
+ Error (W0 < 0)
+ NOT_SUPPORTED Function with FID=trng_func_id
+ is not implemented
+ */
I have a comment on the placement of API descriptions further down.

+ Parameters.Arg0 = FID_TRNG_FEATURES;
+ Parameters.Arg1 = FunctionId;
+ ArmCallMonitor (&Parameters);
+ if (Parameters.Arg0 < TRNG_STATUS_SUCCESS) {
+ return RETURN_UNSUPPORTED;
+ }
+
+ if (Capability != NULL) {
+ *Capability = Parameters.Arg0;
+ }
+
+ return RETURN_SUCCESS;
+}
+#endif //MDEPKG_NDEBUG
+
+/** Get the UUID of the TRNG backend.
+
+ A TRNG may be implemented by the system firmware, in which case this
+ function shall return the UUID of the TRNG backend.
+ Returning the TRNG UUID is optional and if not implemented, RETURN_UNSUPPORTED
+ shall be returned.
+
+ Note: The caller must not rely on the returned UUID as a trustworthy TRNG
+ Back end identity
+
+ @param [out] Guid UUID of the TRNG backend.
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval RETURN_INVALID_PARAMETER Invalid parameter.
+ @retval RETURN_UNSUPPORTED Function not implemented.
+**/
+RETURN_STATUS
+EFIAPI
+GetTrngUuid (
+ OUT GUID *Guid
+ )
+{
+ RETURN_STATUS Status;
+ ARM_MONITOR_ARGS Parameters;
+
+ ZeroMem (&Parameters, sizeof (Parameters));
+
+ /*
+ Cf. [1], Section 2.3 TRNG_GET_UUID
+ Function ID (W0) 0x8400_0052
+ Parameters
+ W1-W7 Reserved (MBZ)
+ Returns
+ Success (W0 != -1)
+ W0 UUID[31:0]
+ W1 UUID[63:32]
+ W2 UUID[95:64]
+ W3 UUID[127:96]
+ Error (W0 = -1)
+ W0 NOT_SUPPORTED
+ */
+ Parameters.Arg0 = FID_TRNG_GET_UUID;
+ ArmCallMonitor (&Parameters);
+
+ // Convert status codes to EFI status codes.
+ Status = TrngStatusToEfiStatus ((INT32)Parameters.Arg0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Guid->Data1 = (Parameters.Arg0 & MAX_UINT32);
+ Guid->Data2 = (Parameters.Arg1 & MAX_UINT16);
+ Guid->Data3 = ((Parameters.Arg1 >> 16) & MAX_UINT16);
+
+ Guid->Data4[0] = (Parameters.Arg2 & MAX_UINT8);
+ Guid->Data4[1] = ((Parameters.Arg2 >> 8) & MAX_UINT8);
+ Guid->Data4[2] = ((Parameters.Arg2 >> 16) & MAX_UINT8);
+ Guid->Data4[3] = ((Parameters.Arg2 >> 24) & MAX_UINT8);
+
+ Guid->Data4[4] = (Parameters.Arg3 & MAX_UINT8);
+ Guid->Data4[5] = ((Parameters.Arg3 >> 8) & MAX_UINT8);
+ Guid->Data4[6] = ((Parameters.Arg3 >> 16) & MAX_UINT8);
+ Guid->Data4[7] = ((Parameters.Arg3 >> 24) & MAX_UINT8);
+
+ DEBUG ((DEBUG_INFO, "FW-TRNG: UUID %g\n", Guid));
+
+ return RETURN_SUCCESS;
+}
+
+/** Returns maximum number of entropy bits that can be returned in a single
+ call.
+
+ @return Returns the maximum number of Entropy bits that can be returned
+ in a single call to GetEntropy().
+**/
+UINTN
+EFIAPI
+GetTrngMaxSupportedEntropyBits (
+ VOID
+ )
+{
+ return MAX_ENTROPY_BITS;
+}
+
+/** Returns N bits of conditioned entropy.
+
+ See [3] Section 2.3.1 GetEntropy: An Interface to the Entropy Source
+ GetEntropy
+ Input:
+ bits_of_entropy: the requested amount of entropy
+ Output:
+ entropy_bitstring: The string that provides the requested entropy.
+ status: A Boolean value that is TRUE if the request has been satisfied,
+ and is FALSE otherwise.
+
+ Note: In this implementation this function returns a status code instead
+ of a boolean value.
+ This is also compatible with the definition of Get_Entropy, see [2]
+ Section 7.4 Entropy Source Calls.
+ (status, entropy_bitstring) = Get_Entropy (
+ requested_entropy,
+ max_length
+ )
+
+ @param [in] EntropyBits Number of entropy bits requested.
+ @param [out] Buffer Buffer to return the entropy bits.
+ @param [in] BufferSize Size of the Buffer in bytes.
+
+ @retval RETURN_SUCCESS The function completed successfully.
+ @retval RETURN_INVALID_PARAMETER Invalid parameter.
+ @retval RETURN_UNSUPPORTED Function not implemented.
+ @retval RETURN_BAD_BUFFER_SIZE Buffer size is too small.
+ @retval RETURN_NOT_READY No Entropy available.
+**/
+RETURN_STATUS
+EFIAPI
+GetEntropy (
+ IN CONST UINTN EntropyBits,
+ OUT UINT8 *Buffer,
+ IN CONST UINTN BufferSize
+ )
+{
+ RETURN_STATUS Status;
+ ARM_MONITOR_ARGS Parameters;
+ UINTN EntropyBytes;
+ UINTN LastValidBits;
+ UINTN ArgSelector;
+ UINTN BytesToClear;
+
+ // [1] Section 2.4.3 Caller responsibilities.
+ // The caller cannot request more than MAX_BITS bits of conditioned
+ // entropy per call.
Comment is redundant, code is clearer without it.

+ if ((EntropyBits == 0) || (EntropyBits > MAX_ENTROPY_BITS)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ EntropyBytes = (EntropyBits + 7) >> 3;
+ if (EntropyBytes > BufferSize) {
Not for later: we're verifying the value of EntropyBytes here - if
there are more aspects of it that need verifying, that should also be
done here.

+ return RETURN_BAD_BUFFER_SIZE;
+ }
+
+ ZeroMem (Buffer, BufferSize);
+ ZeroMem (&Parameters, sizeof (Parameters));
+
+ /*
+ Cf. [1], Section 2.4 TRNG_RND
+ Function ID (W0) 0x8400_0053
+ 0xC400_0053
+ SMC32 Parameters
+ W1 N bits of entropy (1 6 N 6 96)
+ W2-W7 Reserved (MBZ)
+ SMC64 Parameters
+ X1 N bits of entropy (1 6 N 6 192)
+ X2-X7 Reserved (MBZ)
+ SMC32 Returns
+ Success (W0 = 0):
+ W0 MBZ
+ W1 Entropy[95:64]
+ W2 Entropy[63:32]
+ W3 Entropy[31:0]
+ Error (W0 < 0)
+ W0 NOT_SUPPORTED
+ NO_ENTROPY
+ INVALID_PARAMETERS
+ W1 - W3 Reserved (MBZ)
+ SMC64 Returns
+ Success (X0 = 0):
+ X0 MBZ
+ X1 Entropy[191:128]
+ X2 Entropy[127:64]
+ X3 Entropy[63:0]
+ Error (X0 < 0)
+ X0 NOT_SUPPORTED
+ NO_ENTROPY
+ INVALID_PARAMETERS
+ X1 - X3 Reserved (MBZ)
+ */
The above comment block completely wrecks the readability of the
function.

Would suggest putting it in the header file describing the monitor
call. For our SIP SVC calls, we've done this in the following form:

/*
* SMC call to retrieve number of CPUs present in the system.
* Input values:
* x0: NUVIA_SIP_GET_NUM_CPUS
* Return values:
* x0: SMC_OK
* x1: Number of CPUs present
*/
#define NUVIA_SIP_GET_NUM_CPUS SIP_FUNCTION_ID(0x20)

(Where SIP_FUNCTION_ID is one of a set of macros I should submit for
addition to ArmStdSmc.h)

+ Parameters.Arg0 = FID_TRNG_RND;
+ Parameters.Arg1 = EntropyBits;
+ ArmCallMonitor (&Parameters);
+
+ // Convert status codes to EFI status codes.
Function name already says this, comment redundant.

+ Status = TrngStatusToEfiStatus ((INT32)Parameters.Arg0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
From here

+ // Extract Data
+ // ArgSelector = ((EntropyBytes + 3) >> 2); for AArch32
+ // ArgSelector = ((EntropyBytes + 7) >> 3); for AArch64
+ // ((sizeof (UINTN) >> 2) + 1) is 3 or 2 depending on size of UINTN
+ ArgSelector = ((EntropyBytes + (sizeof (UINTN) - 1)) >>
+ ((sizeof (UINTN) >> 2) + 1));
+
+ switch (ArgSelector) {
+ case 3:
+ CopyMem (&Buffer[(sizeof (UINTN) * 2)], &Parameters.Arg1, sizeof (UINTN));
+
+ case 2:
+ CopyMem (&Buffer[sizeof (UINTN)], &Parameters.Arg2, sizeof (UINTN));
+
+ case 1:
+ CopyMem (&Buffer[0], &Parameters.Arg3, sizeof (UINTN));
+ break;
+
+ default:
+ ASSERT (0);
+ return RETURN_INVALID_PARAMETER;
+ } // switch
to here ... I'm not convinced you yourself would be able to read or
explain this code a few months down the line.

Is there a strong reason for why Buffer cannot be a UINTN *?
[SAMI] The specification allows to request minimum 1 bit of entropy (although I don't think there would be a use case for this). Therefore, I selected UINT8.
However, I agree the logic is complex. I will simplify this code.

I think what this code is doing can equally be written as:

Buffer[0] = Parameters.Arg3;
if ((EntropyBytes / sizeof (UINTN)) > 1) {
Buffer[1] = Parameters.Arg2;
}
if ((EntropyBytes / sizeof (UINTN)) > 2) {
Buffer[2] = Parameters.Arg1;
}

+
+
+ // [1] Section 2.4.3 Caller responsibilities.
+ // The caller must ensure that only the value in Entropy[N-1:0] is consumed
+ // and that the remaining bits in Entropy[MAX_BITS-1:N] are ignored.
+ // Therefore, Clear the unused upper bytes.
This is source code, not the specification.

// Mask off any unused top bytes, in accordance with specification

is sufficient as a comment.
[SAMI] I will fix this and the other comments in the next revision.

/
Leif

+ BytesToClear = (sizeof (UINTN) * ArgSelector) - EntropyBytes;
+ if (BytesToClear != 0) {
+ ZeroMem (&Buffer[EntropyBytes], BytesToClear);
+ }
+
+ // Clear the unused MSB bits of the last byte.
+ LastValidBits = EntropyBits & 0x7;
+ if (LastValidBits != 0) {
+ Buffer[EntropyBytes - 1] &= (0xFF >> (8 - LastValidBits));
+ }
+
+ return Status;
+}
+
+/** The constructor checks that the FW-TRNG interface is supported
+ by the host firmware.
+
+ It will ASSERT() if FW-TRNG is not supported.
+ It will always return RETURN_SUCCESS.
+
+ @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS.
+**/
+RETURN_STATUS
+EFIAPI
+ArmFwTrngLibConstructor (
+ VOID
+ )
+{
+ RETURN_STATUS Status;
+ UINT16 MajorRev;
+ UINT16 MinorRev;
+ GUID Guid;
+
+ Status = GetTrngVersion (&MajorRev, &MinorRev);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+#ifndef MDEPKG_NDEBUG
+ // Check that the required features are present.
+ Status = GetTrngFeatures (FID_TRNG_RND, NULL);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ // Check if TRNG UUID is supported and if so trace the GUID.
+ Status = GetTrngFeatures (FID_TRNG_GET_UUID, NULL);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+#endif
+
+ Status = GetTrngUuid (&Guid);
+ if (EFI_ERROR (Status)) {
+ return RETURN_SUCCESS;
+ }
+
+ DEBUG ((
+ DEBUG_INFO,
+ "FW-TRNG: Version %d.%d, GUID {%g}\n",
+ MajorRev,
+ MinorRev,
+ Guid
+ ));
+
+ return RETURN_SUCCESS;
+}
diff --git a/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf
new file mode 100644
index 0000000000000000000000000000000000000000..4b2c58251fbe8fbcb5af308736db014e8d954720
--- /dev/null
+++ b/ArmPkg/Library/ArmFwTrngLib/ArmFwTrngLib.inf
@@ -0,0 +1,34 @@
+## @file
+# Arm Firmware TRNG interface library.
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = ArmFwTrngLib
+ FILE_GUID = 10DE97C9-28E4-4C9B-A53E-8D7D1B0DD4E0
+ VERSION_STRING = 1.0
+ MODULE_TYPE = BASE
+ LIBRARY_CLASS = TrngLib
+ CONSTRUCTOR = ArmFwTrngLibConstructor
+
+[Sources]
+ ArmFwTrngDefs.h
+ ArmFwTrngLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmSmcLib
+ ArmHvcLib
+ BaseLib
+ BaseMemoryLib
+
+[Pcd]
+ gArmTokenSpaceGuid.PcdMonitorConduitHvc
+
--
'Guid(CE165669-3EF3-493F-B85D-6190EE5B9759)'




Join devel@edk2.groups.io to automatically receive all group messages.