diff options
author | Pierre Gondois <pierre.gondois@arm.com> | 2020-08-04 09:08:47 +0100 |
---|---|---|
committer | mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> | 2020-08-13 18:00:06 +0000 |
commit | ca04956e1b7790101a4bd774de60642acc15d695 (patch) | |
tree | 047becb4de2e42991999e33598159ca6c8791494 | |
parent | 667aa7ccbf8311a3bbe6ae541cdb6915711a9f3e (diff) | |
download | edk2-ca04956e1b7790101a4bd774de60642acc15d695.tar.gz edk2-ca04956e1b7790101a4bd774de60642acc15d695.tar.bz2 edk2-ca04956e1b7790101a4bd774de60642acc15d695.zip |
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 <pierre.gondois@arm.com>
Signed-off-by: Sami Mujawar <sami.mujawar@arm.com>
Reviewed-by: Alexei Fedorov <Alexei.Fedorov@arm.com>
-rw-r--r-- | DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.c | 1022 | ||||
-rw-r--r-- | DynamicTablesPkg/Library/Common/AmlLib/String/AmlString.h | 401 |
2 files changed, 1423 insertions, 0 deletions
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. <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;
+}
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. <BR>
+ Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
+
+ 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 <AmlInclude.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
+ );
+
+/** 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_
|