| /** @file | |
| AML String. | |
| Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR> | |
| Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <String/AmlString.h> | |
| #include <AmlDefines.h> | |
| #include <IndustryStandard/AcpiAml.h> | |
| /** 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; | |
| } |