4 Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
5 Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include <String/AmlString.h>
12 #include <AmlDefines.h>
13 #include <IndustryStandard/AcpiAml.h>
15 /** Check NameString/path information is valid.
17 Root, ParentPrefix and SegCount cannot be 0 at the same time.
18 This function works for ASL and AML name strings.
20 @param [in] Root Number of root char.
22 @param [in] ParentPrefix Number of carets char ('^').
24 @param [in] SegCount Number of NameSeg (s).
27 @retval TRUE id the input information is in the right boundaries.
34 IN UINT32 ParentPrefix
,
38 if (((Root
== 0) || (Root
== 1)) &&
39 (ParentPrefix
<= MAX_UINT8
) &&
40 (!((ParentPrefix
!= 0) && (Root
!= 0))) &&
41 (SegCount
<= MAX_UINT8
) &&
42 ((SegCount
+ Root
+ ParentPrefix
) != 0))
50 /** Copy bytes from SrcBuffer to DstBuffer and convert to upper case.
51 Don't copy more than MaxDstBufferSize bytes.
53 @param [out] DstBuffer Destination buffer.
54 @param [in] MaxDstBufferSize Maximum size of DstBuffer.
56 @param [in] SrcBuffer Source buffer.
57 @param [in] Count Count of bytes to copy from SrcBuffer.
60 @retval EFI_SUCCESS The function completed successfully.
61 @retval EFI_INVALID_PARAMETER Invalid parameter.
67 IN UINT32 MaxDstBufferSize
,
68 IN CONST CHAR8
*SrcBuffer
,
74 if ((DstBuffer
== NULL
) ||
78 return EFI_INVALID_PARAMETER
;
85 if (Count
> MaxDstBufferSize
) {
86 Count
= MaxDstBufferSize
;
89 for (Index
= 0; Index
< Count
; Index
++) {
90 if ((SrcBuffer
[Index
] >= 'a') && (SrcBuffer
[Index
] <= 'z')) {
91 DstBuffer
[Index
] = (CHAR8
)((UINT8
)SrcBuffer
[Index
] - ('a' - 'A'));
93 DstBuffer
[Index
] = SrcBuffer
[Index
];
100 /** Check whether Buffer is a root path ('\').
102 This function works for both ASL and AML pathnames.
103 Buffer must be at least 2 bytes long.
105 @param [in] Buffer An ASL/AML path.
107 @retval TRUE Buffer is a root path
108 @retval FALSE Buffer is not a root path.
113 IN CONST CHAR8
*Buffer
116 if (Buffer
== NULL
) {
120 if ((Buffer
[0] == AML_ROOT_CHAR
) && (Buffer
[1] == '\0')) {
127 /** Check whether Ch is an ASL/AML LeadName.
129 This function works for both ASL and AML pathnames.
131 ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms":
132 LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
134 ACPI 6.3 specification, s20.2.2. "Name Objects Encoding":
135 LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
137 @param [in] Ch The char to test.
139 @retval TRUE Ch is an ASL/AML LeadName.
140 @retval FALSE Ch is not an ASL/AML LeadName.
148 if ((Ch
== '_') || ((Ch
>= 'A') && (Ch
<= 'Z')) || ((Ch
>= 'a') && (Ch
<= 'z'))) {
155 /** Check whether Ch is an ASL/AML NameChar.
157 This function works for both ASL and AML pathnames.
159 ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms":
160 NameChar := DigitChar | LeadNameChar
161 LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
164 ACPI 6.3 specification, s20.2.2. "Name Objects Encoding":
165 NameChar := DigitChar | LeadNameChar
166 LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
169 @param [in] Ch The char to test.
171 @retval TRUE Ch is an ASL/AML NameChar.
172 @retval FALSE Ch is not an ASL/AML NameChar.
180 if (AmlIsLeadNameChar (Ch
) || ((Ch
>= '0') && (Ch
<= '9'))) {
187 /** Check whether AslBuffer is an ASL NameSeg.
189 This function only works for ASL NameStrings/pathnames.
190 ASL NameStrings/pathnames are at most 4 chars long.
192 @param [in] AslBuffer Pointer in an ASL NameString/pathname.
193 @param [out] Size Size of the NameSeg.
195 @retval TRUE AslBuffer is an ASL NameSeg.
196 @retval FALSE AslBuffer is not an ASL NameSeg.
201 IN CONST CHAR8
*AslBuffer
,
207 if ((AslBuffer
== NULL
) ||
213 if (!AmlIsLeadNameChar (AslBuffer
[0])) {
217 for (Index
= 1; Index
< AML_NAME_SEG_SIZE
; Index
++) {
218 if ((AslBuffer
[Index
] == '.') ||
219 (AslBuffer
[Index
] == '\0'))
223 } else if (!AmlIsNameChar (AslBuffer
[Index
])) {
232 /** Check whether AmlBuffer is an AML NameSeg.
234 This function only works for AML NameStrings/pathnames.
235 AML NameStrings/pathnames must be 4 chars long.
237 @param [in] AmlBuffer Pointer in an AML NameString/pathname.
239 @retval TRUE AmlBuffer is an AML NameSeg.
240 @retval FALSE AmlBuffer is not an AML NameSeg.
245 IN CONST CHAR8
*AmlBuffer
250 if (AmlBuffer
== NULL
) {
254 if (!AmlIsLeadNameChar (AmlBuffer
[0])) {
258 for (Index
= 1; Index
< AML_NAME_SEG_SIZE
; Index
++) {
259 if (!AmlIsNameChar (AmlBuffer
[Index
])) {
267 /** Parse an ASL NameString/path.
269 An ASL NameString/path must be NULL terminated.
270 Information found in the ASL NameString/path is returned via pointers:
271 Root, ParentPrefix, SegCount.
273 @param [in] Buffer ASL NameString/path.
274 @param [out] Root Pointer holding the number of root char.
276 @param [out] ParentPrefix Pointer holding the number of carets char ('^').
278 @param [out] SegCount Pointer holding the number of NameSeg (s).
281 @retval EFI_SUCCESS The function completed successfully.
282 @retval EFI_INVALID_PARAMETER Invalid parameter.
286 AslParseNameStringInfo (
287 IN CONST CHAR8
*Buffer
,
289 OUT UINT32
*ParentPrefix
,
295 if ((Buffer
== NULL
) ||
297 (ParentPrefix
== NULL
) ||
301 return EFI_INVALID_PARAMETER
;
308 // Handle Root and ParentPrefix(s).
309 if (*Buffer
== AML_ROOT_CHAR
) {
312 } else if (*Buffer
== AML_PARENT_PREFIX_CHAR
) {
316 } while (*Buffer
== AML_PARENT_PREFIX_CHAR
);
319 // Handle SegCount(s).
320 while (AslIsNameSeg (Buffer
, &NameSegSize
)) {
321 // Safety checks on NameSegSize.
322 if ((NameSegSize
== 0) || (NameSegSize
> AML_NAME_SEG_SIZE
)) {
324 return EFI_INVALID_PARAMETER
;
327 // Increment the NameSeg count.
329 Buffer
+= NameSegSize
;
331 // Skip the '.' separator if present.
332 if (*Buffer
== '.') {
337 // An ASL NameString/path must be NULL terminated.
338 if (*Buffer
!= '\0') {
340 return EFI_INVALID_PARAMETER
;
343 if (!AmlIsNameString (*Root
, *ParentPrefix
, *SegCount
)) {
345 return EFI_INVALID_PARAMETER
;
351 /** Parse an AML NameString/path.
353 It is possible to determine the size of an AML NameString/path just
354 by sight reading it. So no overflow can occur.
355 Information found in the AML NameString/path is returned via pointers:
356 Root, ParentPrefix, SegCount.
358 @param [in] Buffer AML NameString/path.
359 @param [out] Root Pointer holding the number of root char.
361 @param [out] ParentPrefix Pointer holding the number of carets char ('^').
363 @param [out] SegCount Pointer holding the number of NameSeg(s).
366 @retval EFI_SUCCESS The function completed successfully.
367 @retval EFI_INVALID_PARAMETER Invalid parameter.
371 AmlParseNameStringInfo (
372 IN CONST CHAR8
*Buffer
,
374 OUT UINT32
*ParentPrefix
,
378 if ((Buffer
== NULL
) ||
380 (ParentPrefix
== NULL
) ||
384 return EFI_INVALID_PARAMETER
;
391 // Handle Root and ParentPrefix(s).
392 if (*Buffer
== AML_ROOT_CHAR
) {
395 } else if (*Buffer
== AML_PARENT_PREFIX_CHAR
) {
399 } while (*Buffer
== AML_PARENT_PREFIX_CHAR
);
402 // Handle SegCount(s).
403 if (*Buffer
== AML_DUAL_NAME_PREFIX
) {
405 } else if (*Buffer
== AML_MULTI_NAME_PREFIX
) {
406 *SegCount
= *((UINT8
*)(Buffer
+ 1));
407 } else if (AmlIsNameSeg (Buffer
)) {
409 } else if (*Buffer
== AML_ZERO_OP
) {
413 return EFI_INVALID_PARAMETER
;
416 // Safety checks on exit.
417 if (!AmlIsNameString (*Root
, *ParentPrefix
, *SegCount
)) {
419 return EFI_INVALID_PARAMETER
;
425 /** Compute the ASL NameString/path size from NameString
426 information (Root, ParentPrefix, SegCount).
428 @param [in] Root Number of root char.
430 @param [in] ParentPrefix Number of carets char ('^').
432 @param [in] SegCount Pointer holding the number of NameSeg(s).
435 @return Size of the ASL NameString/path.
439 AslComputeNameStringSize (
441 IN UINT32 ParentPrefix
,
447 if (!AmlIsNameString (Root
, ParentPrefix
, SegCount
)) {
452 // Root and ParentPrefix(s).
453 TotalSize
= Root
+ ParentPrefix
;
455 // Add size required for NameSeg(s).
456 TotalSize
+= (SegCount
* AML_NAME_SEG_SIZE
);
458 // Add size required for '.' separator(s).
459 TotalSize
+= (SegCount
> 1) ? (SegCount
- 1) : 0;
461 // Add 1 byte for NULL termination '\0'.
467 /** Compute the AML NameString/path size from NameString
468 information (Root, ParentPrefix, SegCount).
470 @param [in] Root Number of root char.
472 @param [in] ParentPrefix Number of carets char ('^').
474 @param [in] SegCount Pointer holding the number of NameSeg(s).
477 @return Size of the AML NameString/path.
481 AmlComputeNameStringSize (
483 IN UINT32 ParentPrefix
,
489 if (!AmlIsNameString (Root
, ParentPrefix
, SegCount
)) {
494 // Root and ParentPrefix(s).
495 TotalSize
= Root
+ ParentPrefix
;
497 // If SegCount == 0, '\0' must end the AML NameString/path.
498 TotalSize
+= (SegCount
== 0) ? 1 : (SegCount
* AML_NAME_SEG_SIZE
);
500 // AML prefix. SegCount > 2 = MultiNamePrefix, SegCount = 2 DualNamePrefix.
501 TotalSize
+= (SegCount
> 2) ? 2 : ((SegCount
== 2) ? 1 : 0);
506 /** Get the ASL NameString/path size.
508 @param [in] AslPath An ASL NameString/path.
509 @param [out] AslPathSizePtr Pointer holding the ASL NameString/path size.
511 @retval EFI_SUCCESS Success.
512 @retval EFI_INVALID_PARAMETER Invalid parameter.
516 AslGetNameStringSize (
517 IN CONST CHAR8
*AslPath
,
518 OUT UINT32
*AslPathSizePtr
521 if ((AslPath
== NULL
) ||
522 (AslPathSizePtr
== NULL
))
525 return EFI_INVALID_PARAMETER
;
532 } while (*AslPath
!= '\0');
537 /** Get the AML NameString/path size.
539 @param [in] AmlPath An AML NameString/path.
540 @param [out] AmlPathSizePtr Pointer holding the AML NameString/path size.
542 @retval EFI_SUCCESS Success.
543 @retval EFI_INVALID_PARAMETER Invalid parameter.
547 AmlGetNameStringSize (
548 IN CONST CHAR8
*AmlPath
,
549 OUT UINT32
*AmlPathSizePtr
558 if ((AmlPath
== NULL
) ||
559 (AmlPathSizePtr
== NULL
))
562 return EFI_INVALID_PARAMETER
;
565 Status
= AmlParseNameStringInfo (
571 if (EFI_ERROR (Status
)) {
576 *AmlPathSizePtr
= AmlComputeNameStringSize (Root
, ParentPrefix
, SegCount
);
577 if (*AmlPathSizePtr
== 0) {
579 return EFI_INVALID_PARAMETER
;
585 /** Convert an ASL NameString/path to an AML NameString/path.
586 The caller must free the memory allocated in this function
587 for AmlPath using FreePool ().
589 @param [in] AslPath An ASL NameString/path.
590 @param [out] OutAmlPath Buffer containing the AML path.
592 @retval EFI_SUCCESS Success.
593 @retval EFI_INVALID_PARAMETER Invalid parameter.
594 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
598 ConvertAslNameToAmlName (
599 IN CONST CHAR8
*AslPath
,
600 OUT CHAR8
**OutAmlPath
611 CONST CHAR8
*AslBuffer
;
615 if ((AslPath
== NULL
) ||
616 (OutAmlPath
== NULL
))
618 return EFI_INVALID_PARAMETER
;
621 // Analyze AslPath. AslPath is checked in the call.
622 Status
= AslParseNameStringInfo (AslPath
, &Root
, &ParentPrefix
, &SegCount
);
623 if (EFI_ERROR (Status
)) {
628 // Compute TotalSize.
629 TotalSize
= AmlComputeNameStringSize (Root
, ParentPrefix
, SegCount
);
630 if (TotalSize
== 0) {
632 return EFI_INVALID_PARAMETER
;
636 AmlPath
= AllocateZeroPool (TotalSize
);
637 if (AmlPath
== NULL
) {
639 return EFI_OUT_OF_RESOURCES
;
645 // Handle Root and ParentPrefix(s).
647 *AmlBuffer
= AML_ROOT_CHAR
;
650 } else if (ParentPrefix
> 0) {
651 SetMem (AmlBuffer
, ParentPrefix
, AML_PARENT_PREFIX_CHAR
);
652 AmlBuffer
+= ParentPrefix
;
653 AslBuffer
+= ParentPrefix
;
656 // Handle prefix and SegCount(s).
658 *AmlBuffer
= AML_MULTI_NAME_PREFIX
;
660 *AmlBuffer
= (UINT8
)SegCount
;
662 } else if (SegCount
== 2) {
663 *AmlBuffer
= AML_DUAL_NAME_PREFIX
;
672 // Get the NameSeg size.
673 if (!AslIsNameSeg (AslBuffer
, &NameSegSize
)) {
675 Status
= EFI_INVALID_PARAMETER
;
679 // Convert to Upper case and copy.
680 Status
= AmlUpperCaseMemCpyS (
686 if (EFI_ERROR (Status
)) {
691 // Complete the NameSeg with an underscore ('_') if shorter than 4 bytes.
693 AmlBuffer
+ NameSegSize
,
694 AML_NAME_SEG_SIZE
- NameSegSize
,
698 // Go to the next NameSeg.
699 AmlBuffer
+= AML_NAME_SEG_SIZE
;
700 AslBuffer
+= NameSegSize
;
702 // Skip the '.' separator.
704 if (*AslBuffer
== '.') {
708 Status
= EFI_INVALID_PARAMETER
;
713 if (*AslBuffer
== '\0') {
717 Status
= EFI_INVALID_PARAMETER
;
724 // '\0' needs to end the AML NameString/path.
725 *AmlBuffer
= AML_ZERO_OP
;
729 // Safety checks on exit.
730 // Check that AmlPath has been filled with TotalSize bytes.
731 if ((SegCount
!= 0) ||
732 (*AslBuffer
!= AML_ZERO_OP
) ||
733 (((UINT32
)(AmlBuffer
- AmlPath
)) != TotalSize
))
736 Status
= EFI_INVALID_PARAMETER
;
740 *OutAmlPath
= AmlPath
;
748 /** Convert an AML NameString/path to an ASL NameString/path.
749 The caller must free the memory allocated in this function.
752 @param [in] AmlPath An AML NameString/path.
753 @param [out] OutAslPath Buffer containing the ASL path.
755 @retval EFI_SUCCESS Success.
756 @retval EFI_INVALID_PARAMETER Invalid parameter.
757 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
761 ConvertAmlNameToAslName (
762 IN CONST CHAR8
*AmlPath
,
763 OUT CHAR8
**OutAslPath
773 CONST CHAR8
*AmlBuffer
;
777 if ((AmlPath
== NULL
) ||
778 (OutAslPath
== NULL
))
781 return EFI_INVALID_PARAMETER
;
784 // Analyze AslPath. AmlPath is checked in the call.
785 Status
= AmlParseNameStringInfo (AmlPath
, &Root
, &ParentPrefix
, &SegCount
);
786 if (EFI_ERROR (Status
)) {
791 // Compute TotalSize.
792 TotalSize
= AslComputeNameStringSize (Root
, ParentPrefix
, SegCount
);
793 if (TotalSize
== 0) {
795 return EFI_INVALID_PARAMETER
;
799 AslPath
= AllocateZeroPool (TotalSize
);
800 if (AslPath
== NULL
) {
802 return EFI_OUT_OF_RESOURCES
;
808 // Handle prefix and SegCount(s).
810 *AslBuffer
= AML_ROOT_CHAR
;
813 } else if (ParentPrefix
> 0) {
814 SetMem (AslBuffer
, ParentPrefix
, AML_PARENT_PREFIX_CHAR
);
815 AslBuffer
+= ParentPrefix
;
816 AmlBuffer
+= ParentPrefix
;
819 // Handle Root and Parent(s).
820 // Skip the MultiName or DualName prefix chars.
823 } else if (SegCount
== 2) {
829 // NameSeg is already in upper case and always 4 bytes long.
830 CopyMem (AslBuffer
, AmlBuffer
, AML_NAME_SEG_SIZE
);
831 AslBuffer
+= AML_NAME_SEG_SIZE
;
832 AmlBuffer
+= AML_NAME_SEG_SIZE
;
836 // Write the '.' separator if there is another NameSeg following.
843 // NULL terminate the ASL NameString.
847 // Safety checks on exit.
848 // Check that AslPath has been filled with TotalSize bytes.
849 if (((UINT32
)(AslBuffer
- AslPath
)) != TotalSize
) {
851 Status
= EFI_INVALID_PARAMETER
;
855 *OutAslPath
= AslPath
;
863 /** Compare two ASL NameStrings.
865 @param [in] AslName1 First NameString to compare.
866 @param [in] AslName2 Second NameString to compare.
868 @retval TRUE if the two strings are identical.
869 @retval FALSE otherwise, or if error.
873 AslCompareNameString (
874 IN CONST CHAR8
*AslName1
,
875 IN CONST CHAR8
*AslName2
882 if ((AslName1
== NULL
) ||
889 Status
= AslGetNameStringSize (AslName1
, &AslName1Len
);
890 if (EFI_ERROR (Status
)) {
895 Status
= AslGetNameStringSize (AslName2
, &AslName2Len
);
896 if (EFI_ERROR (Status
)) {
901 // AslName1 and AslName2 don't have the same length
902 if (AslName1Len
!= AslName2Len
) {
906 return (CompareMem (AslName1
, AslName2
, AslName1Len
) == 0);
909 /** Compare two AML NameStrings.
911 @param [in] AmlName1 First NameString to compare.
912 @param [in] AmlName2 Second NameString to compare.
914 @retval TRUE if the two strings are identical.
915 @retval FALSE otherwise, or if error.
919 AmlCompareNameString (
920 IN CONST CHAR8
*AmlName1
,
921 IN CONST CHAR8
*AmlName2
928 if ((AmlName1
== NULL
) ||
935 Status
= AmlGetNameStringSize (AmlName1
, &AmlName1Len
);
936 if (EFI_ERROR (Status
)) {
941 Status
= AmlGetNameStringSize (AmlName2
, &AmlName2Len
);
942 if (EFI_ERROR (Status
)) {
947 // AmlName1 and AmlName2 don't have the same length
948 if (AmlName1Len
!= AmlName2Len
) {
952 return (CompareMem (AmlName1
, AmlName2
, AmlName1Len
) == 0);
955 /** Compare an AML NameString and an ASL NameString.
957 The ASL NameString is converted to an AML NameString before
958 being compared with the ASL NameString. This allows to expand
959 NameSegs shorter than 4 chars.
960 E.g.: AslName: "DEV" will be expanded to "DEV_" before being
963 @param [in] AmlName1 AML NameString to compare.
964 @param [in] AslName2 ASL NameString to compare.
966 @retval TRUE if the two strings are identical.
967 @retval FALSE otherwise, or if error.
971 CompareAmlWithAslNameString (
972 IN CONST CHAR8
*AmlName1
,
973 IN CONST CHAR8
*AslName2
981 if ((AmlName1
== NULL
) ||
988 // Convert the AslName2 to an AmlName2.
989 // AmlName2 must be freed.
990 Status
= ConvertAmlNameToAslName (AslName2
, &AmlName2
);
991 if (EFI_ERROR (Status
)) {
996 RetVal
= AmlCompareNameString (AmlName1
, AmlName2
);
1004 /** Given an AmlPath, return the address of the first NameSeg.
1006 It is possible to determine the size of an AML NameString/path just
1007 by sight reading it. So no overflow can occur.
1009 @param [in] AmlPath The AML pathname.
1010 @param [in] Root The AML pathname starts with a root char.
1011 It is an absolute path.
1012 @param [in] ParentPrefix The AML pathname has ParentPrefix
1015 @return Pointer to the first NameSeg of the NameString.
1016 Return NULL if AmlPath is NULL.
1021 AmlGetFirstNameSeg (
1022 IN CONST CHAR8
*AmlPath
,
1024 IN UINT32 ParentPrefix
1027 if (AmlPath
== NULL
) {
1033 AmlPath
+= ParentPrefix
;
1034 AmlPath
+= ((*AmlPath
== AML_MULTI_NAME_PREFIX
) ? 2
1035 : (*AmlPath
== AML_DUAL_NAME_PREFIX
) ? 1 : 0);