From fbeab84945b0100310713a584f8fecbf4621c11e Mon Sep 17 00:00:00 2001 From: "levi.yun" Date: Wed, 21 Feb 2024 16:09:38 +0000 Subject: [PATCH] ArmPkg/Library: Introduce ArmTransferListLib ArmTransferList is used to pass boot information according to firmware handoff protocol specification [0]. When initializing StandaloneMm, it gets boot information from the PHIT HOB in the TransferList. [0] https://github.com/FirmwareHandoff/firmware_handoff Signed-off-by: Levi Yun --- ArmPkg/ArmPkg.dec | 5 + ArmPkg/ArmPkg.dsc | 2 + .../IndustryStandard/ArmTransferList.h | 130 ++++++++++++++ ArmPkg/Include/Library/ArmTransferListLib.h | 109 +++++++++++ .../ArmTransferListLib/ArmTransferListLib.c | 170 ++++++++++++++++++ .../ArmTransferListLib/ArmTransferListLib.inf | 27 +++ 6 files changed, 443 insertions(+) create mode 100644 ArmPkg/Include/IndustryStandard/ArmTransferList.h create mode 100644 ArmPkg/Include/Library/ArmTransferListLib.h create mode 100644 ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c create mode 100644 ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 49cbffa5fc..112187fc46 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -93,6 +93,11 @@ # StandaloneMmMmuLib|Include/Library/StandaloneMmMmuLib.h + ## @libraryclass Provides an interface for a Arm Transfer List. + # + ArmTransferListLib|Include/Library/ArmTransferListLib.h + + [Guids.common] gArmTokenSpaceGuid = { 0xBB11ECFE, 0x820F, 0x4968, { 0xBB, 0xA6, 0xF7, 0x6A, 0xFE, 0x30, 0x25, 0x96 } } diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index d5a29f31ea..85d3f49c18 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -86,6 +86,7 @@ ArmLib|ArmPkg/Library/ArmLib/ArmBaseLib.inf ArmMmuLib|ArmPkg/Library/ArmMmuLib/ArmMmuBaseLib.inf + ArmTransferListLib|ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf ArmMtlLib|ArmPkg/Library/ArmMtlNullLib/ArmMtlNullLib.inf @@ -129,6 +130,7 @@ ArmPkg/Library/ArmSmcLibNull/ArmSmcLibNull.inf ArmPkg/Library/ArmSvcLib/ArmSvcLib.inf ArmPkg/Library/OpteeLib/OpteeLib.inf + ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf ArmPkg/Filesystem/SemihostFs/SemihostFs.inf diff --git a/ArmPkg/Include/IndustryStandard/ArmTransferList.h b/ArmPkg/Include/IndustryStandard/ArmTransferList.h new file mode 100644 index 0000000000..455c7d809d --- /dev/null +++ b/ArmPkg/Include/IndustryStandard/ArmTransferList.h @@ -0,0 +1,130 @@ +/** @file + Header file defining a Transfer List and Transfer Entry as specified by the + A-profile Firmware Handoff Protocol specification. + + Copyright (c) 2024, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - https://github.com/FirmwareHandoff/firmware_handoff + + @par Glossary: + - TL - Transfer list + - TE - Transfer entry + - HOB - Hand off block. +**/ + +#ifndef ARM_TRANSFER_LIST_ +#define ARM_TRANSFER_LIST_ + +#include +#include + +#define ARM_FW_HANDOFF_PROTOCOL_VERSION 1 + +#define TRANSFER_LIST_ALIGNMENT 8 // 8 byte alignment +#define TRANSFER_LIST_SIGNATURE_64 (0x4a0fb10b) +#define TRANSFER_LIST_SIGNATURE_32 (0xfb10b) + +/* + * For register convention, please see below: + * https://github.com/FirmwareHandoff/firmware_handoff/blob/main/source/register_conventions.rst + */ +#define REGISTER_CONVENTION_VERSION_SHIFT_64 (32) +#define TRANSFER_LIST_SIGNATURE_MASK_64 \ + ((1ULL << REGISTER_CONVENTION_VERSION_SHIFT_64) - 1) + +#define REGISTER_CONVENTION_VERSION_SHIFT_32 (24) +#define TRANSFER_LIST_SIGNATURE_MASK_32 \ + ((1UL << REGISTER_CONVENTION_VERSION_SHIFT_32) - 1) + +#define REGISTER_CONVENTION_VERSION_MASK (0xff) +#define REGISTER_CONVENTION_VERSION (1) + +#define CREATE_TRANSFER_LIST_HANDOFF_X1_VALUE(version) \ + ((TRANSFER_LIST_SIGNATURE & \ + (REGISTER_CONVENTION_VERSION_SHIFT_64 - 1)) | \ + ((version) << REGISTER_CONVENTION_VERSION_SHIFT_64)) + +#define CREATE_TRANSFER_LIST_HANDOFF_R1_VALUE(version) \ + ((TRANSFER_LIST_SIGNATURE & \ + (REGISTER_CONVENTION_VERSION_SHIFT_32 - 1)) | \ + ((version) << REGISTER_CONVENTION_VERSION_SHIFT_32)) + +/* + * tag id identifies contents of transfer entry. + * below is the standard tag id used in transfer entry. + * please see: + * https://github.com/FirmwareHandoff/firmware_handoff/blob/main/source/transfer_list.rst + * "Standard transfer entries" Section. + */ +#define TRANSFER_ENTRY_TAG_ID_EMPTY 0 +#define TRANSFER_ENTRY_TAG_ID_FDT 1 +#define TRANSFER_ENTRY_TAG_ID_HOB 2 +#define TRANSFER_ENTRY_TAG_ID_HOB_LIST 3 +#define TRANSFER_ENTRY_TAG_ID_ACPI_TABLE_AGGREGATE 4 +#define TRANSFER_ENTRY_TAG_ID_TPM_EVENT_LOG 5 +#define TRANSFER_ENTRY_TAG_ID_TPM_CRB_BASE 6 + +/* + * Flag value in TransferListHeader->Flags. + * please see: + * https://github.com/FirmwareHandoff/firmware_handoff/blob/main/source/transfer_list.rst + */ +#define TRANSFER_LIST_FL_HAS_CHECKSUM BIT0 + +/* + * Transfer list starts with the following header. + * Transfer entries followed after the following header. + */ +typedef struct TransferListHeader { + /// Signature, must be TRANSFER_LIST_SIGNATURE + UINT32 Signature; + + /// Checksum + UINT8 Checksum; + + /// Version of the TL Header. + UINT8 Version; + + /// The size of this TL header in bytes. + UINT8 HeaderSize; + + /// The maximum alignment required by any transfer entry in the transfer list, + /// specified as a power of two. + UINT8 Alignment; + + /// The number of bytes occupied by the TL. This field + /// accounts for the size of the TL header plus the size + /// of all the entries contained in the TL. + UINT32 UsedSize; + + /// The number of bytes occupied by the entire TL, + /// including any spare space at the end after UsedSize. + UINT32 TotalSize; + + /// Flags word. + UINT32 Flags; + + /// Reserved. + UINT32 Reserved; +} TRANSFER_LIST_HEADER; + +/* + * Transfer entry in transfer list starts with the following header. + */ +typedef struct TransferEntryHeader { + /// The entry type identifier. + UINT16 TagId; + + /// Reserved. + UINT8 Reserved0; + + /// The size of this entry header in bytes. + UINT8 HeaderSize; + + /// The size of the data content in bytes. + UINT32 DataSize; +} TRANSFER_ENTRY_HEADER; + +#endif // ARM_TRANSFER_LIST_ diff --git a/ArmPkg/Include/Library/ArmTransferListLib.h b/ArmPkg/Include/Library/ArmTransferListLib.h new file mode 100644 index 0000000000..033821a181 --- /dev/null +++ b/ArmPkg/Include/Library/ArmTransferListLib.h @@ -0,0 +1,109 @@ +/** @file + Library that implements the helper functions to parse and pack a Transfer + List as specified by the A-profile Firmware Handoff Specification. + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - https://github.com/FirmwareHandoff/firmware_handoff + + @par Glossary: + - TL - Transfer list + - TE - Transfer entry + - HOB - Hand off block. +**/ + +#ifndef ARM_TRANSFER_LIST_LIB_ +#define ARM_TRANSFER_LIST_LIB_ + +#include +#include +#include +#include +#include + +/** + Return the first Transfer Entry Node in the Transfer List. + + @param [in] Tlh TransferListHeader + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlGetFirstEntry ( + IN TRANSFER_LIST_HEADER *Tlh + ); + +/** + Return the next Transfer Entry Node in the Transfer List from + last Transfer Entry Node. + + @param [in] Tlh TransferListHeader + @param [in] CurrentTe Pointer to the Current Transfer Entry. + If this is NULL, the first Transfer Entry is returned. + + @return Pointer to the next Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlGetNextEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN TRANSFER_ENTRY_HEADER *CurrentTe + ); + +/** + Return the first Transfer Entry Node in the Transfer List + matched with given tag-id. + + @param [in] Tlh TransferListHeader + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlFindFirstEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN UINT16 TagId + ); + +/** + Return the Next Transfer Entry Node in the Transfer List + matched with given tag-id from last Transfer Entry Node. + + @param [in] Tlh TransferListHeader + @param [in] CurrentTe Pointer to the Current Transfer Entry. + If this is NULL, the first Transfer Entry is returned. + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlFindNextEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN TRANSFER_ENTRY_HEADER *CurrentTe, + IN UINT16 TagId + ); + +/** + Return the data in Transfer Entry. + + @param [in] Te TransferEntryHeader + + @return Pointer to the Data of Transfer Entry Node if successful otherwise NULL + +**/ +VOID * +EFIAPI +TlGetEntryData ( + IN TRANSFER_ENTRY_HEADER *Te + ); + +#endif // ARM_TRANSFER_LIST_LIB_ diff --git a/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c new file mode 100644 index 0000000000..43fbf65090 --- /dev/null +++ b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c @@ -0,0 +1,170 @@ +/** @file + Library that implements the helper functions to parse and pack a Transfer + List as specified by the A-profile Firmware Handoff Specification. + + Copyright (c) 2022, Arm Limited. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Reference(s): + - https://github.com/FirmwareHandoff/firmware_handoff + + @par Glossary: + - TL - Transfer list + - TE - Transfer entry + - Tlh - Transfer list header +**/ + +#include +#include +#include +#include + +/** + Return the first Transfer Entry Node in the Transfer List. + + @param [in] Tlh TransferListHeader + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlGetFirstEntry ( + IN TRANSFER_LIST_HEADER *Tlh + ) +{ + return TlGetNextEntry (Tlh, NULL); +} + +/** + Return the next Transfer Entry Node in the Transfer List from + last Transfer Entry Node. + + @param [in] Tlh TransferListHeader + @param [in] CurrentTe Pointer to the Current Transfer Entry. + If this is NULL, the first Transfer Entry is returned. + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlGetNextEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN TRANSFER_ENTRY_HEADER *CurrentTe + ) +{ + TRANSFER_ENTRY_HEADER *Te; + UINTN CurrentAddr; + UINTN EndAddr; + + if (Tlh == NULL) { + return NULL; + } + + EndAddr = (UINTN)Tlh + Tlh->UsedSize; + + if (CurrentTe != NULL) { + CurrentAddr = (UINTN)CurrentTe + CurrentTe->HeaderSize + CurrentTe->DataSize; + } else { + CurrentAddr = (UINTN)Tlh + Tlh->HeaderSize; + } + + CurrentAddr = ALIGN_VALUE (CurrentAddr, (1 << Tlh->Alignment)); + + Te = (TRANSFER_ENTRY_HEADER *)CurrentAddr; + + if (((CurrentAddr + sizeof (TRANSFER_LIST_HEADER)) < CurrentAddr) || + ((CurrentAddr + sizeof (TRANSFER_ENTRY_HEADER)) > EndAddr) || + ((CurrentAddr + Te->HeaderSize + Te->DataSize) < CurrentAddr) || + ((CurrentAddr + Te->HeaderSize + Te->DataSize) > EndAddr)) + { + return NULL; + } + + return Te; +} + +/** + Return the first Transfer Entry Node in the Transfer List + matched with given tag-id. + + @param [in] Tlh TransferListHeader + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlFindFirstEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN UINT16 TagId + ) +{ + TRANSFER_ENTRY_HEADER *Te; + + Te = TlGetFirstEntry (Tlh); + + while ((Te != NULL) && ((Te->TagId != TagId) || Te->Reserved0 != 0)) { + Te = TlGetNextEntry (Tlh, Te); + } + + return Te; +} + +/** + Return the Next Transfer Entry Node in the Transfer List + matched with given tag-id from last Transfer Entry Node. + + @param [in] Tlh TransferListHeader + @param [in] CurrentTe Pointer to the Current Transfer Entry. + If this is NULL, the first Transfer Entry is returned. + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL + +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TlFindNextEntry ( + IN TRANSFER_LIST_HEADER *Tlh, + IN TRANSFER_ENTRY_HEADER *CurrentTe, + IN UINT16 TagId + ) +{ + TRANSFER_ENTRY_HEADER *Te; + + if (CurrentTe == NULL) { + return TlFindFirstEntry (Tlh, TagId); + } else { + Te = TlGetNextEntry (Tlh, CurrentTe); + } + + while ((Te != NULL) && ((Te->TagId != TagId) || Te->Reserved0 != 0)) { + Te = TlGetNextEntry (Tlh, Te); + } + + return Te; +} + +/** + Return the data in Transfer Entry. + + @param [in] Te TransferEntryHeader + + @return Pointer to the Data of Transfer Entry Node if successful otherwise NULL + +**/ +VOID * +EFIAPI +TlGetEntryData ( + IN TRANSFER_ENTRY_HEADER *Te + ) +{ + if ((Te == NULL) || (Te->DataSize == 0)) { + return NULL; + } + + return (VOID *)((UINTN)Te + Te->HeaderSize); +} diff --git a/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf new file mode 100644 index 0000000000..b1eeb8a1f7 --- /dev/null +++ b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.inf @@ -0,0 +1,27 @@ +## @file +# Library that implements the helper functions to parse and pack a +# Transfer List according to the A-profile Firmware Handoff Specification. +# +# Copyright (c) 2024, Arm Limited. All rights reserved.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x0001001C + BASE_NAME = ArmTransferListLib + FILE_GUID = 3BD1750F-FB52-4AA8-B91E-D00EFA5D7D29 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = ArmTransferListLib + +[Sources] + ArmTransferListLib.c + +[Packages] + ArmPkg/ArmPkg.dec + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib