ShellPkg: Add acpiview tool to dump ACPI tables
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / AcpiView.c
1 /**\r
2 \r
3   Copyright (c) 2016 - 2018, ARM Limited. All rights reserved.\r
4   This program and the accompanying materials\r
5   are licensed and made available under the terms and conditions of the BSD License\r
6   which accompanies this distribution.  The full text of the license may be found at\r
7   http://opensource.org/licenses/bsd-license.php\r
8 \r
9   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 **/\r
12 \r
13 #include <Library/PrintLib.h>\r
14 #include <Library/UefiLib.h>\r
15 #include <Library/ShellLib.h>\r
16 #include <Library/UefiBootServicesTableLib.h>\r
17 #include <Library/BaseMemoryLib.h>\r
18 #include <Library/DebugLib.h>\r
19 #include <Library/MemoryAllocationLib.h>\r
20 #include "AcpiParser.h"\r
21 #include "AcpiTableParser.h"\r
22 #include "AcpiView.h"\r
23 #include "UefiShellAcpiViewCommandLib.h"\r
24 \r
25 EFI_HII_HANDLE gShellAcpiViewHiiHandle = NULL;\r
26 \r
27 // Report variables\r
28 STATIC UINT32             mSelectedAcpiTable;\r
29 STATIC CONST CHAR16*      mSelectedAcpiTableName;\r
30 STATIC BOOLEAN            mSelectedAcpiTableFound;\r
31 STATIC EREPORT_OPTION     mReportType;\r
32 STATIC UINT32             mTableCount;\r
33 STATIC UINT32             mBinTableCount;\r
34 STATIC BOOLEAN            mVerbose;\r
35 STATIC BOOLEAN            mConsistencyCheck;\r
36 STATIC BOOLEAN            mColourHighlighting;\r
37 \r
38 /** An array of acpiview command line parameters.\r
39 */\r
40 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
41   {L"/?", TypeFlag},\r
42   {L"-c", TypeFlag},\r
43   {L"-d", TypeFlag},\r
44   {L"-h", TypeValue},\r
45   {L"-l", TypeFlag},\r
46   {L"-s", TypeValue},\r
47   {L"-v", TypeFlag},\r
48   {NULL, TypeMax}\r
49 };\r
50 \r
51 /** This function returns the colour highlighting status.\r
52 \r
53   @retval TRUE if colour highlighting is enabled.\r
54 */\r
55 BOOLEAN\r
56 GetColourHighlighting (\r
57   VOID\r
58   )\r
59 {\r
60   return mColourHighlighting;\r
61 }\r
62 \r
63 /** This function sets the colour highlighting status.\r
64 \r
65 */\r
66 VOID\r
67 SetColourHighlighting (\r
68   BOOLEAN Highlight\r
69   )\r
70 {\r
71   mColourHighlighting = Highlight;\r
72 }\r
73 \r
74 /** This function returns the report options.\r
75 \r
76   @retval Returns the report option.\r
77 */\r
78 STATIC\r
79 EREPORT_OPTION\r
80 GetReportOption (\r
81   VOID\r
82   )\r
83 {\r
84   return mReportType;\r
85 }\r
86 \r
87 /** This function returns the selected ACPI table.\r
88 \r
89   @retval Returns signature of the selected ACPI table.\r
90 */\r
91 STATIC\r
92 UINT32\r
93 GetSelectedAcpiTable (\r
94   VOID\r
95   )\r
96 {\r
97   return mSelectedAcpiTable;\r
98 }\r
99 \r
100 /** This function dumps the ACPI table to a file.\r
101   @param [in] Ptr       Pointer to the ACPI table data.\r
102   @param [in] Length    The length of the ACPI table.\r
103 \r
104   @retval TRUE          Success.\r
105   @retval FALSE         Failure.\r
106 */\r
107 STATIC\r
108 BOOLEAN\r
109 DumpAcpiTableToFile (\r
110   IN CONST UINT8*  Ptr,\r
111   IN CONST UINTN   Length\r
112   )\r
113 {\r
114   EFI_STATUS         Status;\r
115   CHAR16             FileNameBuffer[MAX_FILE_NAME_LEN];\r
116   SHELL_FILE_HANDLE  DumpFileHandle = NULL;\r
117   UINTN              TransferBytes = Length;\r
118 \r
119   UnicodeSPrint (\r
120     FileNameBuffer,\r
121     sizeof (FileNameBuffer),\r
122     L".\\%s%04d.bin",\r
123     mSelectedAcpiTableName,\r
124     mBinTableCount++\r
125     );\r
126 \r
127   Status = ShellOpenFileByName (\r
128              FileNameBuffer,\r
129              &DumpFileHandle,\r
130              EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE,\r
131              0\r
132              );\r
133   if (EFI_ERROR (Status)) {\r
134     ShellPrintHiiEx (\r
135       -1,\r
136       -1,\r
137       NULL,\r
138       STRING_TOKEN (STR_GEN_READONLY_MEDIA),\r
139       gShellAcpiViewHiiHandle,\r
140       L"acpiview"\r
141       );\r
142     return FALSE;\r
143   }\r
144 \r
145   Print (L"Dumping ACPI table to : %s ... ", FileNameBuffer);\r
146 \r
147   Status = ShellWriteFile (\r
148              DumpFileHandle,\r
149              &TransferBytes,\r
150              (VOID*)Ptr\r
151              );\r
152   if (EFI_ERROR (Status)) {\r
153     Print (L"ERROR: Failed to dump table to binary file.\n");\r
154     TransferBytes = 0;\r
155   } else {\r
156     Print (L"DONE.\n");\r
157   }\r
158 \r
159   ShellCloseFile (&DumpFileHandle);\r
160   return (Length == TransferBytes);\r
161 }\r
162 \r
163 /** This function processes the table reporting options for the ACPI table.\r
164 \r
165   @param [in] Signature The ACPI table Signature.\r
166   @param [in] TablePtr  Pointer to the ACPI table data.\r
167   @param [in] Length    The length fo the ACPI table.\r
168 \r
169   @retval Returns TRUE if the ACPI table should be traced.\r
170 */\r
171 BOOLEAN\r
172 ProcessTableReportOptions (\r
173   IN CONST UINT32  Signature,\r
174   IN CONST UINT8*  TablePtr,\r
175   IN CONST UINT32  Length\r
176   )\r
177 {\r
178   UINTN   OriginalAttribute;\r
179   UINT8*  SignaturePtr = (UINT8*)(UINTN)&Signature;\r
180   BOOLEAN Log = FALSE;\r
181   BOOLEAN HighLight = GetColourHighlighting ();\r
182   switch (GetReportOption ()) {\r
183     case EREPORT_ALL:\r
184       Log = TRUE;\r
185       break;\r
186     case EREPORT_SELECTED:\r
187       if (Signature == GetSelectedAcpiTable ()) {\r
188         Log = TRUE;\r
189         mSelectedAcpiTableFound = TRUE;\r
190       }\r
191       break;\r
192     case EREPORT_TABLE_LIST:\r
193       if (mTableCount == 0) {\r
194         if (HighLight) {\r
195           OriginalAttribute = gST->ConOut->Mode->Attribute;\r
196           gST->ConOut->SetAttribute (\r
197                          gST->ConOut,\r
198                          EFI_TEXT_ATTR(EFI_CYAN,\r
199                            ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))\r
200                          );\r
201         }\r
202         Print (L"\nInstalled Table(s):\n");\r
203         if (HighLight) {\r
204           gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);\r
205         }\r
206       }\r
207       Print (\r
208         L"\t%4d. %c%c%c%c\n",\r
209         ++mTableCount,\r
210         SignaturePtr[0],\r
211         SignaturePtr[1],\r
212         SignaturePtr[2],\r
213         SignaturePtr[3]\r
214         );\r
215       break;\r
216     case EREPORT_DUMP_BIN_FILE:\r
217       if (Signature == GetSelectedAcpiTable ()) {\r
218         mSelectedAcpiTableFound = TRUE;\r
219         DumpAcpiTableToFile (TablePtr, Length);\r
220       }\r
221       break;\r
222     case EREPORT_MAX:\r
223       // We should never be here.\r
224       // This case is only present to prevent compiler warning.\r
225       break;\r
226   } // switch\r
227 \r
228   if (Log) {\r
229     if (HighLight) {\r
230       OriginalAttribute = gST->ConOut->Mode->Attribute;\r
231       gST->ConOut->SetAttribute (\r
232                      gST->ConOut,\r
233                      EFI_TEXT_ATTR(EFI_LIGHTBLUE,\r
234                        ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4))\r
235                      );\r
236     }\r
237     Print (\r
238       L"\n\n --------------- %c%c%c%c Table --------------- \n\n",\r
239       SignaturePtr[0],\r
240       SignaturePtr[1],\r
241       SignaturePtr[2],\r
242       SignaturePtr[3]\r
243       );\r
244     if (HighLight) {\r
245       gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);\r
246     }\r
247   }\r
248 \r
249   return Log;\r
250 }\r
251 \r
252 /** This function converts a string to ACPI table signature.\r
253 \r
254   @param [in] Str   Pointer to the string to be converted to the\r
255                     ACPI table signature.\r
256 \r
257   @retval The ACPI table signature.\r
258 */\r
259 STATIC\r
260 UINT32\r
261 ConvertStrToAcpiSignature (\r
262   IN  CONST CHAR16* Str\r
263   )\r
264 {\r
265   UINT8 Index = 0;\r
266   CHAR8 Ptr[4];\r
267 \r
268   // Convert to Upper case and convert to ASCII\r
269   while ((Index < 4) && (Str[Index] != 0)) {\r
270     if (Str[Index] >= L'a' && Str[Index] <= L'z') {\r
271       Ptr[Index] = (CHAR8)(Str[Index] - (L'a' - L'A'));\r
272     } else {\r
273       Ptr[Index] = (CHAR8)Str[Index];\r
274     }\r
275     Index++;\r
276   }\r
277   return *(UINT32*)Ptr;\r
278 }\r
279 \r
280 /** This function iterates the configuration table entries in the\r
281     system table, retrieves the RSDP pointer and starts parsing\r
282     the ACPI tables.\r
283 \r
284   @param [in] SystemTable Pointer to the EFI system table.\r
285 \r
286   @retval Returns EFI_NOT_FOUND   if the RSDP pointer is not found.\r
287           Returns EFI_UNSUPPORTED if the RSDP version is less than 2.\r
288           Returns EFI_SUCCESS     if successful.\r
289 */\r
290 STATIC\r
291 EFI_STATUS\r
292 EFIAPI\r
293 AcpiView (\r
294   IN EFI_SYSTEM_TABLE* SystemTable\r
295   )\r
296 {\r
297   EFI_STATUS               Status;\r
298   UINTN                    Index;\r
299   EFI_CONFIGURATION_TABLE* EfiConfigurationTable;\r
300   BOOLEAN                  FoundAcpiTable;\r
301   UINTN                    OriginalAttribute;\r
302   UINTN                    PrintAttribute;\r
303   EREPORT_OPTION           ReportOption;\r
304   UINT8*                   RsdpPtr;\r
305   UINT32                   RsdpLength;\r
306   UINT8                    RsdpRevision;\r
307   PARSE_ACPI_TABLE_PROC    RsdpParserProc;\r
308   BOOLEAN                  Trace;\r
309 \r
310   // Search the table for an entry that matches the ACPI Table Guid\r
311   FoundAcpiTable = FALSE;\r
312   for (Index = 0; Index < SystemTable->NumberOfTableEntries; Index++) {\r
313     if (CompareGuid (&gEfiAcpiTableGuid,\r
314           &(SystemTable->ConfigurationTable[Index].VendorGuid))) {\r
315       EfiConfigurationTable = &SystemTable->ConfigurationTable[Index];\r
316       FoundAcpiTable = TRUE;\r
317       break;\r
318     }\r
319   }\r
320 \r
321   if (FoundAcpiTable) {\r
322     RsdpPtr = (UINT8*)EfiConfigurationTable->VendorTable;\r
323 \r
324     // The RSDP revision is 1 byte starting at offset 15\r
325     RsdpRevision = *(RsdpPtr + RSDP_REVISION_OFFSET);\r
326 \r
327     if (RsdpRevision < 2) {\r
328       Print (\r
329         L"ERROR: RSDP version less than 2 is not supported.\n"\r
330         );\r
331       return EFI_UNSUPPORTED;\r
332     }\r
333 \r
334     // The RSDP length is 4 bytes starting at offset 20\r
335     RsdpLength = *(UINT32*)(RsdpPtr + RSDP_LENGTH_OFFSET);\r
336 \r
337     Trace = ProcessTableReportOptions (RSDP_TABLE_INFO, RsdpPtr, RsdpLength);\r
338 \r
339     Status = GetParser (RSDP_TABLE_INFO, &RsdpParserProc);\r
340     if (EFI_ERROR (Status)) {\r
341       Print (\r
342         L"ERROR: No registered parser found for RSDP.\n"\r
343         );\r
344       return Status;\r
345     }\r
346 \r
347     RsdpParserProc (\r
348       Trace,\r
349       RsdpPtr,\r
350       RsdpLength,\r
351       RsdpRevision\r
352       );\r
353 \r
354   } else {\r
355     IncrementErrorCount ();\r
356     Print (\r
357       L"ERROR: Failed to find ACPI Table Guid in System Configuration Table.\n"\r
358       );\r
359     return EFI_NOT_FOUND;\r
360   }\r
361 \r
362   ReportOption = GetReportOption ();\r
363   if (EREPORT_TABLE_LIST != ReportOption) {\r
364     if (((EREPORT_SELECTED == ReportOption)  ||\r
365          (EREPORT_DUMP_BIN_FILE == ReportOption)) &&\r
366         (!mSelectedAcpiTableFound)) {\r
367       Print (L"\nRequested ACPI Table not found.\n");\r
368     } else if (EREPORT_DUMP_BIN_FILE != ReportOption) {\r
369       OriginalAttribute = gST->ConOut->Mode->Attribute;\r
370 \r
371       Print (L"\nTable Statistics:\n");\r
372 \r
373       if (GetColourHighlighting ()) {\r
374         PrintAttribute = (GetErrorCount () > 0) ?\r
375                             EFI_TEXT_ATTR (\r
376                               EFI_RED,\r
377                               ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)\r
378                               ) :\r
379                             OriginalAttribute;\r
380         gST->ConOut->SetAttribute (gST->ConOut, PrintAttribute);\r
381       }\r
382       Print (L"\t%d Error(s)\n", GetErrorCount ());\r
383 \r
384       if (GetColourHighlighting ()) {\r
385         PrintAttribute = (GetWarningCount () > 0) ?\r
386                             EFI_TEXT_ATTR (\r
387                               EFI_RED,\r
388                               ((OriginalAttribute&(BIT4|BIT5|BIT6))>>4)\r
389                               ) :\r
390                             OriginalAttribute;\r
391 \r
392         gST->ConOut->SetAttribute (gST->ConOut, PrintAttribute);\r
393       }\r
394       Print (L"\t%d Warning(s)\n", GetWarningCount ());\r
395 \r
396       if (GetColourHighlighting ()) {\r
397         gST->ConOut->SetAttribute (gST->ConOut, OriginalAttribute);\r
398       }\r
399     }\r
400   }\r
401   return EFI_SUCCESS;\r
402 }\r
403 \r
404 /**\r
405   Function for 'acpiview' command.\r
406 \r
407   @param[in] ImageHandle  Handle to the Image (NULL if Internal).\r
408   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).\r
409 */\r
410 SHELL_STATUS\r
411 EFIAPI\r
412 ShellCommandRunAcpiView (\r
413   IN EFI_HANDLE        ImageHandle,\r
414   IN EFI_SYSTEM_TABLE* SystemTable\r
415   )\r
416 {\r
417   EFI_STATUS         Status;\r
418   SHELL_STATUS       ShellStatus = SHELL_SUCCESS;\r
419   LIST_ENTRY*        Package = NULL;\r
420   CHAR16*            ProblemParam;\r
421   CONST CHAR16*      Temp;\r
422   CHAR8              ColourOption[8];\r
423   SHELL_FILE_HANDLE  TmpDumpFileHandle = NULL;\r
424 \r
425   // Set Defaults\r
426   mReportType = EREPORT_ALL;\r
427   mTableCount = 0;\r
428   mBinTableCount = 0;\r
429   mSelectedAcpiTable = 0;\r
430   mSelectedAcpiTableName = NULL;\r
431   mSelectedAcpiTableFound = FALSE;\r
432   mVerbose = TRUE;\r
433   mConsistencyCheck = TRUE;\r
434 \r
435   // Reset The error/warning counters\r
436   ResetErrorCount ();\r
437   ResetWarningCount ();\r
438 \r
439   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
440   if (EFI_ERROR (Status)) {\r
441     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {\r
442       ShellPrintHiiEx (\r
443         -1,\r
444         -1,\r
445         NULL,\r
446         STRING_TOKEN (STR_GEN_PROBLEM),\r
447         gShellAcpiViewHiiHandle,\r
448         L"acpiview",\r
449         ProblemParam\r
450         );\r
451       FreePool (ProblemParam);\r
452     } else {\r
453       Print (L"acpiview: Error processing input parameter(s)\n");\r
454     }\r
455     ShellStatus = SHELL_INVALID_PARAMETER;\r
456   } else {\r
457     if (ShellCommandLineGetCount (Package) > 1) {\r
458       ShellPrintHiiEx (\r
459         -1,\r
460         -1,\r
461         NULL,\r
462         STRING_TOKEN (STR_GEN_TOO_MANY),\r
463         gShellAcpiViewHiiHandle,\r
464         L"acpiview"\r
465         );\r
466       ShellStatus = SHELL_INVALID_PARAMETER;\r
467     } else if (ShellCommandLineGetFlag (Package, L"-?")) {\r
468       ShellPrintHiiEx (\r
469         -1,\r
470         -1,\r
471         NULL,\r
472         STRING_TOKEN (STR_GET_HELP_ACPIVIEW),\r
473         gShellAcpiViewHiiHandle,\r
474         L"acpiview"\r
475         );\r
476     } else if (ShellCommandLineGetFlag (Package, L"-s") &&\r
477                ShellCommandLineGetValue (Package, L"-s") == NULL) {\r
478       ShellPrintHiiEx (\r
479         -1,\r
480         -1,\r
481         NULL,\r
482         STRING_TOKEN (STR_GEN_NO_VALUE),\r
483         gShellAcpiViewHiiHandle,\r
484         L"acpiview",\r
485         L"-s"\r
486         );\r
487       ShellStatus = SHELL_INVALID_PARAMETER;\r
488     } else if ((ShellCommandLineGetFlag (Package, L"-s") &&\r
489                 ShellCommandLineGetFlag (Package, L"-l"))) {\r
490       ShellPrintHiiEx (\r
491         -1,\r
492         -1,\r
493         NULL,\r
494         STRING_TOKEN (STR_GEN_TOO_MANY),\r
495         gShellAcpiViewHiiHandle,\r
496         L"acpiview"\r
497         );\r
498       ShellStatus = SHELL_INVALID_PARAMETER;\r
499     } else if (ShellCommandLineGetFlag (Package, L"-h") &&\r
500                ShellCommandLineGetValue (Package, L"-h") == NULL) {\r
501         ShellPrintHiiEx (\r
502           -1,\r
503           -1,\r
504           NULL,\r
505           STRING_TOKEN (STR_GEN_NO_VALUE),\r
506           gShellAcpiViewHiiHandle,\r
507           L"acpiview",\r
508           L"-h"\r
509           );\r
510         ShellStatus = SHELL_INVALID_PARAMETER;\r
511     } else if (ShellCommandLineGetFlag (Package, L"-d") &&\r
512                !ShellCommandLineGetFlag (Package, L"-s")) {\r
513         ShellPrintHiiEx (\r
514           -1,\r
515           -1,\r
516           NULL,\r
517           STRING_TOKEN (STR_GEN_MISSING_OPTION),\r
518           gShellAcpiViewHiiHandle,\r
519           L"acpiview",\r
520           L"-s",\r
521           L"-d"\r
522           );\r
523         ShellStatus = SHELL_INVALID_PARAMETER;\r
524     } else {\r
525       // Check if the colour option is set\r
526       Temp = ShellCommandLineGetValue (Package, L"-h");\r
527       if (Temp != NULL) {\r
528         UnicodeStrToAsciiStrS (Temp, ColourOption, sizeof (ColourOption));\r
529         if ((AsciiStriCmp (ColourOption, "ON") == 0) ||\r
530             (AsciiStriCmp (ColourOption, "TRUE") == 0)) {\r
531           SetColourHighlighting (TRUE);\r
532         } else if ((AsciiStriCmp (ColourOption, "OFF") == 0) ||\r
533                    (AsciiStriCmp (ColourOption, "FALSE") == 0)) {\r
534           SetColourHighlighting (FALSE);\r
535         }\r
536       }\r
537 \r
538       if (ShellCommandLineGetFlag (Package, L"-l")) {\r
539         mReportType = EREPORT_TABLE_LIST;\r
540       } else {\r
541         mSelectedAcpiTableName = ShellCommandLineGetValue (Package, L"-s");\r
542         if (mSelectedAcpiTableName != NULL) {\r
543           mSelectedAcpiTable = (UINT32)ConvertStrToAcpiSignature (\r
544                                          mSelectedAcpiTableName\r
545                                          );\r
546           mReportType = EREPORT_SELECTED;\r
547 \r
548           if (ShellCommandLineGetFlag (Package, L"-d"))  {\r
549             // Create a temporary file to check if the media is writable.\r
550             CHAR16 FileNameBuffer[MAX_FILE_NAME_LEN];\r
551             mReportType = EREPORT_DUMP_BIN_FILE;\r
552 \r
553             UnicodeSPrint (\r
554               FileNameBuffer,\r
555               sizeof (FileNameBuffer),\r
556               L".\\%s%04d.tmp",\r
557               mSelectedAcpiTableName,\r
558               mBinTableCount\r
559               );\r
560 \r
561             Status = ShellOpenFileByName (\r
562                        FileNameBuffer,\r
563                        &TmpDumpFileHandle,\r
564                        EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |\r
565                        EFI_FILE_MODE_CREATE,\r
566                        0\r
567                        );\r
568 \r
569             if (EFI_ERROR (Status)) {\r
570               ShellStatus = SHELL_INVALID_PARAMETER;\r
571               TmpDumpFileHandle = NULL;\r
572               ShellPrintHiiEx (\r
573                 -1,\r
574                 -1,\r
575                 NULL,\r
576                 STRING_TOKEN (STR_GEN_READONLY_MEDIA),\r
577                 gShellAcpiViewHiiHandle,\r
578                 L"acpiview"\r
579                 );\r
580               goto Done;\r
581             }\r
582             // Delete Temporary file.\r
583             ShellDeleteFile (&TmpDumpFileHandle);\r
584           } // -d\r
585         } // -s\r
586       }\r
587 \r
588       // Parse ACPI Table information\r
589       Status = AcpiView (SystemTable);\r
590       if (EFI_ERROR (Status)) {\r
591         ShellStatus = SHELL_NOT_FOUND;\r
592       }\r
593     }\r
594   }\r
595 \r
596 Done:\r
597   if (Package != NULL) {\r
598     ShellCommandLineFreeVarList (Package);\r
599   }\r
600   return ShellStatus;\r
601 }\r