From ca04956e1b7790101a4bd774de60642acc15d695 Mon Sep 17 00:00:00 2001 From: Pierre Gondois Date: Tue, 4 Aug 2020 09:08:47 +0100 Subject: DynamicTablesPkg: AML and ASL string helper Dynamic AML requires encoding/decoding and conversion of AML and ASL strings. A collection of helper functions have been provided for internal use in the AmlLib Library. Signed-off-by: Pierre Gondois Signed-off-by: Sami Mujawar Reviewed-by: Alexei Fedorov --- .../Library/Common/AmlLib/String/AmlString.c | 1022 ++++++++++++++++++++ .../Library/Common/AmlLib/String/AmlString.h | 401 ++++++++ 2 files changed, 1423 insertions(+) create mode 100644 DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.c create mode 100644 DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.h (limited to 'DynamicTablesPkg') diff --git a/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.c b/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.c new file mode 100644 index 0000000000..e9d36f4b6c --- /dev/null +++ b/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.c @@ -0,0 +1,1022 @@ +/** @file + AML String. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include + +#include +#include + +/** Check NameString/path information is valid. + + Root, ParentPrefix and SegCount cannot be 0 at the same time. + This function works for ASL and AML name strings. + + @param [in] Root Number of root char. + Must be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Must be [0-255]. + @param [in] SegCount Number of NameSeg (s). + Must be [0-255]. + + @retval TRUE id the input information is in the right boundaries. + FALSE otherwise. +**/ +BOOLEAN +EFIAPI +AmlIsNameString ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ) +{ + if (((Root == 0) || (Root == 1)) && + (ParentPrefix <= MAX_UINT8) && + (!((ParentPrefix != 0) && (Root != 0))) && + (SegCount <= MAX_UINT8) && + ((SegCount + Root + ParentPrefix) != 0)) { + return TRUE; + } + return FALSE; +} + +/** Copy bytes from SrcBuffer to DstBuffer and convert to upper case. + Don't copy more than MaxDstBufferSize bytes. + + @param [out] DstBuffer Destination buffer. + @param [in] MaxDstBufferSize Maximum size of DstBuffer. + Must be non-zero. + @param [in] SrcBuffer Source buffer. + @param [in] Count Count of bytes to copy from SrcBuffer. + Return success if 0. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlUpperCaseMemCpyS ( + OUT CHAR8 * DstBuffer, + IN UINT32 MaxDstBufferSize, + IN CONST CHAR8 * SrcBuffer, + IN UINT32 Count + ) +{ + UINT32 Index; + + if ((DstBuffer == NULL) || + (SrcBuffer == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + if (Count == 0) { + return EFI_SUCCESS; + } + + if (Count > MaxDstBufferSize) { + Count = MaxDstBufferSize; + } + + for (Index = 0; Index < Count; Index++) { + if ((SrcBuffer[Index] >= 'a') && (SrcBuffer[Index] <= 'z')) { + DstBuffer[Index] = (CHAR8)((UINT8)SrcBuffer[Index] - ('a' - 'A')); + } else { + DstBuffer[Index] = SrcBuffer[Index]; + } + } + + return EFI_SUCCESS; +} + +/** Check whether Buffer is a root path ('\'). + + This function works for both ASL and AML pathnames. + Buffer must be at least 2 bytes long. + + @param [in] Buffer An ASL/AML path. + + @retval TRUE Buffer is a root path + @retval FALSE Buffer is not a root path. +**/ +BOOLEAN +EFIAPI +AmlIsRootPath ( + IN CONST CHAR8 * Buffer + ) +{ + if (Buffer == NULL) { + return FALSE; + } + + if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == '\0')) { + return TRUE; + } else { + return FALSE; + } +} + +/** Check whether Ch is an ASL/AML LeadName. + + This function works for both ASL and AML pathnames. + + ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms": + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + + ACPI 6.3 specification, s20.2.2. "Name Objects Encoding": + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + + @param [in] Ch The char to test. + + @retval TRUE Ch is an ASL/AML LeadName. + @retval FALSE Ch is not an ASL/AML LeadName. +**/ +BOOLEAN +EFIAPI +AmlIsLeadNameChar ( + IN CHAR8 Ch + ) +{ + if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z') || (Ch >= 'a' && Ch <= 'z')) { + return TRUE; + } else { + return FALSE; + } +} + +/** Check whether Ch is an ASL/AML NameChar. + + This function works for both ASL and AML pathnames. + + ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms": + NameChar := DigitChar | LeadNameChar + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + DigitChar := '0'-'9' + + ACPI 6.3 specification, s20.2.2. "Name Objects Encoding": + NameChar := DigitChar | LeadNameChar + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + DigitChar := '0'-'9' + + @param [in] Ch The char to test. + + @retval TRUE Ch is an ASL/AML NameChar. + @retval FALSE Ch is not an ASL/AML NameChar. +**/ +BOOLEAN +EFIAPI +AmlIsNameChar ( + IN CHAR8 Ch + ) +{ + if (AmlIsLeadNameChar (Ch) || (Ch >= '0' && Ch <= '9')) { + return TRUE; + } else { + return FALSE; + } +} + +/** Check whether AslBuffer is an ASL NameSeg. + + This function only works for ASL NameStrings/pathnames. + ASL NameStrings/pathnames are at most 4 chars long. + + @param [in] AslBuffer Pointer in an ASL NameString/pathname. + @param [out] Size Size of the NameSeg. + + @retval TRUE AslBuffer is an ASL NameSeg. + @retval FALSE AslBuffer is not an ASL NameSeg. +**/ +BOOLEAN +EFIAPI +AslIsNameSeg ( + IN CONST CHAR8 * AslBuffer, + OUT UINT32 * Size + ) +{ + UINT32 Index; + + if ((AslBuffer == NULL) || + (Size == NULL)) { + return FALSE; + } + + if (!AmlIsLeadNameChar (AslBuffer[0])) { + return FALSE; + } + + for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) { + if ((AslBuffer[Index] == '.') || + (AslBuffer[Index] == '\0')) { + *Size = Index; + return TRUE; + } else if (!AmlIsNameChar (AslBuffer[Index])) { + return FALSE; + } + } + + *Size = Index; + return TRUE; +} + +/** Check whether AmlBuffer is an AML NameSeg. + + This function only works for AML NameStrings/pathnames. + AML NameStrings/pathnames must be 4 chars long. + + @param [in] AmlBuffer Pointer in an AML NameString/pathname. + + @retval TRUE AmlBuffer is an AML NameSeg. + @retval FALSE AmlBuffer is not an AML NameSeg. +**/ +BOOLEAN +EFIAPI +AmlIsNameSeg ( + IN CONST CHAR8 * AmlBuffer + ) +{ + UINT32 Index; + + if (AmlBuffer == NULL) { + return FALSE; + } + + if (!AmlIsLeadNameChar (AmlBuffer[0])) { + return FALSE; + } + + for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) { + if (!AmlIsNameChar (AmlBuffer[Index])) { + return FALSE; + } + } + + return TRUE; +} + +/** Parse an ASL NameString/path. + + An ASL NameString/path must be NULL terminated. + Information found in the ASL NameString/path is returned via pointers: + Root, ParentPrefix, SegCount. + + @param [in] Buffer ASL NameString/path. + @param [out] Root Pointer holding the number of root char. + Can be 0 or 1. + @param [out] ParentPrefix Pointer holding the number of carets char ('^'). + Can be [0-255]. + @param [out] SegCount Pointer holding the number of NameSeg (s). + Can be [0-255]. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AslParseNameStringInfo ( + IN CONST CHAR8 * Buffer, + OUT UINT32 * Root, + OUT UINT32 * ParentPrefix, + OUT UINT32 * SegCount + ) +{ + UINT32 NameSegSize; + + if ((Buffer == NULL) || + (Root == NULL) || + (ParentPrefix == NULL) || + (SegCount == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + *Root = 0; + *ParentPrefix = 0; + *SegCount = 0; + + // Handle Root and ParentPrefix(s). + if (*Buffer == AML_ROOT_CHAR) { + *Root = 1; + Buffer++; + } else if (*Buffer == AML_PARENT_PREFIX_CHAR) { + do { + Buffer++; + (*ParentPrefix)++; + } while (*Buffer == AML_PARENT_PREFIX_CHAR); + } + + // Handle SegCount(s). + while (AslIsNameSeg (Buffer, &NameSegSize)) { + // Safety checks on NameSegSize. + if ((NameSegSize == 0) || (NameSegSize > AML_NAME_SEG_SIZE)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Increment the NameSeg count. + (*SegCount)++; + Buffer += NameSegSize; + + // Skip the '.' separator if present. + if (*Buffer == '.') { + Buffer++; + } + } // while + + // An ASL NameString/path must be NULL terminated. + if (*Buffer != '\0') { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + if (!AmlIsNameString (*Root, *ParentPrefix, *SegCount)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** Parse an AML NameString/path. + + It is possible to determine the size of an AML NameString/path just + by sight reading it. So no overflow can occur. + Information found in the AML NameString/path is returned via pointers: + Root, ParentPrefix, SegCount. + + @param [in] Buffer AML NameString/path. + @param [out] Root Pointer holding the number of root char. + Can be 0 or 1. + @param [out] ParentPrefix Pointer holding the number of carets char ('^'). + Can be [0-255]. + @param [out] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlParseNameStringInfo ( + IN CONST CHAR8 * Buffer, + OUT UINT32 * Root, + OUT UINT32 * ParentPrefix, + OUT UINT32 * SegCount + ) +{ + if ((Buffer == NULL) || + (Root == NULL) || + (ParentPrefix == NULL) || + (SegCount == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + *Root = 0; + *ParentPrefix = 0; + *SegCount = 0; + + // Handle Root and ParentPrefix(s). + if (*Buffer == AML_ROOT_CHAR) { + *Root = 1; + Buffer++; + } else if (*Buffer == AML_PARENT_PREFIX_CHAR) { + do { + Buffer++; + (*ParentPrefix)++; + } while (*Buffer == AML_PARENT_PREFIX_CHAR); + } + + // Handle SegCount(s). + if (*Buffer == AML_DUAL_NAME_PREFIX) { + *SegCount = 2; + } else if (*Buffer == AML_MULTI_NAME_PREFIX) { + *SegCount = *((UINT8*)(Buffer + 1)); + } else if (AmlIsNameSeg (Buffer)) { + *SegCount = 1; + } else if (*Buffer == AML_ZERO_OP) { + *SegCount = 0; + } else { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Safety checks on exit. + if (!AmlIsNameString (*Root, *ParentPrefix, *SegCount)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** Compute the ASL NameString/path size from NameString + information (Root, ParentPrefix, SegCount). + + @param [in] Root Number of root char. + Can be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Can be [0-255]. + @param [in] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @return Size of the ASL NameString/path. +**/ +UINT32 +EFIAPI +AslComputeNameStringSize ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ) +{ + UINT32 TotalSize; + + if (!AmlIsNameString (Root, ParentPrefix, SegCount)) { + ASSERT (0); + return 0; + } + + // Root and ParentPrefix(s). + TotalSize = Root + ParentPrefix; + + // Add size required for NameSeg(s). + TotalSize += (SegCount * AML_NAME_SEG_SIZE); + + // Add size required for '.' separator(s). + TotalSize += (SegCount > 1) ? (SegCount - 1) : 0; + + // Add 1 byte for NULL termination '\0'. + TotalSize += 1; + + return TotalSize; +} + +/** Compute the AML NameString/path size from NameString + information (Root, ParentPrefix, SegCount). + + @param [in] Root Number of root char. + Can be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Can be [0-255]. + @param [in] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @return Size of the AML NameString/path. +**/ +UINT32 +EFIAPI +AmlComputeNameStringSize ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ) +{ + UINT32 TotalSize; + + if (!AmlIsNameString (Root, ParentPrefix, SegCount)) { + ASSERT (0); + return 0; + } + + // Root and ParentPrefix(s). + TotalSize = Root + ParentPrefix; + + // If SegCount == 0, '\0' must end the AML NameString/path. + TotalSize += (SegCount == 0) ? 1 : (SegCount * AML_NAME_SEG_SIZE); + + // AML prefix. SegCount > 2 = MultiNamePrefix, SegCount = 2 DualNamePrefix. + TotalSize += (SegCount > 2) ? 2 : ((SegCount == 2) ? 1 : 0); + + return TotalSize; +} + +/** Get the ASL NameString/path size. + + @param [in] AslPath An ASL NameString/path. + @param [out] AslPathSizePtr Pointer holding the ASL NameString/path size. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AslGetNameStringSize ( + IN CONST CHAR8 * AslPath, + OUT UINT32 * AslPathSizePtr + ) +{ + if ((AslPath == NULL) || + (AslPathSizePtr == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + *AslPathSizePtr = 0; + do { + (*AslPathSizePtr)++; + AslPath++; + } while (*AslPath != '\0'); + + return EFI_SUCCESS; +} + +/** Get the AML NameString/path size. + + @param [in] AmlPath An AML NameString/path. + @param [out] AmlPathSizePtr Pointer holding the AML NameString/path size. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlGetNameStringSize ( + IN CONST CHAR8 * AmlPath, + OUT UINT32 * AmlPathSizePtr + ) +{ + EFI_STATUS Status; + + UINT32 Root; + UINT32 ParentPrefix; + UINT32 SegCount; + + if ((AmlPath == NULL) || + (AmlPathSizePtr == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + Status = AmlParseNameStringInfo ( + AmlPath, + &Root, + &ParentPrefix, + &SegCount + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + *AmlPathSizePtr = AmlComputeNameStringSize (Root, ParentPrefix, SegCount); + if (*AmlPathSizePtr == 0) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** Convert an ASL NameString/path to an AML NameString/path. + The caller must free the memory allocated in this function + for AmlPath using FreePool (). + + @param [in] AslPath An ASL NameString/path. + @param [out] OutAmlPath Buffer containing the AML path. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ConvertAslNameToAmlName ( + IN CONST CHAR8 * AslPath, + OUT CHAR8 ** OutAmlPath + ) +{ + EFI_STATUS Status; + + UINT32 Root; + UINT32 ParentPrefix; + UINT32 SegCount; + UINT32 TotalSize; + UINT32 NameSegSize; + + CONST CHAR8 * AslBuffer; + CHAR8 * AmlBuffer; + CHAR8 * AmlPath; + + if ((AslPath == NULL) || + (OutAmlPath == NULL)) { + return EFI_INVALID_PARAMETER; + } + + // Analyze AslPath. AslPath is checked in the call. + Status = AslParseNameStringInfo (AslPath, &Root, &ParentPrefix, &SegCount); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Compute TotalSize. + TotalSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount); + if (TotalSize == 0) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Allocate memory. + AmlPath = AllocateZeroPool (TotalSize); + if (AmlPath == NULL) { + ASSERT (0); + return EFI_OUT_OF_RESOURCES; + } + + AmlBuffer = AmlPath; + AslBuffer = AslPath; + + // Handle Root and ParentPrefix(s). + if (Root == 1) { + *AmlBuffer = AML_ROOT_CHAR; + AmlBuffer++; + AslBuffer++; + } else if (ParentPrefix > 0) { + SetMem (AmlBuffer, ParentPrefix, AML_PARENT_PREFIX_CHAR); + AmlBuffer += ParentPrefix; + AslBuffer += ParentPrefix; + } + + // Handle prefix and SegCount(s). + if (SegCount > 2) { + *AmlBuffer = AML_MULTI_NAME_PREFIX; + AmlBuffer++; + *AmlBuffer = (UINT8)SegCount; + AmlBuffer++; + } else if (SegCount == 2) { + *AmlBuffer = AML_DUAL_NAME_PREFIX; + AmlBuffer++; + } + + if (SegCount != 0) { + // Write NameSeg(s). + while (1) { + SegCount--; + + // Get the NameSeg size. + if (!AslIsNameSeg (AslBuffer, &NameSegSize)) { + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + + // Convert to Upper case and copy. + Status = AmlUpperCaseMemCpyS ( + AmlBuffer, + TotalSize, + AslBuffer, + NameSegSize + ); + if (EFI_ERROR (Status)) { + ASSERT (0); + goto error_handler; + } + + // Complete the NameSeg with an underscore ('_') if shorter than 4 bytes. + SetMem ( + AmlBuffer + NameSegSize, + AML_NAME_SEG_SIZE - NameSegSize, + AML_NAME_CHAR__ + ); + + // Go to the next NameSeg. + AmlBuffer += AML_NAME_SEG_SIZE; + AslBuffer += NameSegSize; + + // Skip the '.' separator. + if (SegCount != 0) { + if (*AslBuffer == '.') { + AslBuffer++; + } else { + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + } else { + // (SegCount == 0) + if (*AslBuffer == '\0') { + break; + } else { + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + } + } // while + + } else { + // (SegCount == 0) + // '\0' needs to end the AML NameString/path. + *AmlBuffer = AML_ZERO_OP; + AmlBuffer++; + } + + // Safety checks on exit. + // Check that AmlPath has been filled with TotalSize bytes. + if ((SegCount != 0) || + (*AslBuffer != AML_ZERO_OP) || + (((UINT32)(AmlBuffer - AmlPath)) != TotalSize)) { + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + + *OutAmlPath = AmlPath; + return EFI_SUCCESS; + +error_handler: + FreePool (AmlPath); + return Status; +} + +/** Convert an AML NameString/path to an ASL NameString/path. + The caller must free the memory allocated in this function. + using FreePool (). + + @param [in] AmlPath An AML NameString/path. + @param [out] OutAslPath Buffer containing the ASL path. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ConvertAmlNameToAslName ( + IN CONST CHAR8 * AmlPath, + OUT CHAR8 ** OutAslPath + ) +{ + EFI_STATUS Status; + + UINT32 Root; + UINT32 ParentPrefix; + UINT32 SegCount; + UINT32 TotalSize; + + CONST CHAR8 * AmlBuffer; + CHAR8 * AslBuffer; + CHAR8 * AslPath; + + if ((AmlPath == NULL) || + (OutAslPath == NULL)) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Analyze AslPath. AmlPath is checked in the call. + Status = AmlParseNameStringInfo (AmlPath, &Root, &ParentPrefix, &SegCount); + if (EFI_ERROR (Status)) { + ASSERT (0); + return Status; + } + + // Compute TotalSize. + TotalSize = AslComputeNameStringSize (Root, ParentPrefix, SegCount); + if (TotalSize == 0) { + ASSERT (0); + return EFI_INVALID_PARAMETER; + } + + // Allocate memory. + AslPath = AllocateZeroPool (TotalSize); + if (AslPath == NULL) { + ASSERT (0); + return EFI_OUT_OF_RESOURCES; + } + + AmlBuffer = AmlPath; + AslBuffer = AslPath; + + // Handle prefix and SegCount(s). + if (Root == 1) { + *AslBuffer = AML_ROOT_CHAR; + AslBuffer++; + AmlBuffer++; + } else if (ParentPrefix > 0) { + SetMem (AslBuffer, ParentPrefix, AML_PARENT_PREFIX_CHAR); + AslBuffer += ParentPrefix; + AmlBuffer += ParentPrefix; + } + + // Handle Root and Parent(s). + // Skip the MultiName or DualName prefix chars. + if (SegCount > 2) { + AmlBuffer += 2; + } else if (SegCount == 2) { + AmlBuffer += 1; + } + + // Write NameSeg(s). + while (SegCount) { + // NameSeg is already in upper case and always 4 bytes long. + CopyMem (AslBuffer, AmlBuffer, AML_NAME_SEG_SIZE); + AslBuffer += AML_NAME_SEG_SIZE; + AmlBuffer += AML_NAME_SEG_SIZE; + + SegCount--; + + // Write the '.' separator if there is another NameSeg following. + if (SegCount != 0) { + *AslBuffer = '.'; + AslBuffer++; + } + } // while + + // NULL terminate the ASL NameString. + *AslBuffer = '\0'; + AslBuffer++; + + // Safety checks on exit. + // Check that AslPath has been filled with TotalSize bytes. + if (((UINT32)(AslBuffer - AslPath)) != TotalSize) { + ASSERT (0); + Status = EFI_INVALID_PARAMETER; + goto error_handler; + } + + *OutAslPath = AslPath; + return EFI_SUCCESS; + +error_handler: + FreePool (AslPath); + return Status; +} + +/** Compare two ASL NameStrings. + + @param [in] AslName1 First NameString to compare. + @param [in] AslName2 Second NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +AslCompareNameString ( + IN CONST CHAR8 * AslName1, + IN CONST CHAR8 * AslName2 + ) +{ + EFI_STATUS Status; + UINT32 AslName1Len; + UINT32 AslName2Len; + + if ((AslName1 == NULL) || + (AslName2 == NULL)) { + ASSERT (0); + return FALSE; + } + + Status = AslGetNameStringSize (AslName1, &AslName1Len); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + Status = AslGetNameStringSize (AslName2, &AslName2Len); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + // AslName1 and AslName2 don't have the same length + if (AslName1Len != AslName2Len) { + return FALSE; + } + + return (CompareMem (AslName1, AslName2, AslName1Len) == 0); +} + +/** Compare two AML NameStrings. + + @param [in] AmlName1 First NameString to compare. + @param [in] AmlName2 Second NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +AmlCompareNameString ( + IN CONST CHAR8 * AmlName1, + IN CONST CHAR8 * AmlName2 + ) +{ + EFI_STATUS Status; + UINT32 AmlName1Len; + UINT32 AmlName2Len; + + if ((AmlName1 == NULL) || + (AmlName2 == NULL)) { + ASSERT (0); + return FALSE; + } + + Status = AmlGetNameStringSize (AmlName1, &AmlName1Len); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + Status = AmlGetNameStringSize (AmlName2, &AmlName2Len); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + // AmlName1 and AmlName2 don't have the same length + if (AmlName1Len != AmlName2Len) { + return FALSE; + } + + return (CompareMem (AmlName1, AmlName2, AmlName1Len) == 0); +} + +/** Compare an AML NameString and an ASL NameString. + + The ASL NameString is converted to an AML NameString before + being compared with the ASL NameString. This allows to expand + NameSegs shorter than 4 chars. + E.g.: AslName: "DEV" will be expanded to "DEV_" before being + compared. + + @param [in] AmlName1 AML NameString to compare. + @param [in] AslName2 ASL NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +CompareAmlWithAslNameString ( + IN CONST CHAR8 * AmlName1, + IN CONST CHAR8 * AslName2 + ) +{ + EFI_STATUS Status; + + CHAR8 * AmlName2; + BOOLEAN RetVal; + + if ((AmlName1 == NULL) || + (AslName2 == NULL)) { + ASSERT (0); + return FALSE; + } + + // Convert the AslName2 to an AmlName2. + // AmlName2 must be freed. + Status = ConvertAmlNameToAslName (AslName2, &AmlName2); + if (EFI_ERROR (Status)) { + ASSERT (0); + return FALSE; + } + + RetVal = AmlCompareNameString (AmlName1, AmlName2); + + // Free AmlName2. + FreePool (AmlName2); + + return RetVal; +} +/** Given an AmlPath, return the address of the first NameSeg. + + It is possible to determine the size of an AML NameString/path just + by sight reading it. So no overflow can occur. + + @param [in] AmlPath The AML pathname. + @param [in] Root The AML pathname starts with a root char. + It is an absolute path. + @param [in] ParentPrefix The AML pathname has ParentPrefix + carets in its name. + + @return Pointer to the first NameSeg of the NameString. + Return NULL if AmlPath is NULL. +**/ +CONST +CHAR8 * +EFIAPI +AmlGetFirstNameSeg ( + IN CONST CHAR8 * AmlPath, + IN UINT32 Root, + IN UINT32 ParentPrefix + ) +{ + if (AmlPath == NULL) { + ASSERT (0); + return NULL; + } + + AmlPath += Root; + AmlPath += ParentPrefix; + AmlPath += ((*AmlPath == AML_MULTI_NAME_PREFIX) ? 2 + : (*AmlPath == AML_DUAL_NAME_PREFIX) ? 1 : 0); + return AmlPath; +} diff --git a/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.h b/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.h new file mode 100644 index 0000000000..86d9df5f19 --- /dev/null +++ b/DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.h @@ -0,0 +1,401 @@ +/** @file + AML String. + + Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef AML_STRING_H_ +#define AML_STRING_H_ + +/* This header file does not include internal Node definition, + i.e. AML_ROOT_NODE, AML_OBJECT_NODE, etc. The node definitions + must be included by the caller file. The function prototypes must + only expose AML_NODE_HANDLE, AML_ROOT_NODE_HANDLE, etc. node + definitions. + This allows to keep the functions defined here both internal and + potentially external. If necessary, any function of this file can + be exposed externally. + The Api folder is internal to the AmlLib, but should only use these + functions. They provide a "safe" way to interact with the AmlLib. +*/ + +#include + +/** Check NameString/path information is valid. + + Root, ParentPrefix and SegCount cannot be 0 at the same time. + This function works for ASL and AML name strings. + + @param [in] Root Number of root char. + Must be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Must be [0-255]. + @param [in] SegCount Number of NameSeg (s). + Must be [0-255]. + + @retval TRUE id the input information is in the right boundaries. + FALSE otherwise. +**/ +BOOLEAN +EFIAPI +AmlIsNameString ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ); + +/** Copy bytes from SrcBuffer to DstBuffer and convert to upper case. + Don't copy more than MaxDstBufferSize bytes. + + @param [out] DstBuffer Destination buffer. + @param [in] MaxDstBufferSize Maximum size of DstBuffer. + Must be non-zero. + @param [in] SrcBuffer Source buffer. + @param [in] Count Count of bytes to copy from SrcBuffer. + Return success if 0. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlUpperCaseMemCpyS ( + OUT CHAR8 * DstBuffer, + IN UINT32 MaxDstBufferSize, + IN CONST CHAR8 * SrcBuffer, + IN UINT32 Count + ); + +/** Check whether Buffer is a root path ('\'). + + This function works for both ASL and AML pathnames. + Buffer must be at least 2 bytes long. + + @param [in] Buffer An ASL/AML path. + + @retval TRUE Buffer is a root path + @retval FALSE Buffer is not a root path. +**/ +BOOLEAN +EFIAPI +AmlIsRootPath ( + IN CONST CHAR8 * Buffer + ); + +/** Check whether Ch is an ASL/AML LeadName. + + This function works for both ASL and AML pathnames. + + ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms": + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + + ACPI 6.3 specification, s20.2.2. "Name Objects Encoding": + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + + @param [in] Ch The char to test. + + @retval TRUE Ch is an ASL/AML LeadName. + @retval FALSE Ch is not an ASL/AML LeadName. +**/ +BOOLEAN +EFIAPI +AmlIsLeadNameChar ( + IN CHAR8 Ch + ); + +/** Check whether Ch is an ASL/AML NameChar. + + This function works for both ASL and AML pathnames. + + ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms": + NameChar := DigitChar | LeadNameChar + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + DigitChar := '0'-'9' + + ACPI 6.3 specification, s20.2.2. "Name Objects Encoding": + NameChar := DigitChar | LeadNameChar + LeadNameChar := 'A'-'Z' | 'a'-'z' | '_' + DigitChar := '0'-'9' + + @param [in] Ch The char to test. + + @retval TRUE Ch is an ASL/AML NameChar. + @retval FALSE Ch is not an ASL/AML NameChar. +**/ +BOOLEAN +EFIAPI +AmlIsNameChar ( + IN CHAR8 Ch + ); + +/** Check whether AslBuffer is an ASL NameSeg. + + This function only works for ASL NameStrings/pathnames. + ASL NameStrings/pathnames are at most 4 chars long. + + @param [in] AslBuffer Pointer in an ASL NameString/pathname. + @param [out] Size Size of the NameSeg. + + @retval TRUE AslBuffer is an ASL NameSeg. + @retval FALSE AslBuffer is not an ASL NameSeg. +**/ +BOOLEAN +EFIAPI +AslIsNameSeg ( + IN CONST CHAR8 * AslBuffer, + OUT UINT32 * Size + ); + +/** Check whether AmlBuffer is an AML NameSeg. + + This function only works for AML NameStrings/pathnames. + AML NameStrings/pathnames must be 4 chars long. + + @param [in] AmlBuffer Pointer in an AML NameString/pathname. + + @retval TRUE AmlBuffer is an AML NameSeg. + @retval FALSE AmlBuffer is not an AML NameSeg. +**/ +BOOLEAN +EFIAPI +AmlIsNameSeg ( + IN CONST CHAR8 * AmlBuffer + ); + +/** Parse an ASL NameString/path. + + An ASL NameString/path must be NULL terminated. + Information found in the ASL NameString/path is returned via pointers: + Root, ParentPrefix, SegCount. + + @param [in] Buffer ASL NameString/path. + @param [out] Root Pointer holding the number of root char. + Can be 0 or 1. + @param [out] ParentPrefix Pointer holding the number of carets char ('^'). + Can be [0-255]. + @param [out] SegCount Pointer holding the number of NameSeg (s). + Can be [0-255]. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AslParseNameStringInfo ( + IN CONST CHAR8 * Buffer, + OUT UINT32 * Root, + OUT UINT32 * ParentPrefix, + OUT UINT32 * SegCount + ); + +/** Parse an AML NameString/path. + + It is possible to determine the size of an AML NameString/path just + by sight reading it. So no overflow can occur. + Information found in the AML NameString/path is returned via pointers: + Root, ParentPrefix, SegCount. + + @param [in] Buffer AML NameString/path. + @param [out] Root Pointer holding the number of root char. + Can be 0 or 1. + @param [out] ParentPrefix Pointer holding the number of carets char ('^'). + Can be [0-255]. + @param [out] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlParseNameStringInfo ( + IN CONST CHAR8 * Buffer, + OUT UINT32 * Root, + OUT UINT32 * ParentPrefix, + OUT UINT32 * SegCount + ); + +/** Compute the ASL NameString/path size from NameString + information (Root, ParentPrefix, SegCount). + + @param [in] Root Number of root char. + Can be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Can be [0-255]. + @param [in] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @return Size of the ASL NameString/path. +**/ +UINT32 +EFIAPI +AslComputeNameStringSize ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ); + +/** Compute the AML NameString/path size from NameString + information (Root, ParentPrefix, SegCount). + + @param [in] Root Number of root char. + Can be 0 or 1. + @param [in] ParentPrefix Number of carets char ('^'). + Can be [0-255]. + @param [in] SegCount Pointer holding the number of NameSeg(s). + Can be [0-255]. + + @return Size of the AML NameString/path. +**/ +UINT32 +EFIAPI +AmlComputeNameStringSize ( + IN UINT32 Root, + IN UINT32 ParentPrefix, + IN UINT32 SegCount + ); + +/** Get the ASL NameString/path size. + + @param [in] AslPath An ASL NameString/path. + @param [out] AslPathSizePtr Pointer holding the ASL NameString/path size. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AslGetNameStringSize ( + IN CONST CHAR8 * AslPath, + OUT UINT32 * AslPathSizePtr + ); + +/** Get the AML NameString/path size. + + @param [in] AmlPath An AML NameString/path. + @param [out] AmlPathSizePtr Pointer holding the AML NameString/path size. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. +**/ +EFI_STATUS +EFIAPI +AmlGetNameStringSize ( + IN CONST CHAR8 * AmlPath, + OUT UINT32 * AmlPathSizePtr + ); + +/** Convert an ASL NameString/path to an AML NameString/path. + The caller must free the memory allocated in this function + for AmlPath using FreePool (). + + @param [in] AslPath An ASL NameString/path. + @param [out] OutAmlPath Buffer containing the AML path. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ConvertAslNameToAmlName ( + IN CONST CHAR8 * AslPath, + OUT CHAR8 ** OutAmlPath + ); + +/** Convert an AML NameString/path to an ASL NameString/path. + The caller must free the memory allocated in this function. + using FreePool (). + + @param [in] AmlPath An AML NameString/path. + @param [out] OutAslPath Buffer containing the ASL path. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. +**/ +EFI_STATUS +EFIAPI +ConvertAmlNameToAslName ( + IN CONST CHAR8 * AmlPath, + OUT CHAR8 ** OutAslPath + ); + +/** Compare two ASL NameStrings. + + @param [in] AslName1 First NameString to compare. + @param [in] AslName2 Second NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +AslCompareNameString ( + IN CONST CHAR8 * AslName1, + IN CONST CHAR8 * AslName2 + ); + +/** Compare two AML NameStrings. + + @param [in] AmlName1 First NameString to compare. + @param [in] AmlName2 Second NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +AmlCompareNameString ( + IN CONST CHAR8 * AmlName1, + IN CONST CHAR8 * AmlName2 + ); + +/** Compare an AML NameString and an ASL NameString. + + The ASL NameString is converted to an AML NameString before + being compared with the ASL NameString. This allows to expand + NameSegs shorter than 4 chars. + E.g.: AslName: "DEV" will be expanded to "DEV_" before being + compared. + + @param [in] AmlName1 AML NameString to compare. + @param [in] AslName2 ASL NameString to compare. + + @retval TRUE if the two strings are identical. + @retval FALSE otherwise, or if error. +**/ +BOOLEAN +EFIAPI +CompareAmlWithAslNameString ( + IN CONST CHAR8 * AmlName1, + IN CONST CHAR8 * AslName2 + ); + +/** Given an AmlPath, return the address of the first NameSeg. + + It is possible to determine the size of an AML NameString/path just + by sight reading it. So no overflow can occur. + + @param [in] AmlPath The AML pathname. + @param [in] Root The AML pathname starts with a root char. + It is an absolute path. + @param [in] ParentPrefix The AML pathname has ParentPrefix + carets in its name. + + @return Pointer to the first NameSeg of the NameString. + Return NULL if AmlPath is NULL. +**/ +CONST +CHAR8 * +EFIAPI +AmlGetFirstNameSeg ( + IN CONST CHAR8 * AmlPath, + IN UINT32 Root, + IN UINT32 ParentPrefix + ); + +#endif // AML_STRING_H_ -- cgit v1.2.3