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