diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c')
-rw-r--r-- | src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c new file mode 100644 index 00000000..8f3fdaa5 --- /dev/null +++ b/src/VBox/Devices/EFI/Firmware/DynamicTablesPkg/Library/Common/TableHelperLib/TableHelper.c @@ -0,0 +1,343 @@ +/** @file + Table Helper + + Copyright (c) 2017 - 2021, Arm Limited. All rights reserved.<BR> + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include <Protocol/AcpiTable.h> +#include <Library/BaseLib.h> +#include <Library/DebugLib.h> +#include <Library/BaseMemoryLib.h> + +// Module specific include files. +#include <AcpiTableGenerator.h> +#include <ConfigurationManagerObject.h> +#include <Library/TableHelperLib.h> +#include <Protocol/ConfigurationManagerProtocol.h> + +/** The GetCgfMgrInfo function gets the CM_STD_OBJ_CONFIGURATION_MANAGER_INFO + object from the Configuration Manager. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager protocol + interface. + @param [out] CfgMfrInfo Pointer to the Configuration Manager Info + object structure. + + @retval EFI_SUCCESS The object is returned. + @retval EFI_INVALID_PARAMETER The Object ID is invalid. + @retval EFI_NOT_FOUND The requested Object is not found. + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration + Manager is less than the Object size. +**/ +EFI_STATUS +EFIAPI +GetCgfMgrInfo ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + OUT CM_STD_OBJ_CONFIGURATION_MANAGER_INFO ** CfgMfrInfo + ) +{ + EFI_STATUS Status; + CM_OBJ_DESCRIPTOR CmObjectDesc; + + ASSERT (CfgMgrProtocol != NULL); + ASSERT (CfgMfrInfo != NULL); + + *CfgMfrInfo = NULL; + Status = CfgMgrProtocol->GetObject ( + CfgMgrProtocol, + CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo), + CM_NULL_TOKEN, + &CmObjectDesc + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to Get Configuration Manager Info. Status = %r\n", + Status + )); + return Status; + } + + if (CmObjectDesc.ObjectId != CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: EStdObjCfgMgrInfo: Invalid ObjectId = 0x%x, expected Id = 0x%x\n", + CmObjectDesc.ObjectId, + CREATE_CM_STD_OBJECT_ID (EStdObjCfgMgrInfo) + )); + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + if (CmObjectDesc.Size < + (sizeof (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO) * CmObjectDesc.Count)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: EStdObjCfgMgrInfo: Buffer too small, size = 0x%x\n", + CmObjectDesc.Size + )); + ASSERT (FALSE); + return EFI_BAD_BUFFER_SIZE; + } + + *CfgMfrInfo = (CM_STD_OBJ_CONFIGURATION_MANAGER_INFO*)CmObjectDesc.Data; + return Status; +} + +/** The AddAcpiHeader function updates the ACPI header structure pointed by + the AcpiHeader. It utilizes the ACPI table Generator and the Configuration + Manager protocol to obtain any information required for constructing the + header. + + @param [in] CfgMgrProtocol Pointer to the Configuration Manager + protocol interface. + @param [in] Generator Pointer to the ACPI table Generator. + @param [in,out] AcpiHeader Pointer to the ACPI table header to be + updated. + @param [in] AcpiTableInfo Pointer to the ACPI table info structure. + @param [in] Length Length of the ACPI table. + + @retval EFI_SUCCESS The ACPI table is updated successfully. + @retval EFI_INVALID_PARAMETER A parameter is invalid. + @retval EFI_NOT_FOUND The required object information is not found. + @retval EFI_BAD_BUFFER_SIZE The size returned by the Configuration + Manager is less than the Object size for the + requested object. +**/ +EFI_STATUS +EFIAPI +AddAcpiHeader ( + IN CONST EDKII_CONFIGURATION_MANAGER_PROTOCOL * CONST CfgMgrProtocol, + IN CONST ACPI_TABLE_GENERATOR * CONST Generator, + IN OUT EFI_ACPI_DESCRIPTION_HEADER * CONST AcpiHeader, + IN CONST CM_STD_OBJ_ACPI_TABLE_INFO * CONST AcpiTableInfo, + IN CONST UINT32 Length + ) +{ + EFI_STATUS Status; + CM_STD_OBJ_CONFIGURATION_MANAGER_INFO * CfgMfrInfo; + + ASSERT (CfgMgrProtocol != NULL); + ASSERT (Generator != NULL); + ASSERT (AcpiHeader != NULL); + ASSERT (Length >= sizeof (EFI_ACPI_DESCRIPTION_HEADER)); + + if ((CfgMgrProtocol == NULL) || + (Generator == NULL) || + (AcpiHeader == NULL) || + (Length < sizeof (EFI_ACPI_DESCRIPTION_HEADER)) + ) { + return EFI_INVALID_PARAMETER; + } + + Status = GetCgfMgrInfo (CfgMgrProtocol, &CfgMfrInfo); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: Failed to get Configuration Manager info. Status = %r\n", + Status + )); + goto error_handler; + } + + // UINT32 Signature + AcpiHeader->Signature = Generator->AcpiTableSignature; + // UINT32 Length + AcpiHeader->Length = Length; + // UINT8 Revision + AcpiHeader->Revision = AcpiTableInfo->AcpiTableRevision; + // UINT8 Checksum + AcpiHeader->Checksum = 0; + + // UINT8 OemId[6] + CopyMem (AcpiHeader->OemId, CfgMfrInfo->OemId, sizeof (AcpiHeader->OemId)); + + // UINT64 OemTableId + if (AcpiTableInfo->OemTableId != 0) { + AcpiHeader->OemTableId = AcpiTableInfo->OemTableId; + } else { + AcpiHeader->OemTableId = SIGNATURE_32 ( + CfgMfrInfo->OemId[0], + CfgMfrInfo->OemId[1], + CfgMfrInfo->OemId[2], + CfgMfrInfo->OemId[3] + ) | + ((UINT64)Generator->AcpiTableSignature << 32); + } + + // UINT32 OemRevision + if (AcpiTableInfo->OemRevision != 0) { + AcpiHeader->OemRevision = AcpiTableInfo->OemRevision; + } else { + AcpiHeader->OemRevision = CfgMfrInfo->Revision; + } + + // UINT32 CreatorId + AcpiHeader->CreatorId = Generator->CreatorId; + // UINT32 CreatorRevision + AcpiHeader->CreatorRevision = Generator->CreatorRevision; + +error_handler: + return Status; +} + +/** + Test and report if a duplicate entry exists in the given array of comparable + elements. + + @param [in] Array Array of elements to test for duplicates. + @param [in] Count Number of elements in Array. + @param [in] ElementSize Size of an element in bytes + @param [in] EqualTestFunction The function to call to check if any two + elements are equal. + + @retval TRUE A duplicate element was found or one of + the input arguments is invalid. + @retval FALSE Every element in Array is unique. +**/ +BOOLEAN +EFIAPI +FindDuplicateValue ( + IN CONST VOID * Array, + IN CONST UINTN Count, + IN CONST UINTN ElementSize, + IN PFN_IS_EQUAL EqualTestFunction + ) +{ + UINTN Index1; + UINTN Index2; + UINT8 * Element1; + UINT8 * Element2; + + if (Array == NULL) { + DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: Array is NULL.\n")); + return TRUE; + } + + if (ElementSize == 0) { + DEBUG ((DEBUG_ERROR, "ERROR: FindDuplicateValues: ElementSize is 0.\n")); + return TRUE; + } + + if (EqualTestFunction == NULL) { + DEBUG (( + DEBUG_ERROR, + "ERROR: FindDuplicateValues: EqualTestFunction is NULL.\n" + )); + return TRUE; + } + + if (Count < 2) { + return FALSE; + } + + for (Index1 = 0; Index1 < Count - 1; Index1++) { + for (Index2 = Index1 + 1; Index2 < Count; Index2++) { + Element1 = (UINT8*)Array + (Index1 * ElementSize); + Element2 = (UINT8*)Array + (Index2 * ElementSize); + + if (EqualTestFunction (Element1, Element2, Index1, Index2)) { + return TRUE; + } + } + } + return FALSE; +} + +/** Convert a hex number to its ASCII code. + + @param [in] x Hex number to convert. + Must be 0 <= x < 16. + + @return The ASCII code corresponding to x. +**/ +UINT8 +EFIAPI +AsciiFromHex ( + IN UINT8 x + ) +{ + if (x < 10) { + return (UINT8)(x + '0'); + } + + if (x < 16) { + return (UINT8)(x - 10 + 'A'); + } + + ASSERT (FALSE); + return (UINT8)0; +} + +/** Check if a HID is a valid PNP ID. + + @param [in] Hid The Hid to validate. + + @retval TRUE The Hid is a valid PNP ID. + @retval FALSE The Hid is not a valid PNP ID. +**/ +BOOLEAN +IsValidPnpId ( + IN CONST CHAR8 * Hid + ) +{ + UINTN Index; + + if (AsciiStrLen (Hid) != 7) { + return FALSE; + } + + // A valid PNP ID must be of the form "AAA####" + // where A is an uppercase letter and # is a hex digit. + for (Index = 0; Index < 3; Index++) { + if (!IS_UPPER_CHAR (Hid[Index])) { + return FALSE; + } + } + + for (Index = 3; Index < 7; Index++) { + if (!IS_UPPER_HEX (Hid[Index])) { + return FALSE; + } + } + + return TRUE; +} + +/** Check if a HID is a valid ACPI ID. + + @param [in] Hid The Hid to validate. + + @retval TRUE The Hid is a valid ACPI ID. + @retval FALSE The Hid is not a valid ACPI ID. +**/ +BOOLEAN +IsValidAcpiId ( + IN CONST CHAR8 * Hid + ) +{ + UINTN Index; + + if (AsciiStrLen (Hid) != 8) { + return FALSE; + } + + // A valid ACPI ID must be of the form "NNNN####" + // where N is an uppercase letter or a digit ('0'-'9') + // and # is a hex digit. + for (Index = 0; Index < 4; Index++) { + if (!(IS_UPPER_CHAR (Hid[Index]) || IS_DIGIT (Hid[Index]))) { + return FALSE; + } + } + + for (Index = 4; Index < 8; Index++) { + if (!IS_UPPER_HEX (Hid[Index])) { + return FALSE; + } + } + + return TRUE; +} |