From e841099600749c29edaf48236909529d8e629869 Mon Sep 17 00:00:00 2001 From: Prachotan Reddy Bathi Date: Thu, 30 Jan 2025 15:52:29 -0600 Subject: [PATCH] ArmPkg/ArmTransferListLib: Add utility functions Added functionality TransferList Library TransferListVerifyChecksum - Verify TransferList CheckSum TransferListCheckHeader - Check if TransferList header is valid, return suitable opcodes validating the header TransferListFindEntry - Find a specific entry on the TransferList using the TagId TransferListDump - Dump the contents of the TransferList header and the entry headers Signed-off-by: Prachotan Reddy Bathi --- .../IndustryStandard/ArmTransferList.h | 12 +- ArmPkg/Include/Library/ArmTransferListLib.h | 58 ++++++- .../ArmTransferListLib/ArmTransferListLib.c | 156 +++++++++++++++++- 3 files changed, 222 insertions(+), 4 deletions(-) diff --git a/ArmPkg/Include/IndustryStandard/ArmTransferList.h b/ArmPkg/Include/IndustryStandard/ArmTransferList.h index 455c7d809d..303384622f 100644 --- a/ArmPkg/Include/IndustryStandard/ArmTransferList.h +++ b/ArmPkg/Include/IndustryStandard/ArmTransferList.h @@ -2,7 +2,7 @@ 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.
+ Copyright (c) 2025, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): @@ -73,6 +73,16 @@ */ #define TRANSFER_LIST_FL_HAS_CHECKSUM BIT0 +/* + * Operation codes indicating the validity of the Transfer List. + */ +typedef enum { + TRANSFER_LIST_OPS_INVALID, /* invalid for any operation */ + TRANSFER_LIST_OPS_ALL, /* valid for all operations */ + TRANSFER_LIST_OPS_RO, /* valid for read only */ + TRANSFER_LIST_OPS_CUSTOM, /* abort or switch to special code to interpret */ +} TRANSFER_LIST_OPS; + /* * Transfer list starts with the following header. * Transfer entries followed after the following header. diff --git a/ArmPkg/Include/Library/ArmTransferListLib.h b/ArmPkg/Include/Library/ArmTransferListLib.h index 96a12275b8..fb0c69972e 100644 --- a/ArmPkg/Include/Library/ArmTransferListLib.h +++ b/ArmPkg/Include/Library/ArmTransferListLib.h @@ -2,7 +2,7 @@ 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.
+ Copyright (c) 2022 - 2025, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): @@ -21,7 +21,7 @@ /** Return the first Transfer Entry Node in the Transfer List. - @param [in] TransferListHeader TransferListHeader + @param [in] TransferListHeader Pointer to the Transfer List Header. @return Pointer to the Transfer Entry Node if successful otherwise NULL @@ -103,4 +103,58 @@ TransferListGetEntryData ( IN TRANSFER_ENTRY_HEADER *TransferEntry ); +/** + Dump the transfer list to the debug output. + + @param [in] TransferListHeader Pointer to the Transfer List Header + +**/ +VOID +EFIAPI +TransferListDump ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ); + +/** + Verify the checksum of the transfer list. + + @param [in] TransferListHeader Pointer to the Transfer List Header + + @retval FALSE Invalid Checksum + @retval TRUE Valid Checksum +**/ +BOOLEAN +EFIAPI +TransferListVerifyChecksum ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ); + +/** + Check the header of the Transfer List. + + @param [in] TransferListHeader Pointer to the Transfer List Header + + @return TRANSFER_LIST_OPS code indicating the validity of the Transfer List +**/ +TRANSFER_LIST_OPS +EFIAPI +TransferListCheckHeader ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ); + +/** + Find a Transfer Entry Node in the Transfer List matched with the given tag-id. + + @param [in] TransferListHeader Pointer to the Transfer List Header + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TransferListFindEntry ( + IN TRANSFER_LIST_HEADER *TransferListHeader, + IN UINT16 TagId + ); + #endif // ARM_TRANSFER_LIST_LIB_ diff --git a/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c index 7cd203e486..af8170e67f 100644 --- a/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c +++ b/ArmPkg/Library/ArmTransferListLib/ArmTransferListLib.c @@ -2,7 +2,7 @@ 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.
+ Copyright (c) 2022 - 2025, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): @@ -14,6 +14,90 @@ #include #include +/** + This function verifies the checksum of the Transfer List. + + @param [in] TransferListHeader Pointer to the Transfer List Header + + @retval FALSE Invalid Checksum + @retval TRUE Valid Checksum + +**/ +BOOLEAN +EFIAPI +TransferListVerifyChecksum ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ) +{ + if (TransferListHeader == NULL) { + return FALSE; + } + + if ((TransferListHeader->Flags & TRANSFER_LIST_FL_HAS_CHECKSUM) == 0) { + return TRUE; + } + + return (CalculateSum8 ((UINT8 *)TransferListHeader, TransferListHeader->UsedSize) == 0); +} + +/** + This function checks the header of the Transfer List. + + @param [in] TransferListHeader Pointer to the Transfer List Header + + @return TRANSFER_LIST_OPS code indicating the validity of the Transfer List + +**/ +TRANSFER_LIST_OPS +EFIAPI +TransferListCheckHeader ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ) +{ + if (TransferListHeader == NULL) { + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListHeader->Signature != TRANSFER_LIST_SIGNATURE_64) { + DEBUG ((DEBUG_ERROR, "Bad transfer list signature 0x%x\n", TransferListHeader->Signature)); + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListHeader->TotalSize == 0) { + DEBUG ((DEBUG_ERROR, "Bad transfer list total size 0x%x\n", TransferListHeader->TotalSize)); + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListHeader->UsedSize > TransferListHeader->TotalSize) { + DEBUG ((DEBUG_ERROR, "Bad transfer list used size 0x%x\n", TransferListHeader->UsedSize)); + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListHeader->HeaderSize != sizeof (TRANSFER_LIST_HEADER)) { + DEBUG ((DEBUG_ERROR, "Bad transfer list header size 0x%x\n", TransferListHeader->HeaderSize)); + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListVerifyChecksum (TransferListHeader) == FALSE) { + DEBUG ((DEBUG_ERROR, "Bad transfer list checksum 0x%x\n", TransferListHeader->Checksum)); + return TRANSFER_LIST_OPS_INVALID; + } + + if (TransferListHeader->Version == 0) { + DEBUG ((DEBUG_ERROR, "Transfer list version is invalid\n")); + return TRANSFER_LIST_OPS_INVALID; + } else if (TransferListHeader->Version == ARM_FW_HANDOFF_PROTOCOL_VERSION) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Transfer list version is valid for all operations\n")); + return TRANSFER_LIST_OPS_ALL; + } else if (TransferListHeader->Version > ARM_FW_HANDOFF_PROTOCOL_VERSION) { + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Transfer list version is valid for read-only\n")); + return TRANSFER_LIST_OPS_RO; + } + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Old or custom transfer list version is detected\n")); + return TRANSFER_LIST_OPS_CUSTOM; +} + /** Return the first Transfer Entry Node in the Transfer List. @@ -165,3 +249,73 @@ TransferListGetEntryData ( return (VOID *)((UINTN)TransferEntry + TransferEntry->HeaderSize); } + +/** + Find a Transfer Entry Node in the Transfer List matched with the given tag-id. + + @param [in] TransferListHeader Pointer to the Transfer List Header + @param [in] TagId Tag id + + @return Pointer to the Transfer Entry Node if successful otherwise NULL +**/ +TRANSFER_ENTRY_HEADER * +EFIAPI +TransferListFindEntry ( + IN TRANSFER_LIST_HEADER *TransferListHeader, + IN UINT16 TagId + ) +{ + TRANSFER_ENTRY_HEADER *Entry = NULL; + + do { + Entry = TransferListGetNextEntry (TransferListHeader, Entry); + } while ((Entry != NULL) && (Entry->TagId != TagId)); + + return Entry; +} + +/** + Dump the transfer list to the debug output. + + @param [in] TransferListHeader Pointer to the Transfer List Header + +**/ +VOID +EFIAPI +TransferListDump ( + IN TRANSFER_LIST_HEADER *TransferListHeader + ) +{ + TRANSFER_ENTRY_HEADER *Entry; + UINTN Idx; + + Entry = NULL; + Idx = 0; + + if (TransferListHeader == NULL) { + return; + } + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Dump transfer list:\n")); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "signature 0x%x\n", TransferListHeader->Signature)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "checksum 0x%x\n", TransferListHeader->Checksum)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "version 0x%x\n", TransferListHeader->Version)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "hdr_size 0x%x\n", TransferListHeader->HeaderSize)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "alignment 0x%x\n", TransferListHeader->Alignment)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "used_size 0x%x\n", TransferListHeader->UsedSize)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "total_size 0x%x\n", TransferListHeader->TotalSize)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "flags 0x%x\n", TransferListHeader->Flags)); + + while (TRUE) { + Entry = TransferListGetNextEntry (TransferListHeader, Entry); + if (Entry == NULL) { + break; + } + + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Entry %d:\n", Idx++)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "tag_id 0x%x\n", Entry->TagId)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "hdr_size 0x%x\n", Entry->HeaderSize)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "data_size 0x%x\n", Entry->DataSize)); + DEBUG ((DEBUG_INFO | DEBUG_LOAD, "data_addr 0x%lx\n", (UINTN)TransferListGetEntryData (Entry))); + } +}