ShellPkg: Add acpiview tool to dump ACPI tables
[mirror_edk2.git] / ShellPkg / Library / UefiShellAcpiViewCommandLib / Parsers / Fadt / FadtParser.c
1 /**\r
2   FADT table 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   @par Reference(s):\r
14     - ACPI 6.2 Specification - Errata A, September 2017\r
15 **/\r
16 \r
17 #include <IndustryStandard/Acpi.h>\r
18 #include <Library/UefiLib.h>\r
19 #include "AcpiParser.h"\r
20 #include "AcpiTableParser.h"\r
21 \r
22 // Local variables\r
23 STATIC CONST UINT32* DsdtAddress;\r
24 STATIC CONST UINT64* X_DsdtAddress;\r
25 STATIC CONST UINT8*  FadtMinorRevision;\r
26 STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r
27 \r
28 /** A macro defining the Hardware reduced ACPI flag\r
29 */\r
30 #define HW_REDUCED_ACPI   BIT20\r
31 \r
32 // Forward declarations\r
33 CONST ACPI_DESCRIPTION_HEADER_INFO* CONST\r
34 EFIAPI\r
35 GetAcpiXsdtHeaderInfo (\r
36   VOID\r
37 );\r
38 \r
39 STATIC\r
40 VOID\r
41 EFIAPI\r
42 ValidateFirmwareCtrl (\r
43   IN UINT8* Ptr,\r
44   IN VOID*  Context\r
45 );\r
46 \r
47 STATIC\r
48 VOID\r
49 EFIAPI\r
50 ValidateXFirmwareCtrl (\r
51   IN UINT8* Ptr,\r
52   IN VOID*  Context\r
53 );\r
54 \r
55 STATIC\r
56 VOID\r
57 EFIAPI\r
58 ValidateFlags (\r
59   IN UINT8* Ptr,\r
60   IN VOID*  Context\r
61 );\r
62 \r
63 /** An ACPI_PARSER array describing the ACPI FADT Table.\r
64 */\r
65 STATIC CONST ACPI_PARSER FadtParser[] = {\r
66   PARSE_ACPI_HEADER (&AcpiHdrInfo),\r
67   {L"FIRMWARE_CTRL", 4, 36, L"0x%x", NULL, NULL, ValidateFirmwareCtrl, NULL},\r
68   {L"DSDT", 4, 40, L"0x%x", NULL, (VOID**)&DsdtAddress, NULL, NULL},\r
69   {L"Reserved", 1, 44, L"%x", NULL, NULL, NULL, NULL},\r
70   {L"Preferred_PM_Profile", 1, 45, L"0x%x", NULL, NULL, NULL, NULL},\r
71   {L"SCI_INT", 2, 46, L"0x%x", NULL, NULL, NULL, NULL},\r
72   {L"SMI_CMD", 4, 48, L"0x%x", NULL, NULL, NULL, NULL},\r
73   {L"ACPI_ENABLE", 1, 52, L"0x%x", NULL, NULL, NULL, NULL},\r
74   {L"ACPI_DISABLE", 1, 53, L"0x%x", NULL, NULL, NULL, NULL},\r
75   {L"S4BIOS_REQ", 1, 54, L"0x%x", NULL, NULL, NULL, NULL},\r
76   {L"PSTATE_CNT", 1, 55, L"0x%x", NULL, NULL, NULL, NULL},\r
77   {L"PM1a_EVT_BLK", 4, 56, L"0x%x", NULL, NULL, NULL, NULL},\r
78   {L"PM1b_EVT_BLK", 4, 60, L"0x%x", NULL, NULL, NULL, NULL},\r
79   {L"PM1a_CNT_BLK", 4, 64, L"0x%x", NULL, NULL, NULL, NULL},\r
80   {L"PM1b_CNT_BLK", 4, 68, L"0x%x", NULL, NULL, NULL, NULL},\r
81   {L"PM2_CNT_BLK", 4, 72, L"0x%x", NULL, NULL, NULL, NULL},\r
82   {L"PM_TMR_BLK", 4, 76, L"0x%x", NULL, NULL, NULL, NULL},\r
83   {L"GPE0_BLK", 4, 80, L"0x%x", NULL, NULL, NULL, NULL},\r
84   {L"GPE1_BLK", 4, 84, L"0x%x", NULL, NULL, NULL, NULL},\r
85   {L"PM1_EVT_LEN", 1, 88, L"0x%x", NULL, NULL, NULL, NULL},\r
86   {L"PM1_CNT_LEN", 1, 89, L"0x%x", NULL, NULL, NULL, NULL},\r
87   {L"PM2_CNT_LEN", 1, 90, L"0x%x", NULL, NULL, NULL, NULL},\r
88   {L"PM_TMR_LEN", 1, 91, L"0x%x", NULL, NULL, NULL, NULL},\r
89   {L"GPE0_BLK_LEN", 1, 92, L"0x%x", NULL, NULL, NULL, NULL},\r
90   {L"GPE1_BLK_LEN", 1, 93, L"0x%x", NULL, NULL, NULL, NULL},\r
91   {L"GPE1_BASE", 1, 94, L"0x%x", NULL, NULL, NULL, NULL},\r
92   {L"CST_CNT", 1, 95, L"0x%x", NULL, NULL, NULL, NULL},\r
93   {L"P_LVL2_LAT", 2, 96, L"0x%x", NULL, NULL, NULL, NULL},\r
94   {L"P_LVL3_LAT", 2, 98, L"0x%x", NULL, NULL, NULL, NULL},\r
95   {L"FLUSH_SIZE", 2, 100, L"0x%x", NULL, NULL, NULL, NULL},\r
96   {L"FLUSH_STRIDE", 2, 102, L"0x%x", NULL, NULL, NULL, NULL},\r
97   {L"DUTY_OFFSET", 1, 104, L"0x%x", NULL, NULL, NULL, NULL},\r
98   {L"DUTY_WIDTH", 1, 105, L"0x%x", NULL, NULL, NULL, NULL},\r
99   {L"DAY_ALRM", 1, 106, L"0x%x", NULL, NULL, NULL, NULL},\r
100   {L"MON_ALRM", 1, 107, L"0x%x", NULL, NULL, NULL, NULL},\r
101   {L"CENTURY", 1, 108, L"0x%x", NULL, NULL, NULL, NULL},\r
102   {L"IAPC_BOOT_ARCH", 2, 109, L"0x%x", NULL, NULL, NULL, NULL},\r
103   {L"Reserved", 1, 111, L"0x%x", NULL, NULL, NULL, NULL},\r
104   {L"Flags", 4, 112, L"0x%x", NULL, NULL, ValidateFlags, NULL},\r
105   {L"RESET_REG", 12, 116, NULL, DumpGas, NULL, NULL, NULL},\r
106   {L"RESET_VALUE", 1, 128, L"0x%x", NULL, NULL, NULL, NULL},\r
107   {L"ARM_BOOT_ARCH", 2, 129, L"0x%x", NULL, NULL, NULL, NULL},\r
108   {L"FADT Minor Version", 1, 131, L"0x%x", NULL, (VOID**)&FadtMinorRevision,\r
109     NULL, NULL},\r
110   {L"X_FIRMWARE_CTRL", 8, 132, L"0x%lx", NULL, NULL,\r
111     ValidateXFirmwareCtrl, NULL},\r
112   {L"X_DSDT", 8, 140, L"0x%lx", NULL, (VOID**)&X_DsdtAddress, NULL, NULL},\r
113   {L"X_PM1a_EVT_BLK", 12, 148, NULL, DumpGas, NULL, NULL, NULL},\r
114   {L"X_PM1b_EVT_BLK", 12, 160, NULL, DumpGas, NULL, NULL, NULL},\r
115   {L"X_PM1a_CNT_BLK", 12, 172, NULL, DumpGas, NULL, NULL, NULL},\r
116   {L"X_PM1b_CNT_BLK", 12, 184, NULL, DumpGas, NULL, NULL, NULL},\r
117   {L"X_PM2_CNT_BLK", 12, 196, NULL, DumpGas, NULL, NULL, NULL},\r
118   {L"X_PM_TMR_BLK", 12, 208, NULL, DumpGas, NULL, NULL, NULL},\r
119   {L"X_GPE0_BLK", 12, 220, NULL, DumpGas, NULL, NULL, NULL},\r
120   {L"X_GPE1_BLK", 12, 232, NULL, DumpGas, NULL, NULL, NULL},\r
121   {L"SLEEP_CONTROL_REG", 12, 244, NULL, DumpGas, NULL, NULL, NULL},\r
122   {L"SLEEP_STATUS_REG", 12, 256, NULL, DumpGas, NULL, NULL, NULL},\r
123   {L"Hypervisor VendorIdentity", 8, 268, L"%lx", NULL, NULL, NULL, NULL}\r
124 };\r
125 \r
126 /** This function validates the Firmware Control Field.\r
127 \r
128   @param [in] Ptr     Pointer to the start of the field data.\r
129   @param [in] Context Pointer to context specific information e.g. this\r
130                       could be a pointer to the ACPI table header.\r
131 */\r
132 STATIC\r
133 VOID\r
134 EFIAPI\r
135 ValidateFirmwareCtrl (\r
136   IN UINT8* Ptr,\r
137   IN VOID*  Context\r
138 )\r
139 {\r
140 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
141   if (*(UINT32*)Ptr != 0) {\r
142     IncrementErrorCount ();\r
143     Print (\r
144       L"\nERROR: Firmware Control must be zero for ARM platforms."\r
145     );\r
146   }\r
147 #endif\r
148 }\r
149 \r
150 /** This function validates the X_Firmware Control Field.\r
151 \r
152   @param [in] Ptr     Pointer to the start of the field data.\r
153   @param [in] Context Pointer to context specific information e.g. this\r
154                       could be a pointer to the ACPI table header.\r
155 */\r
156 STATIC\r
157 VOID\r
158 EFIAPI\r
159 ValidateXFirmwareCtrl (\r
160   IN UINT8* Ptr,\r
161   IN VOID*  Context\r
162 )\r
163 {\r
164 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
165   if (*(UINT64*)Ptr != 0) {\r
166     IncrementErrorCount ();\r
167     Print (\r
168       L"\nERROR: X Firmware Control must be zero for ARM platforms."\r
169     );\r
170   }\r
171 #endif\r
172 }\r
173 \r
174 /** This function validates the flags.\r
175 \r
176   @param [in] Ptr     Pointer to the start of the field data.\r
177   @param [in] Context Pointer to context specific information e.g. this\r
178                       could be a pointer to the ACPI table header.\r
179 */\r
180 STATIC\r
181 VOID\r
182 EFIAPI\r
183 ValidateFlags (\r
184   IN UINT8* Ptr,\r
185   IN VOID*  Context\r
186 )\r
187 {\r
188 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
189   if (((*(UINT32*)Ptr) & HW_REDUCED_ACPI) == 0) {\r
190     IncrementErrorCount ();\r
191     Print (\r
192       L"\nERROR: HW_REDUCED_ACPI flag must be set for ARM platforms."\r
193     );\r
194   }\r
195 #endif\r
196 }\r
197 \r
198 /** This function parses the ACPI FADT table.\r
199   This function parses the FADT table and optionally traces the ACPI\r
200   table fields.\r
201 \r
202   This function also performs validation of the ACPI table fields.\r
203 \r
204   @param [in] Trace              If TRUE, trace the ACPI fields.\r
205   @param [in] Ptr                Pointer to the start of the buffer.\r
206   @param [in] AcpiTableLength    Length of the ACPI table.\r
207   @param [in] AcpiTableRevision  Revision of the ACPI table.\r
208 */\r
209 VOID\r
210 EFIAPI\r
211 ParseAcpiFadt (\r
212   IN BOOLEAN Trace,\r
213   IN UINT8*  Ptr,\r
214   IN UINT32  AcpiTableLength,\r
215   IN UINT8   AcpiTableRevision\r
216   )\r
217 {\r
218   UINT8*  DsdtPtr;\r
219 \r
220   ParseAcpi (\r
221     Trace,\r
222     0,\r
223     "FADT",\r
224     Ptr,\r
225     AcpiTableLength,\r
226     PARSER_PARAMS (FadtParser)\r
227     );\r
228 \r
229   if (Trace) {\r
230     Print (L"\nSummary:\n");\r
231     PrintFieldName (2, L"FADT Version");\r
232     Print (L"%d.%d\n",  *AcpiHdrInfo.Revision, *FadtMinorRevision);\r
233 \r
234     if (*GetAcpiXsdtHeaderInfo ()->OemTableId != *AcpiHdrInfo.OemTableId) {\r
235       IncrementErrorCount ();\r
236       Print (L"ERROR: OEM Table Id does not match with RSDT/XSDT.\n");\r
237     }\r
238   }\r
239 \r
240   // If X_DSDT is not zero then use X_DSDT and ignore DSDT,\r
241   // else use DSDT.\r
242   if (*X_DsdtAddress != 0) {\r
243     DsdtPtr = (UINT8*)(UINTN)(*X_DsdtAddress);\r
244   } else if (*DsdtAddress != 0) {\r
245     DsdtPtr = (UINT8*)(UINTN)(*DsdtAddress);\r
246   } else {\r
247     // Both DSDT and X_DSDT cannot be zero.\r
248 #if defined (MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r
249     if (Trace) {\r
250       // The DSDT Table is mandatory for ARM systems\r
251       // as the CPU information MUST be presented in\r
252       // the DSDT.\r
253       IncrementErrorCount ();\r
254       Print (L"ERROR: Both X_DSDT and DSDT are NULL.\n");\r
255     }\r
256 #endif\r
257     return;\r
258   }\r
259 \r
260   ProcessAcpiTable (DsdtPtr);\r
261 }\r