xref: /netbsd-src/sys/external/bsd/acpica/dist/common/dmtbdump.c (revision 987b04d624d6d5e25e3e80d683a4ebe80fe47dcf)
1 /******************************************************************************
2  *
3  * Module Name: dmtbdump - Dump ACPI data tables that contain no AML code
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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
82 AcpiDmDumpBuffer (
83     void                    *Table,
84     UINT32                  BufferOffset,
85     UINT32                  Length,
86     UINT32                  AbsoluteOffset,
87     char                    *Header)
88 {
89     UINT8                   *Buffer;
90     UINT8                   BufChar;
91     UINT32                  i;
92     UINT32                  j;
93 
94 
95     if (!Length)
96     {
97         return;
98     }
99 
100     Buffer = ACPI_CAST_PTR (UINT8, Table) + BufferOffset;
101     i = 0;
102 
103     while (i < Length)
104     {
105         if ((Length > 16) && (i != 0))
106         {
107         if ((Length - i) < 16)
108             AcpiOsPrintf ("\n/* %3.3Xh %4.4u %3u */                            ", AbsoluteOffset, AbsoluteOffset, Length - i);
109         else
110             AcpiOsPrintf ("\n/* %3.3Xh %4.4u  16 */                            ", AbsoluteOffset, AbsoluteOffset);
111         }
112         AbsoluteOffset += 16;
113 
114         /* Emit the raw data bytes*/
115 
116         for (j = 0; j < 16; j++)
117         {
118             if (i + j >= Length)
119             {
120                 /* Dump fill spaces */
121 
122                 AcpiOsPrintf ("%*s", (48 - (3 * (Length -i))), " ");
123                 break;
124             }
125             AcpiOsPrintf ("%.02X ", Buffer[(ACPI_SIZE) i + j]);
126         }
127 
128         /* Emit the ASCII equivalent to the raw data bytes */
129 
130         for (j = 0; j < 16; j++)
131         {
132             if (i + j >= Length)
133             {
134                 AcpiOsPrintf (" */\\\n");
135                 return;
136             }
137 
138             /*
139              * Add comment characters so rest of line is ignored when
140              * compiled
141              */
142             if (j == 0)
143             {
144                 AcpiOsPrintf ("/* ");
145             }
146 
147             BufChar = Buffer[(ACPI_SIZE) i + j];
148             if (isprint (BufChar))
149             {
150                 AcpiOsPrintf ("%c", BufChar);
151             }
152             else
153             {
154                 AcpiOsPrintf (".");
155             }
156         }
157 
158         /* Done with that line. */
159         /* Close the comment and insert a backslash - line continuation character */
160 
161         AcpiOsPrintf (" */\\");
162 
163         i += 16; /* Point to next line */
164     }
165 
166     AcpiOsPrintf ("\n");
167 }
168 
169 
170 /*******************************************************************************
171  *
172  * FUNCTION:    AcpiDmDumpUnicode
173  *
174  * PARAMETERS:  Table               - ACPI Table or subtable
175  *              BufferOffset        - Offset of buffer from Table above
176  *              ByteLength          - Length of the buffer
177  *
178  * RETURN:      None
179  *
180  * DESCRIPTION: Validate and dump the contents of a buffer that contains
181  *              unicode data. The output is a standard ASCII string. If it
182  *              appears that the data is not unicode, the buffer is dumped
183  *              as hex characters.
184  *
185  ******************************************************************************/
186 
187 void
188 AcpiDmDumpUnicode (
189     void                    *Table,
190     UINT32                  BufferOffset,
191     UINT32                  ByteLength)
192 {
193     UINT8                   *Buffer;
194     UINT32                  Length;
195     UINT32                  i;
196 
197 
198     Buffer = ((UINT8 *) Table) + BufferOffset;
199     Length = ByteLength - 2; /* Last two bytes are the null terminator */
200 
201     /* Ensure all low bytes are entirely printable ASCII */
202 
203     for (i = 0; i < Length; i += 2)
204     {
205         if (!isprint (Buffer[i]))
206         {
207             goto DumpRawBuffer;
208         }
209     }
210 
211     /* Ensure all high bytes are zero */
212 
213     for (i = 1; i < Length; i += 2)
214     {
215         if (Buffer[i])
216         {
217             goto DumpRawBuffer;
218         }
219     }
220 
221     /* Dump the buffer as a normal string */
222 
223     AcpiOsPrintf ("\"");
224     for (i = 0; i < Length; i += 2)
225     {
226         AcpiOsPrintf ("%c", Buffer[i]);
227     }
228 
229     AcpiOsPrintf ("\"\n");
230     return;
231 
232 DumpRawBuffer:
233     AcpiDmDumpBuffer (Table, BufferOffset, ByteLength,
234         BufferOffset, NULL);
235     AcpiOsPrintf ("\n");
236 }
237 
238 
239 /*******************************************************************************
240  *
241  * FUNCTION:    AcpiDmDumpRsdp
242  *
243  * PARAMETERS:  Table               - A RSDP
244  *
245  * RETURN:      Length of the table (there is not always a length field,
246  *              use revision or length if available (ACPI 2.0+))
247  *
248  * DESCRIPTION: Format the contents of a RSDP
249  *
250  ******************************************************************************/
251 
252 UINT32
253 AcpiDmDumpRsdp (
254     ACPI_TABLE_HEADER       *Table)
255 {
256     ACPI_TABLE_RSDP         *Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table);
257     UINT32                  Length = sizeof (ACPI_RSDP_COMMON);
258     UINT8                   Checksum;
259     ACPI_STATUS             Status;
260 
261 
262     /* Dump the common ACPI 1.0 portion */
263 
264     Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp1);
265     if (ACPI_FAILURE (Status))
266     {
267         return (Length);
268     }
269 
270     /* Validate the first checksum */
271 
272     Checksum = AcpiUtGenerateChecksum (Rsdp, sizeof (ACPI_RSDP_COMMON),
273         Rsdp->Checksum);
274     if (Checksum != Rsdp->Checksum)
275     {
276         AcpiOsPrintf ("/* Incorrect Checksum above, should be 0x%2.2X */\n",
277             Checksum);
278     }
279 
280     /* The RSDP for ACPI 2.0+ contains more data and has a Length field */
281 
282     if (Rsdp->Revision > 0)
283     {
284         Length = Rsdp->Length;
285         Status = AcpiDmDumpTable (Length, 0, Table, 0, AcpiDmTableInfoRsdp2);
286         if (ACPI_FAILURE (Status))
287         {
288             return (Length);
289         }
290 
291         /* Validate the extended checksum over entire RSDP */
292 
293         Checksum = AcpiUtGenerateChecksum (Rsdp, sizeof (ACPI_TABLE_RSDP),
294             Rsdp->ExtendedChecksum);
295         if (Checksum != Rsdp->ExtendedChecksum)
296         {
297             AcpiOsPrintf (
298                 "/* Incorrect Extended Checksum above, should be 0x%2.2X */\n",
299                 Checksum);
300         }
301     }
302 
303     return (Length);
304 }
305 
306 
307 /*******************************************************************************
308  *
309  * FUNCTION:    AcpiDmDumpRsdt
310  *
311  * PARAMETERS:  Table               - A RSDT
312  *
313  * RETURN:      None
314  *
315  * DESCRIPTION: Format the contents of a RSDT
316  *
317  ******************************************************************************/
318 
319 void
320 AcpiDmDumpRsdt (
321     ACPI_TABLE_HEADER       *Table)
322 {
323     UINT32                  *Array;
324     UINT32                  Entries;
325     UINT32                  Offset;
326     UINT32                  i;
327 
328 
329     /* Point to start of table pointer array */
330 
331     Array = ACPI_CAST_PTR (ACPI_TABLE_RSDT, Table)->TableOffsetEntry;
332     Offset = sizeof (ACPI_TABLE_HEADER);
333 
334     /* RSDT uses 32-bit pointers */
335 
336     Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT32);
337 
338     for (i = 0; i < Entries; i++)
339     {
340         AcpiDmLineHeader2 (Offset, sizeof (UINT32), "ACPI Table Address", i);
341         AcpiOsPrintf ("%8.8X\n", Array[i]);
342         Offset += sizeof (UINT32);
343     }
344 }
345 
346 
347 /*******************************************************************************
348  *
349  * FUNCTION:    AcpiDmDumpXsdt
350  *
351  * PARAMETERS:  Table               - A XSDT
352  *
353  * RETURN:      None
354  *
355  * DESCRIPTION: Format the contents of a XSDT
356  *
357  ******************************************************************************/
358 
359 void
360 AcpiDmDumpXsdt (
361     ACPI_TABLE_HEADER       *Table)
362 {
363     UINT64                  *Array;
364     UINT32                  Entries;
365     UINT32                  Offset;
366     UINT32                  i;
367 
368 
369     /* Point to start of table pointer array */
370 
371     Array = ACPI_CAST_PTR (ACPI_TABLE_XSDT, Table)->TableOffsetEntry;
372     Offset = sizeof (ACPI_TABLE_HEADER);
373 
374     /* XSDT uses 64-bit pointers */
375 
376     Entries = (Table->Length - sizeof (ACPI_TABLE_HEADER)) / sizeof (UINT64);
377 
378     for (i = 0; i < Entries; i++)
379     {
380         AcpiDmLineHeader2 (Offset, sizeof (UINT64), "ACPI Table Address", i);
381         AcpiOsPrintf ("%8.8X%8.8X\n", ACPI_FORMAT_UINT64 (Array[i]));
382         Offset += sizeof (UINT64);
383     }
384 }
385 
386 
387 /*******************************************************************************
388  *
389  * FUNCTION:    AcpiDmDumpFadt
390  *
391  * PARAMETERS:  Table               - A FADT
392  *
393  * RETURN:      None
394  *
395  * DESCRIPTION: Format the contents of a FADT
396  *
397  * NOTE:        We cannot depend on the FADT version to indicate the actual
398  *              contents of the FADT because of BIOS bugs. The table length
399  *              is the only reliable indicator.
400  *
401  ******************************************************************************/
402 
403 void
404 AcpiDmDumpFadt (
405     ACPI_TABLE_HEADER       *Table)
406 {
407     ACPI_STATUS             Status;
408 
409 
410     /* Always dump the minimum FADT revision 1 fields (ACPI 1.0) */
411 
412     Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
413         AcpiDmTableInfoFadt1);
414     if (ACPI_FAILURE (Status))
415     {
416         return;
417     }
418 
419     /* Check for FADT revision 2 fields (ACPI 1.0B MS extensions) */
420 
421     if ((Table->Length > ACPI_FADT_V1_SIZE) &&
422         (Table->Length <= ACPI_FADT_V2_SIZE))
423     {
424         Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
425             AcpiDmTableInfoFadt2);
426         if (ACPI_FAILURE (Status))
427         {
428             return;
429         }
430     }
431 
432     /* Check for FADT revision 3/4 fields and up (ACPI 2.0+ extended data) */
433 
434     else if (Table->Length > ACPI_FADT_V2_SIZE)
435     {
436         Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
437             AcpiDmTableInfoFadt3);
438         if (ACPI_FAILURE (Status))
439         {
440             return;
441         }
442 
443         /* Check for FADT revision 5 fields and up (ACPI 5.0+) */
444 
445         if (Table->Length > ACPI_FADT_V3_SIZE)
446         {
447             Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
448                 AcpiDmTableInfoFadt5);
449             if (ACPI_FAILURE (Status))
450             {
451                 return;
452             }
453         }
454 
455         /* Check for FADT revision 6 fields and up (ACPI 6.0+) */
456 
457         if (Table->Length > ACPI_FADT_V5_SIZE)
458         {
459             Status = AcpiDmDumpTable (Table->Length, 0, Table, 0,
460                 AcpiDmTableInfoFadt6);
461             if (ACPI_FAILURE (Status))
462             {
463                 return;
464             }
465         }
466     }
467 
468     /* Validate various fields in the FADT, including length */
469 
470     AcpiTbCreateLocalFadt (Table, Table->Length);
471 
472     /* Validate FADT length against the revision */
473 
474     AcpiDmValidateFadtLength (Table->Revision, Table->Length);
475 }
476 
477 
478 /*******************************************************************************
479  *
480  * FUNCTION:    AcpiDmValidateFadtLength
481  *
482  * PARAMETERS:  Revision            - FADT revision (Header->Revision)
483  *              Length              - FADT length (Header->Length
484  *
485  * RETURN:      None
486  *
487  * DESCRIPTION: Check the FADT revision against the expected table length for
488  *              that revision. Issue a warning if the length is not what was
489  *              expected. This seems to be such a common BIOS bug that the
490  *              FADT revision has been rendered virtually meaningless.
491  *
492  ******************************************************************************/
493 
494 static void
495 AcpiDmValidateFadtLength (
496     UINT32                  Revision,
497     UINT32                  Length)
498 {
499     UINT32                  ExpectedLength;
500 
501 
502     switch (Revision)
503     {
504     case 0:
505 
506         AcpiOsPrintf ("// ACPI Warning: Invalid FADT revision: 0\n");
507         return;
508 
509     case 1:
510 
511         ExpectedLength = ACPI_FADT_V1_SIZE;
512         break;
513 
514     case 2:
515 
516         ExpectedLength = ACPI_FADT_V2_SIZE;
517         break;
518 
519     case 3:
520     case 4:
521 
522         ExpectedLength = ACPI_FADT_V3_SIZE;
523         break;
524 
525     case 5:
526 
527         ExpectedLength = ACPI_FADT_V5_SIZE;
528         break;
529 
530     case 6:
531 
532         ExpectedLength = ACPI_FADT_V6_SIZE;
533         break;
534 
535     default:
536 
537         return;
538     }
539 
540     if (Length == ExpectedLength)
541     {
542         return;
543     }
544 
545     AcpiOsPrintf (
546         "\n// ACPI Warning: FADT revision %X does not match length: "
547         "found %X expected %X\n",
548         Revision, Length, ExpectedLength);
549 }
550