123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- /** @file
- Arm Firmware TRNG interface library.
- Copyright (c) 2021 - 2022, 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-90B, Recommendation for the Entropy
- Sources Used for Random Bit Generation.
- (https://csrc.nist.gov/publications/detail/sp/800-90b/final)
- @par Glossary:
- - TRNG - True Random Number Generator
- - FID - Function ID
- **/
- #include <Base.h>
- #include <Library/ArmLib.h>
- #include <Library/ArmMonitorLib.h>
- #include <Library/BaseMemoryLib.h>
- #include <Library/DebugLib.h>
- #include "ArmTrngDefs.h"
- /** Convert TRNG status codes to RETURN status codes.
- @param [in] TrngStatus TRNG status code.
- @retval RETURN_SUCCESS Success.
- @retval RETURN_UNSUPPORTED Function not implemented or
- negative return code.
- @retval RETURN_INVALID_PARAMETER A parameter is invalid.
- @retval RETURN_NOT_READY No Entropy available.
- **/
- STATIC
- RETURN_STATUS
- TrngStatusToReturnStatus (
- IN INT32 TrngStatus
- )
- {
- switch (TrngStatus) {
- case TRNG_STATUS_NOT_SUPPORTED:
- return RETURN_UNSUPPORTED;
- case TRNG_STATUS_INVALID_PARAMETER:
- return RETURN_INVALID_PARAMETER;
- case TRNG_STATUS_NO_ENTROPY:
- return RETURN_NOT_READY;
- case TRNG_STATUS_SUCCESS:
- return RETURN_SUCCESS;
- default:
- if (TrngStatus < 0) {
- return RETURN_UNSUPPORTED;
- }
- return RETURN_SUCCESS;
- }
- }
- /** Get the version of the Arm TRNG backend.
- A TRNG may be implemented by the system firmware, in which case this
- function shall return the version of the Arm 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
- GetArmTrngVersion (
- 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));
- Parameters.Arg0 = ARM_SMC_ID_TRNG_VERSION;
- ArmMonitorCall (&Parameters);
- Revision = (INT32)Parameters.Arg0;
- Status = TrngStatusToReturnStatus (Revision);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- *MinorRevision = (Revision & TRNG_REV_MINOR_MASK);
- *MajorRevision = ((Revision >> TRNG_REV_MAJOR_SHIFT) & TRNG_REV_MAJOR_MASK);
- return RETURN_SUCCESS;
- }
- /** Get the features supported by the Arm TRNG backend.
- The caller can determine if functions defined in the Arm TRNG ABI are
- present in the ABI implementation.
- @param [in] FunctionId Function Id.
- @param [out] Capability Function specific capability if present.
- @retval RETURN_SUCCESS The function completed successfully.
- @retval RETURN_INVALID_PARAMETER Invalid parameter.
- @retval RETURN_UNSUPPORTED Function not implemented.
- **/
- STATIC
- RETURN_STATUS
- EFIAPI
- GetArmTrngFeatures (
- IN CONST UINT32 FunctionId,
- OUT UINT32 *Capability OPTIONAL
- )
- {
- ARM_MONITOR_ARGS Parameters;
- RETURN_STATUS Status;
- ZeroMem (&Parameters, sizeof (Parameters));
- Parameters.Arg0 = ARM_SMC_ID_TRNG_FEATURES;
- Parameters.Arg1 = FunctionId;
- ArmMonitorCall (&Parameters);
- Status = TrngStatusToReturnStatus (Parameters.Arg0);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- if (Capability != NULL) {
- *Capability = (UINT32)Parameters.Arg0;
- }
- return RETURN_SUCCESS;
- }
- /** Get the UUID of the Arm 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 Arm 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 Arm TRNG
- Back end identity
- @param [out] Guid UUID of the Arm TRNG backend.
- @retval RETURN_SUCCESS The function completed successfully.
- @retval RETURN_INVALID_PARAMETER Invalid parameter.
- @retval RETURN_UNSUPPORTED Function not implemented.
- **/
- RETURN_STATUS
- EFIAPI
- GetArmTrngUuid (
- OUT GUID *Guid
- )
- {
- ARM_MONITOR_ARGS Parameters;
- if (Guid == NULL) {
- return RETURN_INVALID_PARAMETER;
- }
- ZeroMem (&Parameters, sizeof (Parameters));
- Parameters.Arg0 = ARM_SMC_ID_TRNG_GET_UUID;
- ArmMonitorCall (&Parameters);
- // Only invalid value is TRNG_STATUS_NOT_SUPPORTED (-1).
- if ((INT32)Parameters.Arg0 == TRNG_STATUS_NOT_SUPPORTED) {
- return TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
- }
- 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 GetArmTrngEntropy().
- **/
- UINTN
- EFIAPI
- GetArmTrngMaxSupportedEntropyBits (
- VOID
- )
- {
- return MAX_ENTROPY_BITS;
- }
- /** Returns N bits of conditioned entropy.
- See [2] 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.
- @param [in] EntropyBits Number of entropy bits requested.
- @param [in] BufferSize Size of the Buffer in bytes.
- @param [out] Buffer Buffer to return the entropy bits.
- @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
- GetArmTrngEntropy (
- IN UINTN EntropyBits,
- IN UINTN BufferSize,
- OUT UINT8 *Buffer
- )
- {
- RETURN_STATUS Status;
- ARM_MONITOR_ARGS Parameters;
- UINTN EntropyBytes;
- UINTN LastValidBits;
- UINTN BytesToClear;
- UINTN EntropyData[3];
- if ((EntropyBits == 0) ||
- (EntropyBits > MAX_ENTROPY_BITS) ||
- (Buffer == NULL))
- {
- return RETURN_INVALID_PARAMETER;
- }
- EntropyBytes = (EntropyBits + 7) >> 3;
- if (EntropyBytes > BufferSize) {
- return RETURN_BAD_BUFFER_SIZE;
- }
- ZeroMem (Buffer, BufferSize);
- ZeroMem (&Parameters, sizeof (Parameters));
- Parameters.Arg0 = ARM_SMC_ID_TRNG_RND;
- Parameters.Arg1 = EntropyBits;
- ArmMonitorCall (&Parameters);
- Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- // The entropy data is returned in the Parameters.Arg<3..1>
- // With the lower order bytes in Parameters.Arg3 and the higher
- // order bytes being stored in Parameters.Arg1.
- EntropyData[0] = Parameters.Arg3;
- EntropyData[1] = Parameters.Arg2;
- EntropyData[2] = Parameters.Arg1;
- CopyMem (Buffer, EntropyData, EntropyBytes);
- // Mask off any unused top bytes, in accordance with specification.
- BytesToClear = BufferSize - 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
- ArmTrngLibConstructor (
- VOID
- )
- {
- ARM_MONITOR_ARGS Parameters;
- RETURN_STATUS Status;
- UINT16 MajorRev;
- UINT16 MinorRev;
- GUID Guid;
- ZeroMem (&Parameters, sizeof (Parameters));
- Parameters.Arg0 = SMCCC_VERSION;
- ArmMonitorCall (&Parameters);
- Status = TrngStatusToReturnStatus ((INT32)Parameters.Arg0);
- if (RETURN_ERROR (Status)) {
- ASSERT_RETURN_ERROR (Status);
- goto ErrorHandler;
- }
- // Cf [1] s2.1.3 'Caller responsibilities',
- // SMCCC version must be greater or equal than 1.1
- if ((INT32)Parameters.Arg0 < 0x10001) {
- ASSERT_RETURN_ERROR (RETURN_UNSUPPORTED);
- goto ErrorHandler;
- }
- Status = GetArmTrngVersion (&MajorRev, &MinorRev);
- if (RETURN_ERROR (Status)) {
- ASSERT_RETURN_ERROR (Status);
- goto ErrorHandler;
- }
- // Check that the required features are present.
- Status = GetArmTrngFeatures (ARM_SMC_ID_TRNG_RND, NULL);
- if (RETURN_ERROR (Status)) {
- ASSERT_RETURN_ERROR (Status);
- goto ErrorHandler;
- }
- // Check if TRNG UUID is supported and if so trace the GUID.
- Status = GetArmTrngFeatures (ARM_SMC_ID_TRNG_GET_UUID, NULL);
- if (RETURN_ERROR (Status)) {
- ASSERT_RETURN_ERROR (Status);
- goto ErrorHandler;
- }
- DEBUG_CODE_BEGIN ();
- Status = GetArmTrngUuid (&Guid);
- if (RETURN_ERROR (Status)) {
- ASSERT_RETURN_ERROR (Status);
- goto ErrorHandler;
- }
- DEBUG ((
- DEBUG_INFO,
- "FW-TRNG: Version %d.%d, GUID {%g}\n",
- MajorRev,
- MinorRev,
- &Guid
- ));
- DEBUG_CODE_END ();
- return RETURN_SUCCESS;
- ErrorHandler:
- DEBUG ((DEBUG_ERROR, "ArmTrngLib could not be correctly initialized.\n"));
- return RETURN_SUCCESS;
- }
|