1 /** @file
2   AML String.
3 
4   Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved. <BR>
5   Copyright (c) 2019 - 2020, Arm Limited. All rights reserved.<BR>
6 
7   SPDX-License-Identifier: BSD-2-Clause-Patent
8 **/
9 
10 #include <String/AmlString.h>
11 
12 #include <AmlDefines.h>
13 #include <IndustryStandard/AcpiAml.h>
14 
15 /** Check NameString/path information is valid.
16 
17   Root, ParentPrefix and SegCount cannot be 0 at the same time.
18   This function works for ASL and AML name strings.
19 
20   @param [in]   Root          Number of root char.
21                               Must be 0 or 1.
22   @param [in]   ParentPrefix  Number of carets char ('^').
23                               Must be [0-255].
24   @param [in]   SegCount      Number of NameSeg (s).
25                               Must be [0-255].
26 
27   @retval TRUE id the input information is in the right boundaries.
28           FALSE otherwise.
29 **/
30 BOOLEAN
31 EFIAPI
AmlIsNameString(IN UINT32 Root,IN UINT32 ParentPrefix,IN UINT32 SegCount)32 AmlIsNameString (
33   IN  UINT32    Root,
34   IN  UINT32    ParentPrefix,
35   IN  UINT32    SegCount
36   )
37 {
38   if (((Root == 0) || (Root == 1))            &&
39       (ParentPrefix <= MAX_UINT8)             &&
40       (!((ParentPrefix != 0) && (Root != 0))) &&
41       (SegCount <= MAX_UINT8)                 &&
42       ((SegCount + Root + ParentPrefix) != 0)) {
43     return TRUE;
44   }
45   return FALSE;
46 }
47 
48 /** Copy bytes from SrcBuffer to DstBuffer and convert to upper case.
49     Don't copy more than MaxDstBufferSize bytes.
50 
51   @param  [out] DstBuffer         Destination buffer.
52   @param  [in]  MaxDstBufferSize  Maximum size of DstBuffer.
53                                   Must be non-zero.
54   @param  [in]  SrcBuffer         Source buffer.
55   @param  [in]  Count             Count of bytes to copy from SrcBuffer.
56                                   Return success if 0.
57 
58   @retval EFI_SUCCESS             The function completed successfully.
59   @retval EFI_INVALID_PARAMETER   Invalid parameter.
60 **/
61 EFI_STATUS
62 EFIAPI
AmlUpperCaseMemCpyS(OUT CHAR8 * DstBuffer,IN UINT32 MaxDstBufferSize,IN CONST CHAR8 * SrcBuffer,IN UINT32 Count)63 AmlUpperCaseMemCpyS (
64   OUT       CHAR8   * DstBuffer,
65   IN        UINT32    MaxDstBufferSize,
66   IN  CONST CHAR8   * SrcBuffer,
67   IN        UINT32    Count
68   )
69 {
70   UINT32 Index;
71 
72   if ((DstBuffer == NULL) ||
73       (SrcBuffer == NULL)) {
74     ASSERT (0);
75     return EFI_INVALID_PARAMETER;
76   }
77 
78   if (Count == 0) {
79     return EFI_SUCCESS;
80   }
81 
82   if (Count > MaxDstBufferSize) {
83     Count = MaxDstBufferSize;
84   }
85 
86   for (Index = 0; Index < Count; Index++) {
87     if ((SrcBuffer[Index] >= 'a') && (SrcBuffer[Index] <= 'z')) {
88       DstBuffer[Index] = (CHAR8)((UINT8)SrcBuffer[Index] - ('a' - 'A'));
89     } else {
90       DstBuffer[Index] = SrcBuffer[Index];
91     }
92   }
93 
94   return EFI_SUCCESS;
95 }
96 
97 /** Check whether Buffer is a root path ('\').
98 
99   This function works for both ASL and AML pathnames.
100   Buffer must be at least 2 bytes long.
101 
102   @param  [in]  Buffer   An ASL/AML path.
103 
104   @retval TRUE    Buffer is a root path
105   @retval FALSE   Buffer is not a root path.
106 **/
107 BOOLEAN
108 EFIAPI
AmlIsRootPath(IN CONST CHAR8 * Buffer)109 AmlIsRootPath (
110   IN  CONST  CHAR8  * Buffer
111   )
112 {
113   if (Buffer == NULL) {
114     return FALSE;
115   }
116 
117   if ((Buffer[0] == AML_ROOT_CHAR) && (Buffer[1] == '\0')) {
118     return TRUE;
119   } else {
120     return FALSE;
121   }
122 }
123 
124 /** Check whether Ch is an ASL/AML LeadName.
125 
126   This function works for both ASL and AML pathnames.
127 
128   ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms":
129   LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
130 
131   ACPI 6.3 specification, s20.2.2. "Name Objects Encoding":
132   LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
133 
134   @param  [in]  Ch    The char to test.
135 
136   @retval TRUE    Ch is an ASL/AML LeadName.
137   @retval FALSE   Ch is not an ASL/AML LeadName.
138 **/
139 BOOLEAN
140 EFIAPI
AmlIsLeadNameChar(IN CHAR8 Ch)141 AmlIsLeadNameChar (
142   IN  CHAR8   Ch
143   )
144 {
145   if ((Ch == '_') || (Ch >= 'A' && Ch <= 'Z') || (Ch >= 'a' && Ch <= 'z')) {
146     return TRUE;
147   } else {
148     return FALSE;
149   }
150 }
151 
152 /** Check whether Ch is an ASL/AML NameChar.
153 
154   This function works for both ASL and AML pathnames.
155 
156   ACPI 6.3 specification, s19.2.2. "ASL Name and Pathname Terms":
157   NameChar := DigitChar | LeadNameChar
158   LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
159   DigitChar := '0'-'9'
160 
161   ACPI 6.3 specification, s20.2.2. "Name Objects Encoding":
162   NameChar := DigitChar | LeadNameChar
163   LeadNameChar := 'A'-'Z' | 'a'-'z' | '_'
164   DigitChar := '0'-'9'
165 
166   @param  [in]  Ch    The char to test.
167 
168   @retval TRUE    Ch is an ASL/AML NameChar.
169   @retval FALSE   Ch is not an ASL/AML NameChar.
170 **/
171 BOOLEAN
172 EFIAPI
AmlIsNameChar(IN CHAR8 Ch)173 AmlIsNameChar (
174   IN  CHAR8  Ch
175   )
176 {
177   if (AmlIsLeadNameChar (Ch) || (Ch >= '0' && Ch <= '9')) {
178     return TRUE;
179   } else {
180     return FALSE;
181   }
182 }
183 
184 /** Check whether AslBuffer is an ASL NameSeg.
185 
186   This function only works for ASL NameStrings/pathnames.
187   ASL NameStrings/pathnames are at most 4 chars long.
188 
189   @param [in]   AslBuffer   Pointer in an ASL NameString/pathname.
190   @param [out]  Size        Size of the NameSeg.
191 
192   @retval TRUE    AslBuffer is an ASL NameSeg.
193   @retval FALSE   AslBuffer is not an ASL NameSeg.
194 **/
195 BOOLEAN
196 EFIAPI
AslIsNameSeg(IN CONST CHAR8 * AslBuffer,OUT UINT32 * Size)197 AslIsNameSeg (
198   IN  CONST  CHAR8    * AslBuffer,
199   OUT        UINT32   * Size
200   )
201 {
202   UINT32    Index;
203 
204   if ((AslBuffer == NULL) ||
205       (Size == NULL)) {
206     return FALSE;
207   }
208 
209   if (!AmlIsLeadNameChar (AslBuffer[0])) {
210     return FALSE;
211   }
212 
213   for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
214     if ((AslBuffer[Index] == '.')   ||
215         (AslBuffer[Index] == '\0')) {
216       *Size = Index;
217       return TRUE;
218     } else if (!AmlIsNameChar (AslBuffer[Index])) {
219       return FALSE;
220     }
221   }
222 
223   *Size = Index;
224   return TRUE;
225 }
226 
227 /** Check whether AmlBuffer is an AML NameSeg.
228 
229   This function only works for AML NameStrings/pathnames.
230   AML NameStrings/pathnames must be 4 chars long.
231 
232   @param [in] AmlBuffer   Pointer in an AML NameString/pathname.
233 
234   @retval TRUE    AmlBuffer is an AML NameSeg.
235   @retval FALSE   AmlBuffer is not an AML NameSeg.
236 **/
237 BOOLEAN
238 EFIAPI
AmlIsNameSeg(IN CONST CHAR8 * AmlBuffer)239 AmlIsNameSeg (
240   IN  CONST  CHAR8    * AmlBuffer
241   )
242 {
243   UINT32    Index;
244 
245   if (AmlBuffer == NULL) {
246     return FALSE;
247   }
248 
249   if (!AmlIsLeadNameChar (AmlBuffer[0])) {
250     return FALSE;
251   }
252 
253   for (Index = 1; Index < AML_NAME_SEG_SIZE; Index++) {
254     if (!AmlIsNameChar (AmlBuffer[Index])) {
255       return FALSE;
256     }
257   }
258 
259   return TRUE;
260 }
261 
262 /** Parse an ASL NameString/path.
263 
264   An ASL NameString/path must be NULL terminated.
265   Information found in the ASL NameString/path is returned via pointers:
266   Root, ParentPrefix, SegCount.
267 
268   @param [in]    Buffer       ASL NameString/path.
269   @param [out]   Root         Pointer holding the number of root char.
270                               Can be 0 or 1.
271   @param [out]   ParentPrefix Pointer holding the number of carets char ('^').
272                               Can be [0-255].
273   @param [out]   SegCount     Pointer holding the number of NameSeg (s).
274                               Can be [0-255].
275 
276   @retval EFI_SUCCESS             The function completed successfully.
277   @retval EFI_INVALID_PARAMETER   Invalid parameter.
278 **/
279 EFI_STATUS
280 EFIAPI
AslParseNameStringInfo(IN CONST CHAR8 * Buffer,OUT UINT32 * Root,OUT UINT32 * ParentPrefix,OUT UINT32 * SegCount)281 AslParseNameStringInfo (
282   IN  CONST CHAR8     * Buffer,
283   OUT       UINT32    * Root,
284   OUT       UINT32    * ParentPrefix,
285   OUT       UINT32    * SegCount
286   )
287 {
288   UINT32      NameSegSize;
289 
290   if ((Buffer == NULL)        ||
291       (Root == NULL)          ||
292       (ParentPrefix == NULL)  ||
293       (SegCount == NULL)) {
294     ASSERT (0);
295     return EFI_INVALID_PARAMETER;
296   }
297 
298   *Root = 0;
299   *ParentPrefix = 0;
300   *SegCount = 0;
301 
302   // Handle Root and ParentPrefix(s).
303   if (*Buffer == AML_ROOT_CHAR) {
304     *Root = 1;
305     Buffer++;
306   } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
307     do {
308       Buffer++;
309       (*ParentPrefix)++;
310     } while (*Buffer == AML_PARENT_PREFIX_CHAR);
311   }
312 
313   // Handle SegCount(s).
314   while (AslIsNameSeg (Buffer, &NameSegSize)) {
315     // Safety checks on NameSegSize.
316     if ((NameSegSize == 0) || (NameSegSize > AML_NAME_SEG_SIZE)) {
317       ASSERT (0);
318       return EFI_INVALID_PARAMETER;
319     }
320 
321     // Increment the NameSeg count.
322     (*SegCount)++;
323     Buffer += NameSegSize;
324 
325     // Skip the '.' separator if present.
326     if (*Buffer == '.') {
327       Buffer++;
328     }
329   } // while
330 
331   // An ASL NameString/path must be NULL terminated.
332   if (*Buffer != '\0') {
333     ASSERT (0);
334     return EFI_INVALID_PARAMETER;
335   }
336 
337   if (!AmlIsNameString (*Root, *ParentPrefix, *SegCount)) {
338     ASSERT (0);
339     return EFI_INVALID_PARAMETER;
340   }
341 
342   return EFI_SUCCESS;
343 }
344 
345 /** Parse an AML NameString/path.
346 
347   It is possible to determine the size of an AML NameString/path just
348   by sight reading it. So no overflow can occur.
349   Information found in the AML NameString/path is returned via pointers:
350   Root, ParentPrefix, SegCount.
351 
352   @param [in]    Buffer         AML NameString/path.
353   @param [out]   Root           Pointer holding the number of root char.
354                                 Can be 0 or 1.
355   @param [out]   ParentPrefix   Pointer holding the number of carets char ('^').
356                                 Can be [0-255].
357   @param [out]   SegCount       Pointer holding the number of NameSeg(s).
358                                 Can be [0-255].
359 
360   @retval EFI_SUCCESS             The function completed successfully.
361   @retval EFI_INVALID_PARAMETER   Invalid parameter.
362 **/
363 EFI_STATUS
364 EFIAPI
AmlParseNameStringInfo(IN CONST CHAR8 * Buffer,OUT UINT32 * Root,OUT UINT32 * ParentPrefix,OUT UINT32 * SegCount)365 AmlParseNameStringInfo (
366   IN  CONST CHAR8   * Buffer,
367   OUT       UINT32  * Root,
368   OUT       UINT32  * ParentPrefix,
369   OUT       UINT32  * SegCount
370   )
371 {
372   if ((Buffer == NULL) ||
373       (Root == NULL)   ||
374       (ParentPrefix == NULL) ||
375       (SegCount == NULL)) {
376     ASSERT (0);
377     return EFI_INVALID_PARAMETER;
378   }
379 
380   *Root = 0;
381   *ParentPrefix = 0;
382   *SegCount = 0;
383 
384   // Handle Root and ParentPrefix(s).
385   if (*Buffer == AML_ROOT_CHAR) {
386     *Root = 1;
387     Buffer++;
388   } else if (*Buffer == AML_PARENT_PREFIX_CHAR) {
389     do {
390       Buffer++;
391       (*ParentPrefix)++;
392     } while (*Buffer == AML_PARENT_PREFIX_CHAR);
393   }
394 
395   // Handle SegCount(s).
396   if (*Buffer == AML_DUAL_NAME_PREFIX) {
397     *SegCount = 2;
398   } else if (*Buffer == AML_MULTI_NAME_PREFIX) {
399     *SegCount = *((UINT8*)(Buffer + 1));
400   } else if (AmlIsNameSeg (Buffer)) {
401     *SegCount = 1;
402   } else if (*Buffer == AML_ZERO_OP) {
403     *SegCount = 0;
404   } else {
405     ASSERT (0);
406     return EFI_INVALID_PARAMETER;
407   }
408 
409   // Safety checks on exit.
410   if (!AmlIsNameString (*Root, *ParentPrefix, *SegCount)) {
411     ASSERT (0);
412     return EFI_INVALID_PARAMETER;
413   }
414 
415   return EFI_SUCCESS;
416 }
417 
418 /** Compute the ASL NameString/path size from NameString
419     information (Root, ParentPrefix, SegCount).
420 
421   @param [in] Root          Number of root char.
422                             Can be 0 or 1.
423   @param [in] ParentPrefix  Number of carets char ('^').
424                             Can be [0-255].
425   @param [in] SegCount      Pointer holding the number of NameSeg(s).
426                             Can be [0-255].
427 
428   @return Size of the ASL NameString/path.
429 **/
430 UINT32
431 EFIAPI
AslComputeNameStringSize(IN UINT32 Root,IN UINT32 ParentPrefix,IN UINT32 SegCount)432 AslComputeNameStringSize (
433   IN  UINT32    Root,
434   IN  UINT32    ParentPrefix,
435   IN  UINT32    SegCount
436   )
437 {
438   UINT32    TotalSize;
439 
440   if (!AmlIsNameString (Root, ParentPrefix, SegCount)) {
441     ASSERT (0);
442     return 0;
443   }
444 
445   // Root and ParentPrefix(s).
446   TotalSize = Root + ParentPrefix;
447 
448   // Add size required for NameSeg(s).
449   TotalSize += (SegCount * AML_NAME_SEG_SIZE);
450 
451   // Add size required for '.' separator(s).
452   TotalSize += (SegCount > 1) ? (SegCount - 1) : 0;
453 
454   // Add 1 byte for NULL termination '\0'.
455   TotalSize += 1;
456 
457   return TotalSize;
458 }
459 
460 /** Compute the AML NameString/path size from NameString
461     information (Root, ParentPrefix, SegCount).
462 
463   @param [in] Root          Number of root char.
464                             Can be 0 or 1.
465   @param [in] ParentPrefix  Number of carets char ('^').
466                             Can be [0-255].
467   @param [in] SegCount      Pointer holding the number of NameSeg(s).
468                             Can be [0-255].
469 
470   @return Size of the AML NameString/path.
471 **/
472 UINT32
473 EFIAPI
AmlComputeNameStringSize(IN UINT32 Root,IN UINT32 ParentPrefix,IN UINT32 SegCount)474 AmlComputeNameStringSize (
475   IN  UINT32    Root,
476   IN  UINT32    ParentPrefix,
477   IN  UINT32    SegCount
478   )
479 {
480   UINT32    TotalSize;
481 
482   if (!AmlIsNameString (Root, ParentPrefix, SegCount)) {
483     ASSERT (0);
484     return 0;
485   }
486 
487   // Root and ParentPrefix(s).
488   TotalSize = Root + ParentPrefix;
489 
490   // If SegCount == 0, '\0' must end the AML NameString/path.
491   TotalSize += (SegCount == 0) ? 1 : (SegCount * AML_NAME_SEG_SIZE);
492 
493   // AML prefix. SegCount > 2 = MultiNamePrefix, SegCount = 2 DualNamePrefix.
494   TotalSize += (SegCount > 2) ? 2 : ((SegCount == 2) ? 1 : 0);
495 
496   return TotalSize;
497 }
498 
499 /** Get the ASL NameString/path size.
500 
501   @param [in]   AslPath         An ASL NameString/path.
502   @param [out]  AslPathSizePtr  Pointer holding the ASL NameString/path size.
503 
504   @retval EFI_SUCCESS             Success.
505   @retval EFI_INVALID_PARAMETER   Invalid parameter.
506 **/
507 EFI_STATUS
508 EFIAPI
AslGetNameStringSize(IN CONST CHAR8 * AslPath,OUT UINT32 * AslPathSizePtr)509 AslGetNameStringSize (
510   IN  CONST CHAR8   * AslPath,
511   OUT       UINT32  * AslPathSizePtr
512   )
513 {
514   if ((AslPath == NULL) ||
515       (AslPathSizePtr == NULL)) {
516     ASSERT (0);
517     return EFI_INVALID_PARAMETER;
518   }
519 
520   *AslPathSizePtr = 0;
521   do {
522     (*AslPathSizePtr)++;
523     AslPath++;
524   } while (*AslPath != '\0');
525 
526   return EFI_SUCCESS;
527 }
528 
529 /** Get the AML NameString/path size.
530 
531   @param [in]   AmlPath         An AML NameString/path.
532   @param [out]  AmlPathSizePtr  Pointer holding the AML NameString/path size.
533 
534   @retval EFI_SUCCESS             Success.
535   @retval EFI_INVALID_PARAMETER   Invalid parameter.
536 **/
537 EFI_STATUS
538 EFIAPI
AmlGetNameStringSize(IN CONST CHAR8 * AmlPath,OUT UINT32 * AmlPathSizePtr)539 AmlGetNameStringSize (
540   IN   CONST  CHAR8   * AmlPath,
541   OUT         UINT32  * AmlPathSizePtr
542   )
543 {
544   EFI_STATUS    Status;
545 
546   UINT32        Root;
547   UINT32        ParentPrefix;
548   UINT32        SegCount;
549 
550   if ((AmlPath == NULL) ||
551       (AmlPathSizePtr == NULL)) {
552     ASSERT (0);
553     return EFI_INVALID_PARAMETER;
554   }
555 
556   Status = AmlParseNameStringInfo (
557              AmlPath,
558              &Root,
559              &ParentPrefix,
560              &SegCount
561              );
562   if (EFI_ERROR (Status)) {
563     ASSERT (0);
564     return Status;
565   }
566 
567   *AmlPathSizePtr = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);
568   if (*AmlPathSizePtr == 0) {
569     ASSERT (0);
570     return EFI_INVALID_PARAMETER;
571   }
572 
573   return Status;
574 }
575 
576 /** Convert an ASL NameString/path to an AML NameString/path.
577     The caller must free the memory allocated in this function
578     for AmlPath using FreePool ().
579 
580   @param  [in]  AslPath     An ASL NameString/path.
581   @param  [out] OutAmlPath  Buffer containing the AML path.
582 
583   @retval EFI_SUCCESS             Success.
584   @retval EFI_INVALID_PARAMETER   Invalid parameter.
585   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
586 **/
587 EFI_STATUS
588 EFIAPI
ConvertAslNameToAmlName(IN CONST CHAR8 * AslPath,OUT CHAR8 ** OutAmlPath)589 ConvertAslNameToAmlName (
590   IN  CONST  CHAR8   * AslPath,
591   OUT        CHAR8  ** OutAmlPath
592   )
593 {
594   EFI_STATUS      Status;
595 
596   UINT32          Root;
597   UINT32          ParentPrefix;
598   UINT32          SegCount;
599   UINT32          TotalSize;
600   UINT32          NameSegSize;
601 
602   CONST CHAR8   * AslBuffer;
603   CHAR8         * AmlBuffer;
604   CHAR8         * AmlPath;
605 
606   if ((AslPath == NULL) ||
607       (OutAmlPath == NULL)) {
608     return EFI_INVALID_PARAMETER;
609   }
610 
611   // Analyze AslPath. AslPath is checked in the call.
612   Status = AslParseNameStringInfo (AslPath, &Root, &ParentPrefix, &SegCount);
613   if (EFI_ERROR (Status)) {
614     ASSERT (0);
615     return Status;
616   }
617 
618   // Compute TotalSize.
619   TotalSize = AmlComputeNameStringSize (Root, ParentPrefix, SegCount);
620   if (TotalSize == 0) {
621     ASSERT (0);
622     return EFI_INVALID_PARAMETER;
623   }
624 
625   // Allocate memory.
626   AmlPath = AllocateZeroPool (TotalSize);
627   if (AmlPath == NULL) {
628     ASSERT (0);
629     return EFI_OUT_OF_RESOURCES;
630   }
631 
632   AmlBuffer = AmlPath;
633   AslBuffer = AslPath;
634 
635   // Handle Root and ParentPrefix(s).
636   if (Root == 1) {
637     *AmlBuffer = AML_ROOT_CHAR;
638     AmlBuffer++;
639     AslBuffer++;
640   } else if (ParentPrefix > 0) {
641     SetMem (AmlBuffer, ParentPrefix, AML_PARENT_PREFIX_CHAR);
642     AmlBuffer += ParentPrefix;
643     AslBuffer += ParentPrefix;
644   }
645 
646   // Handle prefix and SegCount(s).
647   if (SegCount > 2) {
648     *AmlBuffer = AML_MULTI_NAME_PREFIX;
649     AmlBuffer++;
650     *AmlBuffer = (UINT8)SegCount;
651     AmlBuffer++;
652   } else if (SegCount == 2) {
653     *AmlBuffer = AML_DUAL_NAME_PREFIX;
654     AmlBuffer++;
655   }
656 
657   if (SegCount != 0) {
658     // Write NameSeg(s).
659     while (1) {
660       SegCount--;
661 
662       // Get the NameSeg size.
663       if (!AslIsNameSeg (AslBuffer, &NameSegSize)) {
664         ASSERT (0);
665         Status = EFI_INVALID_PARAMETER;
666         goto error_handler;
667       }
668 
669       // Convert to Upper case and copy.
670       Status = AmlUpperCaseMemCpyS (
671                  AmlBuffer,
672                  TotalSize,
673                  AslBuffer,
674                  NameSegSize
675                  );
676       if (EFI_ERROR (Status)) {
677         ASSERT (0);
678         goto error_handler;
679       }
680 
681       // Complete the NameSeg with an underscore ('_') if shorter than 4 bytes.
682       SetMem (
683         AmlBuffer + NameSegSize,
684         AML_NAME_SEG_SIZE - NameSegSize,
685         AML_NAME_CHAR__
686         );
687 
688       // Go to the next NameSeg.
689       AmlBuffer += AML_NAME_SEG_SIZE;
690       AslBuffer += NameSegSize;
691 
692       // Skip the '.' separator.
693       if (SegCount != 0) {
694         if (*AslBuffer == '.') {
695           AslBuffer++;
696         } else {
697           ASSERT (0);
698           Status = EFI_INVALID_PARAMETER;
699           goto error_handler;
700         }
701       } else {
702         // (SegCount == 0)
703         if (*AslBuffer == '\0') {
704           break;
705         } else {
706           ASSERT (0);
707           Status = EFI_INVALID_PARAMETER;
708           goto error_handler;
709         }
710       }
711     } // while
712 
713   } else {
714     // (SegCount == 0)
715     // '\0' needs to end the AML NameString/path.
716     *AmlBuffer = AML_ZERO_OP;
717     AmlBuffer++;
718   }
719 
720   // Safety checks on exit.
721   // Check that AmlPath has been filled with TotalSize bytes.
722   if ((SegCount != 0)               ||
723       (*AslBuffer != AML_ZERO_OP)   ||
724       (((UINT32)(AmlBuffer - AmlPath)) != TotalSize)) {
725       ASSERT (0);
726       Status = EFI_INVALID_PARAMETER;
727       goto error_handler;
728   }
729 
730   *OutAmlPath = AmlPath;
731   return EFI_SUCCESS;
732 
733 error_handler:
734   FreePool (AmlPath);
735   return Status;
736 }
737 
738 /** Convert an AML NameString/path to an ASL NameString/path.
739     The caller must free the memory allocated in this function.
740     using FreePool ().
741 
742   @param  [in]  AmlPath     An AML NameString/path.
743   @param  [out] OutAslPath  Buffer containing the ASL path.
744 
745   @retval EFI_SUCCESS             Success.
746   @retval EFI_INVALID_PARAMETER   Invalid parameter.
747   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
748 **/
749 EFI_STATUS
750 EFIAPI
ConvertAmlNameToAslName(IN CONST CHAR8 * AmlPath,OUT CHAR8 ** OutAslPath)751 ConvertAmlNameToAslName (
752   IN  CONST CHAR8     * AmlPath,
753   OUT       CHAR8    ** OutAslPath
754   )
755 {
756   EFI_STATUS      Status;
757 
758   UINT32          Root;
759   UINT32          ParentPrefix;
760   UINT32          SegCount;
761   UINT32          TotalSize;
762 
763   CONST CHAR8   * AmlBuffer;
764   CHAR8         * AslBuffer;
765   CHAR8         * AslPath;
766 
767   if ((AmlPath == NULL)   ||
768       (OutAslPath == NULL)) {
769     ASSERT (0);
770     return EFI_INVALID_PARAMETER;
771   }
772 
773   // Analyze AslPath. AmlPath is checked in the call.
774   Status = AmlParseNameStringInfo (AmlPath, &Root, &ParentPrefix, &SegCount);
775   if (EFI_ERROR (Status)) {
776     ASSERT (0);
777     return Status;
778   }
779 
780   // Compute TotalSize.
781   TotalSize = AslComputeNameStringSize (Root, ParentPrefix, SegCount);
782   if (TotalSize == 0) {
783     ASSERT (0);
784     return EFI_INVALID_PARAMETER;
785   }
786 
787   // Allocate memory.
788   AslPath = AllocateZeroPool (TotalSize);
789   if (AslPath == NULL) {
790     ASSERT (0);
791     return EFI_OUT_OF_RESOURCES;
792   }
793 
794   AmlBuffer = AmlPath;
795   AslBuffer = AslPath;
796 
797   // Handle prefix and SegCount(s).
798   if (Root == 1) {
799     *AslBuffer = AML_ROOT_CHAR;
800     AslBuffer++;
801     AmlBuffer++;
802   } else if (ParentPrefix > 0) {
803     SetMem (AslBuffer, ParentPrefix, AML_PARENT_PREFIX_CHAR);
804     AslBuffer += ParentPrefix;
805     AmlBuffer += ParentPrefix;
806   }
807 
808   // Handle Root and Parent(s).
809   // Skip the MultiName or DualName prefix chars.
810   if (SegCount > 2) {
811     AmlBuffer += 2;
812   } else if (SegCount == 2) {
813     AmlBuffer += 1;
814   }
815 
816   // Write NameSeg(s).
817   while (SegCount) {
818     // NameSeg is already in upper case and always 4 bytes long.
819     CopyMem (AslBuffer, AmlBuffer, AML_NAME_SEG_SIZE);
820     AslBuffer += AML_NAME_SEG_SIZE;
821     AmlBuffer += AML_NAME_SEG_SIZE;
822 
823     SegCount--;
824 
825     // Write the '.' separator if there is another NameSeg following.
826     if (SegCount != 0) {
827       *AslBuffer = '.';
828       AslBuffer++;
829     }
830   } // while
831 
832   // NULL terminate the ASL NameString.
833   *AslBuffer = '\0';
834   AslBuffer++;
835 
836   // Safety checks on exit.
837   // Check that AslPath has been filled with TotalSize bytes.
838   if (((UINT32)(AslBuffer - AslPath)) != TotalSize) {
839     ASSERT (0);
840     Status = EFI_INVALID_PARAMETER;
841     goto error_handler;
842   }
843 
844   *OutAslPath = AslPath;
845   return EFI_SUCCESS;
846 
847 error_handler:
848   FreePool (AslPath);
849   return Status;
850 }
851 
852 /** Compare two ASL NameStrings.
853 
854   @param [in] AslName1    First NameString to compare.
855   @param [in] AslName2    Second NameString to compare.
856 
857   @retval TRUE if the two strings are identical.
858   @retval FALSE otherwise, or if error.
859 **/
860 BOOLEAN
861 EFIAPI
AslCompareNameString(IN CONST CHAR8 * AslName1,IN CONST CHAR8 * AslName2)862 AslCompareNameString (
863   IN  CONST CHAR8 *   AslName1,
864   IN  CONST CHAR8 *   AslName2
865   )
866 {
867   EFI_STATUS    Status;
868   UINT32        AslName1Len;
869   UINT32        AslName2Len;
870 
871   if ((AslName1 == NULL) ||
872       (AslName2 == NULL)) {
873     ASSERT (0);
874     return FALSE;
875   }
876 
877   Status = AslGetNameStringSize (AslName1, &AslName1Len);
878   if (EFI_ERROR (Status)) {
879     ASSERT (0);
880     return FALSE;
881   }
882 
883   Status = AslGetNameStringSize (AslName2, &AslName2Len);
884   if (EFI_ERROR (Status)) {
885     ASSERT (0);
886     return FALSE;
887   }
888 
889   // AslName1 and AslName2 don't have the same length
890   if (AslName1Len != AslName2Len) {
891     return FALSE;
892   }
893 
894   return (CompareMem (AslName1, AslName2, AslName1Len) == 0);
895 }
896 
897 /** Compare two AML NameStrings.
898 
899   @param [in] AmlName1    First NameString to compare.
900   @param [in] AmlName2    Second NameString to compare.
901 
902   @retval TRUE if the two strings are identical.
903   @retval FALSE otherwise, or if error.
904 **/
905 BOOLEAN
906 EFIAPI
AmlCompareNameString(IN CONST CHAR8 * AmlName1,IN CONST CHAR8 * AmlName2)907 AmlCompareNameString (
908   IN  CONST CHAR8 *   AmlName1,
909   IN  CONST CHAR8 *   AmlName2
910   )
911 {
912   EFI_STATUS    Status;
913   UINT32        AmlName1Len;
914   UINT32        AmlName2Len;
915 
916   if ((AmlName1 == NULL) ||
917       (AmlName2 == NULL)) {
918     ASSERT (0);
919     return FALSE;
920   }
921 
922   Status = AmlGetNameStringSize (AmlName1, &AmlName1Len);
923   if (EFI_ERROR (Status)) {
924     ASSERT (0);
925     return FALSE;
926   }
927 
928   Status = AmlGetNameStringSize (AmlName2, &AmlName2Len);
929   if (EFI_ERROR (Status)) {
930     ASSERT (0);
931     return FALSE;
932   }
933 
934   // AmlName1 and AmlName2 don't have the same length
935   if (AmlName1Len != AmlName2Len) {
936     return FALSE;
937   }
938 
939   return (CompareMem (AmlName1, AmlName2, AmlName1Len) == 0);
940 }
941 
942 /** Compare an AML NameString and an ASL NameString.
943 
944   The ASL NameString is converted to an AML NameString before
945   being compared with the ASL NameString. This allows to expand
946   NameSegs shorter than 4 chars.
947   E.g.: AslName: "DEV" will be expanded to "DEV_" before being
948         compared.
949 
950   @param [in] AmlName1   AML NameString to compare.
951   @param [in] AslName2   ASL NameString to compare.
952 
953   @retval TRUE if the two strings are identical.
954   @retval FALSE otherwise, or if error.
955 **/
956 BOOLEAN
957 EFIAPI
CompareAmlWithAslNameString(IN CONST CHAR8 * AmlName1,IN CONST CHAR8 * AslName2)958 CompareAmlWithAslNameString (
959   IN  CONST CHAR8 *   AmlName1,
960   IN  CONST CHAR8 *   AslName2
961   )
962 {
963   EFI_STATUS    Status;
964 
965   CHAR8       * AmlName2;
966   BOOLEAN       RetVal;
967 
968   if ((AmlName1 == NULL) ||
969       (AslName2 == NULL)) {
970     ASSERT (0);
971     return FALSE;
972   }
973 
974   // Convert the AslName2 to an AmlName2.
975   // AmlName2 must be freed.
976   Status = ConvertAmlNameToAslName (AslName2, &AmlName2);
977   if (EFI_ERROR (Status)) {
978     ASSERT (0);
979     return FALSE;
980   }
981 
982   RetVal = AmlCompareNameString (AmlName1, AmlName2);
983 
984   // Free AmlName2.
985   FreePool (AmlName2);
986 
987   return RetVal;
988 }
989 /** Given an AmlPath, return the address of the first NameSeg.
990 
991   It is possible to determine the size of an AML NameString/path just
992   by sight reading it. So no overflow can occur.
993 
994   @param  [in]  AmlPath       The AML pathname.
995   @param  [in]  Root          The AML pathname starts with a root char.
996                               It is an absolute path.
997   @param  [in]  ParentPrefix  The AML pathname has ParentPrefix
998                               carets in its name.
999 
1000   @return Pointer to the first NameSeg of the NameString.
1001           Return NULL if AmlPath is NULL.
1002 **/
1003 CONST
1004 CHAR8 *
1005 EFIAPI
AmlGetFirstNameSeg(IN CONST CHAR8 * AmlPath,IN UINT32 Root,IN UINT32 ParentPrefix)1006 AmlGetFirstNameSeg (
1007   IN  CONST  CHAR8    * AmlPath,
1008   IN         UINT32     Root,
1009   IN         UINT32     ParentPrefix
1010   )
1011 {
1012   if (AmlPath == NULL) {
1013     ASSERT (0);
1014     return NULL;
1015   }
1016 
1017   AmlPath += Root;
1018   AmlPath += ParentPrefix;
1019   AmlPath += ((*AmlPath == AML_MULTI_NAME_PREFIX) ? 2
1020                : (*AmlPath == AML_DUAL_NAME_PREFIX) ? 1 : 0);
1021   return AmlPath;
1022 }
1023