ShellPkg/UefiShellAcpiViewCommandLib: Fix ECC issues
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / AcpiParser.c
1 /** @file\r
2   ACPI parser\r
3 \r
4   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.\r
5   This program and the accompanying materials\r
6   are licensed and made available under the terms and conditions of the BSD License\r
7   which accompanies this distribution.  The full text of the license may be found at\r
8   http://opensource.org/licenses/bsd-license.php\r
9 \r
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 **/\r
13 \r
14 #include <Uefi.h>\r
15 #include <Library/UefiLib.h>\r
16 #include <Library/UefiBootServicesTableLib.h>\r
17 #include "AcpiParser.h"\r
18 #include "AcpiView.h"\r
19 \r
20 STATIC UINT32   gIndent;\r
21 STATIC UINT32   mTableErrorCount;\r
22 STATIC UINT32   mTableWarningCount;\r
23 \r
24 /**\r
25   This function resets the ACPI table error counter to Zero.\r
26 **/\r
27 VOID\r
28 ResetErrorCount (\r
29   VOID\r
30   )\r
31 {\r
32   mTableErrorCount = 0;\r
33 }\r
34 \r
35 /**\r
36   This function returns the ACPI table error count.\r
37 \r
38   @retval Returns the count of errors detected in the ACPI tables.\r
39 **/\r
40 UINT32\r
41 GetErrorCount (\r
42   VOID\r
43   )\r
44 {\r
45   return mTableErrorCount;\r
46 }\r
47 \r
48 /**\r
49   This function resets the ACPI table warning counter to Zero.\r
50 **/\r
51 VOID\r
52 ResetWarningCount (\r
53   VOID\r
54   )\r
55 {\r
56   mTableWarningCount = 0;\r
57 }\r
58 \r
59 /**\r
60   This function returns the ACPI table warning count.\r
61 \r
62   @retval Returns the count of warning detected in the ACPI tables.\r
63 **/\r
64 UINT32\r
65 GetWarningCount (\r
66   VOID\r
67   )\r
68 {\r
69   return mTableWarningCount;\r
70 }\r
71 \r
72 /**\r
73   This function increments the ACPI table error counter.\r
74 **/\r
75 VOID\r
76 EFIAPI\r
77 IncrementErrorCount (\r
78   VOID\r
79   )\r
80 {\r
81   mTableErrorCount++;\r
82 }\r
83 \r
84 /**\r
85   This function increments the ACPI table warning counter.\r
86 **/\r
87 VOID\r
88 EFIAPI\r
89 IncrementWarningCount (\r
90   VOID\r
91   )\r
92 {\r
93   mTableWarningCount++;\r
94 }\r
95 \r
96 /**\r
97   This function verifies the ACPI table checksum.\r
98 \r
99   This function verifies the checksum for the ACPI table and optionally\r
100   prints the status.\r
101 \r
102   @param [in] Log     If TRUE log the status of the checksum.\r
103   @param [in] Ptr     Pointer to the start of the table buffer.\r
104   @param [in] Length  The length of the buffer.\r
105 \r
106   @retval TRUE        The checksum is OK.\r
107   @retval FALSE       The checksum failed.\r
108 **/\r
109 BOOLEAN\r
110 EFIAPI\r
111 VerifyChecksum (\r
112   IN BOOLEAN Log,\r
113   IN UINT8*  Ptr,\r
114   IN UINT32  Length\r
115   )\r
116 {\r
117   UINTN ByteCount = 0;\r
118   UINT8 Checksum = 0;\r
119   UINTN OriginalAttribute;\r
120 \r
121   while (ByteCount < Length) {\r
122     Checksum += *(Ptr++);\r
123     ByteCount++;\r
124   }\r
125 \r
126   if (Log) {\r
127     OriginalAttribute = gST->ConOut->Mode->Attribute;\r
128     if (Checksum == 0) {\r
129       if (GetColourHighlighting ()) {\r
130         gST->ConOut->SetAttribute (\r
131                        gST->ConOut,\r
132                        EFI_TEXT_ATTR (EFI_GREEN,\r
133                          ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))\r
134                        );\r
135       }\r
136       Print (L"\n\nTable Checksum : OK\n\n");\r
137     } else {\r
138       IncrementErrorCount ();\r
139       if (GetColourHighlighting ()) {\r
140         gST->ConOut->SetAttribute (\r
141                        gST->ConOut,\r
142                        EFI_TEXT_ATTR (EFI_RED,\r
143                          ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))\r
144                        );\r
145       }\r
146       Print (L"\n\nTable Checksum : FAILED (0x%X)\n\n", Checksum);\r
147     }\r
148     if (GetColourHighlighting ()) {\r
149       gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);\r
150     }\r
151   }\r
152 \r
153   return (Checksum == 0);\r
154 }\r
155 \r
156 /**\r
157   This function performs a raw data dump of the ACPI table.\r
158 \r
159   @param [in] Ptr     Pointer to the start of the table buffer.\r
160   @param [in] Length  The length of the buffer.\r
161 **/\r
162 VOID\r
163 EFIAPI\r
164 DumpRaw (\r
165   IN UINT8* Ptr,\r
166   IN UINT32 Length\r
167   )\r
168 {\r
169   UINTN ByteCount = 0;\r
170   UINTN PartLineChars;\r
171   UINTN AsciiBufferIndex = 0;\r
172   CHAR8 AsciiBuffer[17];\r
173 \r
174   Print (L"Address  : 0x%p\n", Ptr);\r
175   Print (L"Length   : %d\n", Length);\r
176 \r
177   while (ByteCount < Length) {\r
178     if ((ByteCount & 0x0F) == 0) {\r
179       AsciiBuffer[AsciiBufferIndex] = '\0';\r
180       Print (L"  %a\n%08X : ", AsciiBuffer, ByteCount);\r
181       AsciiBufferIndex = 0;\r
182     } else if ((ByteCount & 0x07) == 0) {\r
183       Print (L"- ");\r
184     }\r
185 \r
186     if ((*Ptr >= ' ') && (*Ptr < 0x7F)) {\r
187       AsciiBuffer[AsciiBufferIndex++] = *Ptr;\r
188     } else {\r
189       AsciiBuffer[AsciiBufferIndex++] = '.';\r
190     }\r
191 \r
192     Print (L"%02X ", *Ptr++);\r
193 \r
194     ByteCount++;\r
195   }\r
196 \r
197   // Justify the final line using spaces before printing\r
198   // the ASCII data.\r
199   PartLineChars = (Length & 0x0F);\r
200   if (PartLineChars != 0) {\r
201     PartLineChars = 48 - (PartLineChars * 3);\r
202     if ((Length & 0x0F) <= 8) {\r
203       PartLineChars += 2;\r
204     }\r
205     while (PartLineChars > 0) {\r
206       Print (L" ");\r
207       PartLineChars--;\r
208     }\r
209   }\r
210 \r
211   // Print ASCII data for the final line.\r
212   AsciiBuffer[AsciiBufferIndex] = '\0';\r
213   Print (L"  %a", AsciiBuffer);\r
214 }\r
215 \r
216 /**\r
217   This function traces 1 byte of data as specified in the format string.\r
218 \r
219   @param [in] Format  The format string for tracing the data.\r
220   @param [in] Ptr     Pointer to the start of the buffer.\r
221 **/\r
222 VOID\r
223 EFIAPI\r
224 DumpUint8 (\r
225   IN CONST CHAR16* Format,\r
226   IN UINT8*        Ptr\r
227   )\r
228 {\r
229   Print (Format, *Ptr);\r
230 }\r
231 \r
232 /**\r
233   This function traces 2 bytes of data as specified in the format string.\r
234 \r
235   @param [in] Format  The format string for tracing the data.\r
236   @param [in] Ptr     Pointer to the start of the buffer.\r
237 **/\r
238 VOID\r
239 EFIAPI\r
240 DumpUint16 (\r
241   IN CONST CHAR16* Format,\r
242   IN UINT8*        Ptr\r
243   )\r
244 {\r
245   Print (Format, *(UINT16*)Ptr);\r
246 }\r
247 \r
248 /**\r
249   This function traces 4 bytes of data as specified in the format string.\r
250 \r
251   @param [in] Format  The format string for tracing the data.\r
252   @param [in] Ptr     Pointer to the start of the buffer.\r
253 **/\r
254 VOID\r
255 EFIAPI\r
256 DumpUint32 (\r
257   IN CONST CHAR16* Format,\r
258   IN UINT8*        Ptr\r
259   )\r
260 {\r
261   Print (Format, *(UINT32*)Ptr);\r
262 }\r
263 \r
264 /**\r
265   This function traces 8 bytes of data as specified by the format string.\r
266 \r
267   @param [in] Format  The format string for tracing the data.\r
268   @param [in] Ptr     Pointer to the start of the buffer.\r
269 **/\r
270 VOID\r
271 EFIAPI\r
272 DumpUint64 (\r
273   IN CONST CHAR16* Format,\r
274   IN UINT8*        Ptr\r
275   )\r
276 {\r
277   // Some fields are not aligned and this causes alignment faults\r
278   // on ARM platforms if the compiler generates LDRD instructions.\r
279   // Perform word access so that LDRD instructions are not generated.\r
280   UINT64 Val = *(UINT32*)(Ptr + sizeof (UINT32));\r
281   Val <<= 32;\r
282   Val |= *(UINT32*)Ptr;\r
283 \r
284   Print (Format, Val);\r
285 }\r
286 \r
287 /**\r
288   This function traces 3 characters which can be optionally\r
289   formated using the format string if specified.\r
290 \r
291   If no format string is specified the Format must be NULL.\r
292 \r
293   @param [in] Format  Optional format string for tracing the data.\r
294   @param [in] Ptr     Pointer to the start of the buffer.\r
295 **/\r
296 VOID\r
297 EFIAPI\r
298 Dump3Chars (\r
299   IN CONST CHAR16* Format OPTIONAL,\r
300   IN UINT8*        Ptr\r
301   )\r
302 {\r
303   Print (\r
304     (Format != NULL) ? Format : L"%c%c%c",\r
305     Ptr[0],\r
306     Ptr[1],\r
307     Ptr[2]\r
308     );\r
309 }\r
310 \r
311 /**\r
312   This function traces 4 characters which can be optionally\r
313   formated using the format string if specified.\r
314 \r
315   If no format string is specified the Format must be NULL.\r
316 \r
317   @param [in] Format  Optional format string for tracing the data.\r
318   @param [in] Ptr     Pointer to the start of the buffer.\r
319 **/\r
320 VOID\r
321 EFIAPI\r
322 Dump4Chars (\r
323   IN CONST CHAR16* Format OPTIONAL,\r
324   IN UINT8*        Ptr\r
325   )\r
326 {\r
327   Print (\r
328     (Format != NULL) ? Format : L"%c%c%c%c",\r
329     Ptr[0],\r
330     Ptr[1],\r
331     Ptr[2],\r
332     Ptr[3]\r
333     );\r
334 }\r
335 \r
336 /**\r
337   This function traces 6 characters which can be optionally\r
338   formated using the format string if specified.\r
339 \r
340   If no format string is specified the Format must be NULL.\r
341 \r
342   @param [in] Format  Optional format string for tracing the data.\r
343   @param [in] Ptr     Pointer to the start of the buffer.\r
344 **/\r
345 VOID\r
346 EFIAPI\r
347 Dump6Chars (\r
348   IN CONST CHAR16* Format OPTIONAL,\r
349   IN UINT8*        Ptr\r
350   )\r
351 {\r
352   Print (\r
353     (Format != NULL) ? Format : L"%c%c%c%c%c%c",\r
354     Ptr[0],\r
355     Ptr[1],\r
356     Ptr[2],\r
357     Ptr[3],\r
358     Ptr[4],\r
359     Ptr[5]\r
360     );\r
361 }\r
362 \r
363 /**\r
364   This function traces 8 characters which can be optionally\r
365   formated using the format string if specified.\r
366 \r
367   If no format string is specified the Format must be NULL.\r
368 \r
369   @param [in] Format  Optional format string for tracing the data.\r
370   @param [in] Ptr     Pointer to the start of the buffer.\r
371 **/\r
372 VOID\r
373 EFIAPI\r
374 Dump8Chars (\r
375   IN CONST CHAR16* Format OPTIONAL,\r
376   IN UINT8*        Ptr\r
377   )\r
378 {\r
379   Print (\r
380     (Format != NULL) ? Format : L"%c%c%c%c%c%c%c%c",\r
381     Ptr[0],\r
382     Ptr[1],\r
383     Ptr[2],\r
384     Ptr[3],\r
385     Ptr[4],\r
386     Ptr[5],\r
387     Ptr[6],\r
388     Ptr[7]\r
389     );\r
390 }\r
391 \r
392 /**\r
393   This function indents and prints the ACPI table Field Name.\r
394 \r
395   @param [in] Indent      Number of spaces to add to the global table indent.\r
396                           The global table indent is 0 by default; however\r
397                           this value is updated on entry to the ParseAcpi()\r
398                           by adding the indent value provided to ParseAcpi()\r
399                           and restored back on exit.\r
400                           Therefore the total indent in the output is\r
401                           dependent on from where this function is called.\r
402   @param [in] FieldName   Pointer to the Field Name.\r
403 **/\r
404 VOID\r
405 EFIAPI\r
406 PrintFieldName (\r
407   IN UINT32         Indent,\r
408   IN CONST CHAR16*  FieldName\r
409 )\r
410 {\r
411   Print (\r
412     L"%*a%-*s : ",\r
413     gIndent + Indent,\r
414     "",\r
415     (OUTPUT_FIELD_COLUMN_WIDTH - gIndent - Indent),\r
416     FieldName\r
417     );\r
418 }\r
419 \r
420 /**\r
421   This function is used to parse an ACPI table buffer.\r
422 \r
423   The ACPI table buffer is parsed using the ACPI table parser information\r
424   specified by a pointer to an array of ACPI_PARSER elements. This parser\r
425   function iterates through each item on the ACPI_PARSER array and logs the\r
426   ACPI table fields.\r
427 \r
428   This function can optionally be used to parse ACPI tables and fetch specific\r
429   field values. The ItemPtr member of the ACPI_PARSER structure (where used)\r
430   is updated by this parser function to point to the selected field data\r
431   (e.g. useful for variable length nested fields).\r
432 \r
433   @param [in] Trace        Trace the ACPI fields TRUE else only parse the\r
434                            table.\r
435   @param [in] Indent       Number of spaces to indent the output.\r
436   @param [in] AsciiName    Optional pointer to an ASCII string that describes\r
437                            the table being parsed.\r
438   @param [in] Ptr          Pointer to the start of the buffer.\r
439   @param [in] Length       Length of the buffer pointed by Ptr.\r
440   @param [in] Parser       Pointer to an array of ACPI_PARSER structure that\r
441                            describes the table being parsed.\r
442   @param [in] ParserItems  Number of items in the ACPI_PARSER array.\r
443 \r
444   @retval Number of bytes parsed.\r
445 **/\r
446 UINT32\r
447 EFIAPI\r
448 ParseAcpi (\r
449   IN BOOLEAN            Trace,\r
450   IN UINT32             Indent,\r
451   IN CONST CHAR8*       AsciiName OPTIONAL,\r
452   IN UINT8*             Ptr,\r
453   IN UINT32             Length,\r
454   IN CONST ACPI_PARSER* Parser,\r
455   IN UINT32             ParserItems\r
456 )\r
457 {\r
458   UINT32  Index;\r
459   UINT32  Offset = 0;\r
460 \r
461   // Increment the Indent\r
462   gIndent += Indent;\r
463 \r
464   if (Trace && (AsciiName != NULL)){\r
465     BOOLEAN HighLight = GetColourHighlighting ();\r
466     UINTN   OriginalAttribute;\r
467 \r
468     if (HighLight) {\r
469       OriginalAttribute = gST->ConOut->Mode->Attribute;\r
470       gST->ConOut->SetAttribute (\r
471                      gST->ConOut,\r
472                      EFI_TEXT_ATTR(EFI_YELLOW,\r
473                        ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))\r
474                      );\r
475     }\r
476     Print (\r
477       L"%*a%-*a :\n",\r
478       gIndent,\r
479       "",\r
480       (OUTPUT_FIELD_COLUMN_WIDTH - gIndent),\r
481       AsciiName\r
482       );\r
483     if (HighLight) {\r
484       gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);\r
485     }\r
486   }\r
487 \r
488   for (Index = 0; Index < ParserItems; Index++) {\r
489     if ((Offset + Parser[Index].Length) > Length) {\r
490       // We don't parse past the end of the max length specified\r
491       break;\r
492     }\r
493 \r
494     if (Offset != Parser[Index].Offset) {\r
495       IncrementErrorCount ();\r
496       Print (\r
497         L"\nERROR: %a: Offset Mismatch for %s\n"\r
498           "CurrentOffset = %d FieldOffset = %d\n",\r
499         AsciiName,\r
500         Parser[Index].NameStr,\r
501         Offset,\r
502         Parser[Index].Offset\r
503         );\r
504     }\r
505 \r
506     if (Trace) {\r
507       // if there is a Formatter function let the function handle\r
508       // the printing else if a Format is specified in the table use\r
509       // the Format for printing\r
510       PrintFieldName (2, Parser[Index].NameStr);\r
511       if (Parser[Index].PrintFormatter != NULL) {\r
512         Parser[Index].PrintFormatter (Parser[Index].Format, Ptr);\r
513       } else if (Parser[Index].Format != NULL) {\r
514         switch (Parser[Index].Length) {\r
515           case 1:\r
516             DumpUint8 (Parser[Index].Format, Ptr);\r
517             break;\r
518           case 2:\r
519             DumpUint16 (Parser[Index].Format, Ptr);\r
520             break;\r
521           case 4:\r
522             DumpUint32 (Parser[Index].Format, Ptr);\r
523             break;\r
524           case 8:\r
525             DumpUint64 (Parser[Index].Format, Ptr);\r
526             break;\r
527           default:\r
528             Print (\r
529               L"\nERROR: %a: CANNOT PARSE THIS FIELD, Field Length = %d\n",\r
530               AsciiName,\r
531               Parser[Index].Length\r
532               );\r
533         } // switch\r
534 \r
535         // Validating only makes sense if we are tracing\r
536         // the parsed table entries, to report by table name.\r
537         if (Parser[Index].FieldValidator != NULL) {\r
538           Parser[Index].FieldValidator (Ptr, Parser[Index].Context);\r
539         }\r
540       }\r
541       Print (L"\n");\r
542     } // if (Trace)\r
543 \r
544     if (Parser[Index].ItemPtr != NULL) {\r
545       *Parser[Index].ItemPtr = (VOID*)Ptr;\r
546     }\r
547 \r
548     Ptr += Parser[Index].Length;\r
549     Offset += Parser[Index].Length;\r
550   } // for\r
551 \r
552   // Decrement the Indent\r
553   gIndent -= Indent;\r
554   return Offset;\r
555 }\r
556 \r
557 /**\r
558   An array describing the ACPI Generic Address Structure.\r
559   The GasParser array is used by the ParseAcpi function to parse and/or trace\r
560   the GAS structure.\r
561 **/\r
562 STATIC CONST ACPI_PARSER GasParser[] = {\r
563   {L"Address Space ID", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r
564   {L"Register Bit Width", 1, 1, L"0x%x", NULL, NULL, NULL, NULL},\r
565   {L"Register Bit Offset", 1, 2, L"0x%x", NULL, NULL, NULL, NULL},\r
566   {L"Address Size", 1, 3, L"0x%x", NULL, NULL, NULL, NULL},\r
567   {L"Address", 8, 4, L"0x%lx", NULL, NULL, NULL, NULL}\r
568 };\r
569 \r
570 /**\r
571   This function indents and traces the GAS structure as described by the GasParser.\r
572 \r
573   @param [in] Ptr     Pointer to the start of the buffer.\r
574   @param [in] Indent  Number of spaces to indent the output.\r
575 **/\r
576 VOID\r
577 EFIAPI\r
578 DumpGasStruct (\r
579   IN UINT8*        Ptr,\r
580   IN UINT32        Indent\r
581   )\r
582 {\r
583   Print (L"\n");\r
584   ParseAcpi (\r
585     TRUE,\r
586     Indent,\r
587     NULL,\r
588     Ptr,\r
589     GAS_LENGTH,\r
590     PARSER_PARAMS (GasParser)\r
591     );\r
592 }\r
593 \r
594 /**\r
595   This function traces the GAS structure as described by the GasParser.\r
596 \r
597   @param [in] Format  Optional format string for tracing the data.\r
598   @param [in] Ptr     Pointer to the start of the buffer.\r
599 **/\r
600 VOID\r
601 EFIAPI\r
602 DumpGas (\r
603   IN CONST CHAR16* Format OPTIONAL,\r
604   IN UINT8*        Ptr\r
605   )\r
606 {\r
607   DumpGasStruct (Ptr, 2);\r
608 }\r
609 \r
610 /**\r
611   This function traces the ACPI header as described by the AcpiHeaderParser.\r
612 \r
613   @param [in] Ptr          Pointer to the start of the buffer.\r
614 \r
615   @retval Number of bytes parsed.\r
616 **/\r
617 UINT32\r
618 EFIAPI\r
619 DumpAcpiHeader (\r
620   IN UINT8* Ptr\r
621   )\r
622 {\r
623   ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
624   ACPI_PARSER AcpiHeaderParser[] = {\r
625     PARSE_ACPI_HEADER (&AcpiHdrInfo)\r
626   };\r
627 \r
628   return ParseAcpi (\r
629            TRUE,\r
630            0,\r
631            "ACPI Table Header",\r
632            Ptr,\r
633            ACPI_DESCRIPTION_HEADER_LENGTH,\r
634            PARSER_PARAMS (AcpiHeaderParser)\r
635            );\r
636 }\r
637 \r
638 /**\r
639   This function parses the ACPI header as described by the AcpiHeaderParser.\r
640 \r
641   This function optionally returns the signature, length and revision of the\r
642   ACPI table.\r
643 \r
644   @param [in]  Ptr        Pointer to the start of the buffer.\r
645   @param [out] Signature  Gets location of the ACPI table signature.\r
646   @param [out] Length     Gets location of the length of the ACPI table.\r
647   @param [out] Revision   Gets location of the revision of the ACPI table.\r
648 \r
649   @retval Number of bytes parsed.\r
650 **/\r
651 UINT32\r
652 EFIAPI\r
653 ParseAcpiHeader (\r
654   IN  UINT8*         Ptr,\r
655   OUT CONST UINT32** Signature,\r
656   OUT CONST UINT32** Length,\r
657   OUT CONST UINT8**  Revision\r
658   )\r
659 {\r
660   UINT32                        BytesParsed;\r
661   ACPI_DESCRIPTION_HEADER_INFO  AcpiHdrInfo;\r
662   ACPI_PARSER AcpiHeaderParser[] = {\r
663     PARSE_ACPI_HEADER (&AcpiHdrInfo)\r
664   };\r
665 \r
666   BytesParsed = ParseAcpi (\r
667                   FALSE,\r
668                   0,\r
669                   NULL,\r
670                   Ptr,\r
671                   ACPI_DESCRIPTION_HEADER_LENGTH,\r
672                   PARSER_PARAMS (AcpiHeaderParser)\r
673                   );\r
674 \r
675   *Signature = AcpiHdrInfo.Signature;\r
676   *Length = AcpiHdrInfo.Length;\r
677   *Revision = AcpiHdrInfo.Revision;\r
678 \r
679   return BytesParsed;\r
680 }\r