1 /******************************************************************************
2  *
3  * Module Name: dmtbdump - Dump ACPI data tables that contain no AML code
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acdisasm.h"
47 #include "actables.h"
48 
49 /* This module used for application-level code only */
50 
51 #define _COMPONENT          ACPI_CA_DISASSEMBLER
52         ACPI_MODULE_NAME    ("dmtbdump")
53 
54 
55 /* Local prototypes */
56 
57 static void
58 AcpiDmValidateFadtLength (
59     UINT32                  Revision,
60     UINT32                  Length);
61 
62 
63 /*******************************************************************************
64  *
65  * FUNCTION:    AcpiDmDumpBuffer
66  *
67  * PARAMETERS:  Table               - ACPI Table or subtable
68  *              BufferOffset        - Offset of buffer from Table above
69  *              Length              - Length of the buffer
70  *              AbsoluteOffset      - Offset of buffer in the main ACPI table
71  *              Header              - Name of the buffer field (printed on the
72  *                                    first line only.)
73  *
74  * RETURN:      None
75  *
76  * DESCRIPTION: Format the contents of an arbitrary length data buffer (in the
77  *              disassembler output format.)
78  *
79  ******************************************************************************/
80 
81 void
AcpiDmDumpBuffer(void * Table,UINT32 BufferOffset,UINT32 Length,UINT32 AbsoluteOffset,char * Header)82 AcpiDmDumpBuffer (
83     void                    *Table,
84     UINT32                  BufferOffset,
85     UINT32                  Length,
86     UINT32                  AbsoluteOffset,
87     char                    *Header)
88 {
89     UINT8                   *Buffer;
90     UINT32                  i;
91 
92 
93     if (!Length)
94     {
95         return;
96     }
97 
98     Buffer = ACPI_CAST_PTR (UINT8, Table) + BufferOffset;
99     i = 0;
100 
101     while (i < Length)
102     {
103         if (!(i % 16))
104         {
105             /* Insert a backslash - line continuation character */
106 
107             if (Length > 16)
108             {
109                 AcpiOsPrintf ("\\\n    ");
110             }
111         }
112 
113         AcpiOsPrintf ("%.02X ", *Buffer);
114         i++;
115         Buffer++;
116         AbsoluteOffset++;
117     }
118 
119     AcpiOsPrintf ("\n");
120 }
121 
122 
123 /*******************************************************************************
124  *
125  * FUNCTION:    AcpiDmDumpUnicode
126  *
127  * PARAMETERS:  Table               - ACPI Table or subtable
128  *              BufferOffset        - Offset of buffer from Table above
129  *              ByteLength          - Length of the buffer
130  *
131  * RETURN:      None
132  *
133  * DESCRIPTION: Validate and dump the contents of a buffer that contains
134  *              unicode data. The output is a standard ASCII string. If it
135  *              appears that the data is not unicode, the buffer is dumped
136  *              as hex characters.
137  *
138  ******************************************************************************/
139 
140 void
AcpiDmDumpUnicode(void * Table,UINT32 BufferOffset,UINT32 ByteLength)141 AcpiDmDumpUnicode (
142     void                    *Table,
143     UINT32                  BufferOffset,
144     UINT32                  ByteLength)
145 {
146     UINT8                   *Buffer;
147     UINT32                  Length;
148     UINT32                  i;
149 
150 
151     Buffer = ((UINT8 *) Table) + BufferOffset;
152     Length = ByteLength - 2; /* Last two bytes are the null terminator */
153 
154     /* Ensure all low bytes are entirely printable ASCII */
155 
156     for (i = 0; i < Length; i += 2)
157     {
158         if (!isprint (Buffer[i]))
159         {
160             goto DumpRawBuffer;
161         }
162     }
163 
164     /* Ensure all high bytes are zero */
165 
166     for (i = 1; i < Length; i += 2)
167     {
168         if (Buffer[i])
169         {
170             goto DumpRawBuffer;
171         }
172     }
173 
174     /* Dump the buffer as a normal string */
175 
176     AcpiOsPrintf ("\"");
177     for (i = 0; i < Length; i += 2)
178     {
179         AcpiOsPrintf ("%c", Buffer[i]);
180     }
181 
182     AcpiOsPrintf ("\"\n");
183     return;
184 
185 DumpRawBuffer:
186     AcpiDmDumpBuffer (Table, BufferOffset, ByteLength,
187         BufferOffset, NULL);
188     AcpiOsPrintf ("\n");
189 }
190 
191 
192 /*******************************************************************************
193  *
194  * FUNCTION:    AcpiDmDumpRsdp
195  *
196  * PARAMETERS:  Table               - A RSDP
197  *
198  * RETURN:      Length of the table (there is not always a length field,
199  *              use revision or length if available (ACPI 2.0+))
200  *
201  * DESCRIPTION: Format the contents of a RSDP
202  *
203  ******************************************************************************/
204 
205 UINT32
AcpiDmDumpRsdp(ACPI_TABLE_HEADER * Table)206 AcpiDmDumpRsdp (
207     ACPI_TABLE_HEADER       *Table)
208 {
209     ACPI_TABLE_RSDP         *Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table);
210     UINT32                  Length = sizeof (ACPI_RSDP_COMMON);
211     UINT8                   Checksum;
212     ACPI_STATUS             Status;
213 
214 
215     /* Dump the common ACPI 1.0 portion */
216 
217     Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp1);
218     if (ACPI_FAILURE (Status))
219     {
220         return (Length);
221     }
222 
223     /* Validate the first checksum */
224 
225     Checksum = AcpiUtGenerateChecksum (Rsdp, sizeof (ACPI_RSDP_COMMON),
226         Rsdp->Checksum);
227     if (Checksum != Rsdp->Checksum)
228     {
229         AcpiOsPrintf ("/* Incorrect Checksum above, should be 0x%2.2X */\n",
230             Checksum);
231     }
232 
233     /* The RSDP for ACPI 2.0+ contains more data and has a Length field */
234 
235     if (Rsdp->Revision > 0)
236     {
237         Length = Rsdp->Length;
238         Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp2);
239         if (ACPI_FAILURE (Status))
240         {
241             return (Length);
242         }
243 
244         /* Validate the extended checksum over entire RSDP */
245 
246         Checksum = AcpiUtGenerateChecksum (Rsdp, sizeof (ACPI_TABLE_RSDP),
247             Rsdp->ExtendedChecksum);
248         if (Checksum != Rsdp->ExtendedChecksum)
249         {
250             AcpiOsPrintf (
251                 "/* Incorrect Extended Checksum above, should be 0x%2.2X */\n",
252                 Checksum);
253         }
254     }
255 
256     return (Length);
257 }
258 
259 
260 /*******************************************************************************
261  *
262  * FUNCTION:    AcpiDmDumpRsdt
263  *
264  * PARAMETERS:  Table               - A RSDT
265  *
266  * RETURN:      None
267  *
268  * DESCRIPTION: Format the contents of a RSDT
269  *
270  ******************************************************************************/
271 
272 void
AcpiDmDumpRsdt(ACPI_TABLE_HEADER * Table)273 AcpiDmDumpRsdt (
274     ACPI_TABLE_HEADER       *Table)
275 {
276     UINT32                  *Array;
277     UINT32                  Entries;
278     UINT32                  Offset;
279     UINT32                  i;
280 
281 
282     /* Point to start of table pointer array */
283 
284     Array = ACPI_CAST_PTR (ACPI_TABLE_RSDT, Table)->TableOffsetEntry;
285     Offset = sizeof (ACPI_TABLE_HEADER);
286 
287     /* RSDT uses 32-bit pointers */
288 
289     Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT32);
290 
291     for (i = 0; i < Entries; i++)
292     {
293         AcpiDmLineHeader2 (Offset, sizeof (UINT32), "ACPI Table Address", i);
294         AcpiOsPrintf ("%8.8X\n", Array[i]);
295         Offset += sizeof (UINT32);
296     }
297 }
298 
299 
300 /*******************************************************************************
301  *
302  * FUNCTION:    AcpiDmDumpXsdt
303  *
304  * PARAMETERS:  Table               - A XSDT
305  *
306  * RETURN:      None
307  *
308  * DESCRIPTION: Format the contents of a XSDT
309  *
310  ******************************************************************************/
311 
312 void
AcpiDmDumpXsdt(ACPI_TABLE_HEADER * Table)313 AcpiDmDumpXsdt (
314     ACPI_TABLE_HEADER       *Table)
315 {
316     UINT64                  *Array;
317     UINT32                  Entries;
318     UINT32                  Offset;
319     UINT32                  i;
320 
321 
322     /* Point to start of table pointer array */
323 
324     Array = ACPI_CAST_PTR (ACPI_TABLE_XSDT, Table)->TableOffsetEntry;
325     Offset = sizeof (ACPI_TABLE_HEADER);
326 
327     /* XSDT uses 64-bit pointers */
328 
329     Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT64);
330 
331     for (i = 0; i < Entries; i++)
332     {
333         AcpiDmLineHeader2 (Offset, sizeof (UINT64), "ACPI Table Address", i);
334         AcpiOsPrintf ("%8.8X%8.8X\n", ACPI_FORMAT_UINT64 (Array[i]));
335         Offset += sizeof (UINT64);
336     }
337 }
338 
339 
340 /*******************************************************************************
341  *
342  * FUNCTION:    AcpiDmDumpFadt
343  *
344  * PARAMETERS:  Table               - A FADT
345  *
346  * RETURN:      None
347  *
348  * DESCRIPTION: Format the contents of a FADT
349  *
350  * NOTE:        We cannot depend on the FADT version to indicate the actual
351  *              contents of the FADT because of BIOS bugs. The table length
352  *              is the only reliable indicator.
353  *
354  ******************************************************************************/
355 
356 void
AcpiDmDumpFadt(ACPI_TABLE_HEADER * Table)357 AcpiDmDumpFadt (
358     ACPI_TABLE_HEADER       *Table)
359 {
360     ACPI_STATUS             Status;
361 
362 
363     /* Always dump the minimum FADT revision 1 fields (ACPI 1.0) */
364 
365     Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
366         AcpiDmTableInfoFadt1);
367     if (ACPI_FAILURE (Status))
368     {
369         return;
370     }
371 
372     /* Check for FADT revision 2 fields (ACPI 1.0B MS extensions) */
373 
374     if ((Table->Length > ACPI_FADT_V1_SIZE) &&
375         (Table->Length <= ACPI_FADT_V2_SIZE))
376     {
377         Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
378             AcpiDmTableInfoFadt2);
379         if (ACPI_FAILURE (Status))
380         {
381             return;
382         }
383     }
384 
385     /* Check for FADT revision 3/4 fields and up (ACPI 2.0+ extended data) */
386 
387     else if (Table->Length > ACPI_FADT_V2_SIZE)
388     {
389         Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
390             AcpiDmTableInfoFadt3);
391         if (ACPI_FAILURE (Status))
392         {
393             return;
394         }
395 
396         /* Check for FADT revision 5 fields and up (ACPI 5.0+) */
397 
398         if (Table->Length > ACPI_FADT_V3_SIZE)
399         {
400             Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
401                 AcpiDmTableInfoFadt5);
402             if (ACPI_FAILURE (Status))
403             {
404                 return;
405             }
406         }
407 
408         /* Check for FADT revision 6 fields and up (ACPI 6.0+) */
409 
410         if (Table->Length > ACPI_FADT_V3_SIZE)
411         {
412             Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
413                 AcpiDmTableInfoFadt6);
414             if (ACPI_FAILURE (Status))
415             {
416                 return;
417             }
418         }
419     }
420 
421     /* Validate various fields in the FADT, including length */
422 
423     AcpiTbCreateLocalFadt (Table, Table->Length);
424 
425     /* Validate FADT length against the revision */
426 
427     AcpiDmValidateFadtLength (Table->Revision, Table->Length);
428 }
429 
430 
431 /*******************************************************************************
432  *
433  * FUNCTION:    AcpiDmValidateFadtLength
434  *
435  * PARAMETERS:  Revision            - FADT revision (Header->Revision)
436  *              Length              - FADT length (Header->Length
437  *
438  * RETURN:      None
439  *
440  * DESCRIPTION: Check the FADT revision against the expected table length for
441  *              that revision. Issue a warning if the length is not what was
442  *              expected. This seems to be such a common BIOS bug that the
443  *              FADT revision has been rendered virtually meaningless.
444  *
445  ******************************************************************************/
446 
447 static void
AcpiDmValidateFadtLength(UINT32 Revision,UINT32 Length)448 AcpiDmValidateFadtLength (
449     UINT32                  Revision,
450     UINT32                  Length)
451 {
452     UINT32                  ExpectedLength;
453 
454 
455     switch (Revision)
456     {
457     case 0:
458 
459         AcpiOsPrintf ("// ACPI Warning: Invalid FADT revision: 0\n");
460         return;
461 
462     case 1:
463 
464         ExpectedLength = ACPI_FADT_V1_SIZE;
465         break;
466 
467     case 2:
468 
469         ExpectedLength = ACPI_FADT_V2_SIZE;
470         break;
471 
472     case 3:
473     case 4:
474 
475         ExpectedLength = ACPI_FADT_V3_SIZE;
476         break;
477 
478     case 5:
479 
480         ExpectedLength = ACPI_FADT_V5_SIZE;
481         break;
482 
483     default:
484 
485         return;
486     }
487 
488     if (Length == ExpectedLength)
489     {
490         return;
491     }
492 
493     AcpiOsPrintf (
494         "\n// ACPI Warning: FADT revision %X does not match length: "
495         "found %X expected %X\n",
496         Revision, Length, ExpectedLength);
497 }
498