1/******************************************************************************
2 *
3 * Module Name: apdump - Dump routines for ACPI tables (acpidump)
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 "acpidump.h"
45
46
47/* Local prototypes */
48
49static int
50ApDumpTableBuffer (
51    ACPI_TABLE_HEADER       *Table,
52    UINT32                  Instance,
53    ACPI_PHYSICAL_ADDRESS   Address);
54
55
56/******************************************************************************
57 *
58 * FUNCTION:    ApIsValidHeader
59 *
60 * PARAMETERS:  Table               - Pointer to table to be validated
61 *
62 * RETURN:      TRUE if the header appears to be valid. FALSE otherwise
63 *
64 * DESCRIPTION: Check for a valid ACPI table header
65 *
66 ******************************************************************************/
67
68BOOLEAN
69ApIsValidHeader (
70    ACPI_TABLE_HEADER       *Table)
71{
72
73    if (!ACPI_VALIDATE_RSDP_SIG (Table->Signature))
74    {
75        /* Make sure signature is all ASCII and a valid ACPI name */
76
77        if (!AcpiUtValidNameseg (Table->Signature))
78        {
79            fprintf (stderr, "Table signature (0x%8.8X) is invalid\n",
80                *(UINT32 *) Table->Signature);
81            return (FALSE);
82        }
83
84        /* Check for minimum table length */
85
86        if (Table->Length < sizeof (ACPI_TABLE_HEADER))
87        {
88            fprintf (stderr, "Table length (0x%8.8X) is invalid\n",
89                Table->Length);
90            return (FALSE);
91        }
92    }
93
94    return (TRUE);
95}
96
97
98/******************************************************************************
99 *
100 * FUNCTION:    ApIsValidChecksum
101 *
102 * PARAMETERS:  Table               - Pointer to table to be validated
103 *
104 * RETURN:      TRUE if the checksum appears to be valid. FALSE otherwise.
105 *
106 * DESCRIPTION: Check for a valid ACPI table checksum.
107 *
108 ******************************************************************************/
109
110BOOLEAN
111ApIsValidChecksum (
112    ACPI_TABLE_HEADER       *Table)
113{
114    ACPI_STATUS             Status;
115    ACPI_TABLE_RSDP         *Rsdp;
116
117
118    if (ACPI_VALIDATE_RSDP_SIG (Table->Signature))
119    {
120        /*
121         * Checksum for RSDP.
122         * Note: Other checksums are computed during the table dump.
123         */
124        Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table);
125        Status = AcpiTbValidateRsdp (Rsdp);
126    }
127    else
128    {
129        /* We don't have to check for a CDAT here, since CDAT is not in the RSDT/XSDT */
130
131        Status = AcpiUtVerifyChecksum (Table, Table->Length);
132    }
133
134    if (ACPI_FAILURE (Status))
135    {
136        fprintf (stderr, "%4.4s: Warning: wrong checksum in table\n",
137            Table->Signature);
138    }
139
140    return (AE_OK);
141}
142
143
144/******************************************************************************
145 *
146 * FUNCTION:    ApGetTableLength
147 *
148 * PARAMETERS:  Table               - Pointer to the table
149 *
150 * RETURN:      Table length
151 *
152 * DESCRIPTION: Obtain table length according to table signature.
153 *
154 ******************************************************************************/
155
156UINT32
157ApGetTableLength (
158    ACPI_TABLE_HEADER       *Table)
159{
160    ACPI_TABLE_RSDP         *Rsdp;
161
162
163    /* Check if table is valid */
164
165    if (!ApIsValidHeader (Table))
166    {
167        return (0);
168    }
169
170    if (ACPI_VALIDATE_RSDP_SIG (Table->Signature))
171    {
172        Rsdp = ACPI_CAST_PTR (ACPI_TABLE_RSDP, Table);
173        return (AcpiTbGetRsdpLength (Rsdp));
174    }
175
176    /* Normal ACPI table */
177
178    return (Table->Length);
179}
180
181
182/******************************************************************************
183 *
184 * FUNCTION:    ApDumpTableBuffer
185 *
186 * PARAMETERS:  Table               - ACPI table to be dumped
187 *              Instance            - ACPI table instance no. to be dumped
188 *              Address             - Physical address of the table
189 *
190 * RETURN:      None
191 *
192 * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
193 *              header that is compatible with the AcpiXtract utility.
194 *
195 ******************************************************************************/
196
197static int
198ApDumpTableBuffer (
199    ACPI_TABLE_HEADER       *Table,
200    UINT32                  Instance,
201    ACPI_PHYSICAL_ADDRESS   Address)
202{
203    UINT32                  TableLength;
204
205
206    TableLength = ApGetTableLength (Table);
207
208    /* Print only the header if requested */
209
210    if (Gbl_SummaryMode)
211    {
212        AcpiTbPrintTableHeader (Address, Table);
213        return (0);
214    }
215
216    /* Dump to binary file if requested */
217
218    if (Gbl_BinaryMode)
219    {
220        return (ApWriteToBinaryFile (Table, Instance));
221    }
222
223    /*
224     * Dump the table with header for use with acpixtract utility.
225     * Note: simplest to just always emit a 64-bit address. AcpiXtract
226     * utility can handle this.
227     */
228    fprintf (Gbl_OutputFile, "%4.4s @ 0x%8.8X%8.8X\n",
229        Table->Signature, ACPI_FORMAT_UINT64 (Address));
230
231    AcpiUtDumpBufferToFile (Gbl_OutputFile,
232        ACPI_CAST_PTR (UINT8, Table), TableLength,
233        DB_BYTE_DISPLAY, 0);
234    fprintf (Gbl_OutputFile, "\n");
235    return (0);
236}
237
238
239/******************************************************************************
240 *
241 * FUNCTION:    ApDumpAllTables
242 *
243 * PARAMETERS:  None
244 *
245 * RETURN:      Status
246 *
247 * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
248 *              tables that we can possibly get).
249 *
250 ******************************************************************************/
251
252int
253ApDumpAllTables (
254    void)
255{
256    ACPI_TABLE_HEADER       *Table;
257    UINT32                  Instance = 0;
258    ACPI_PHYSICAL_ADDRESS   Address;
259    ACPI_STATUS             Status;
260    int                     TableStatus;
261    UINT32                  i;
262
263
264    /* Get and dump all available ACPI tables */
265
266    for (i = 0; i < AP_MAX_ACPI_FILES; i++)
267    {
268        Status = AcpiOsGetTableByIndex (i, &Table, &Instance, &Address);
269        if (ACPI_FAILURE (Status))
270        {
271            /* AE_LIMIT means that no more tables are available */
272
273            if (Status == AE_LIMIT)
274            {
275                return (0);
276            }
277            else if (i == 0)
278            {
279                fprintf (stderr, "Could not get ACPI tables, %s\n",
280                    AcpiFormatException (Status));
281                return (-1);
282            }
283            else
284            {
285                fprintf (stderr, "Could not get ACPI table at index %u, %s\n",
286                    i, AcpiFormatException (Status));
287                continue;
288            }
289        }
290
291        TableStatus = ApDumpTableBuffer (Table, Instance, Address);
292        ACPI_FREE (Table);
293
294        if (TableStatus)
295        {
296            break;
297        }
298    }
299
300    /* Something seriously bad happened if the loop terminates here */
301
302    return (-1);
303}
304
305
306/******************************************************************************
307 *
308 * FUNCTION:    ApDumpTableByAddress
309 *
310 * PARAMETERS:  AsciiAddress        - Address for requested ACPI table
311 *
312 * RETURN:      Status
313 *
314 * DESCRIPTION: Get an ACPI table via a physical address and dump it.
315 *
316 ******************************************************************************/
317
318int
319ApDumpTableByAddress (
320    char                    *AsciiAddress)
321{
322    ACPI_PHYSICAL_ADDRESS   Address;
323    ACPI_TABLE_HEADER       *Table;
324    ACPI_STATUS             Status;
325    int                     TableStatus;
326    UINT64                  LongAddress;
327
328
329    /* Convert argument to an integer physical address */
330
331    Status = AcpiUtStrtoul64 (AsciiAddress, &LongAddress);
332    if (ACPI_FAILURE (Status))
333    {
334        fprintf (stderr, "%s: Could not convert to a physical address\n",
335            AsciiAddress);
336        return (-1);
337    }
338
339    Address = (ACPI_PHYSICAL_ADDRESS) LongAddress;
340    Status = AcpiOsGetTableByAddress (Address, &Table);
341    if (ACPI_FAILURE (Status))
342    {
343        fprintf (stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
344            ACPI_FORMAT_UINT64 (Address),
345            AcpiFormatException (Status));
346        return (-1);
347    }
348
349    TableStatus = ApDumpTableBuffer (Table, 0, Address);
350    ACPI_FREE (Table);
351    return (TableStatus);
352}
353
354
355/******************************************************************************
356 *
357 * FUNCTION:    ApDumpTableByName
358 *
359 * PARAMETERS:  Signature           - Requested ACPI table signature
360 *
361 * RETURN:      Status
362 *
363 * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
364 *              multiple tables with the same signature (SSDTs).
365 *
366 ******************************************************************************/
367
368int
369ApDumpTableByName (
370    char                    *Signature)
371{
372    char                    LocalSignature [ACPI_NAMESEG_SIZE + 1];
373    UINT32                  Instance;
374    ACPI_TABLE_HEADER       *Table;
375    ACPI_PHYSICAL_ADDRESS   Address;
376    ACPI_STATUS             Status;
377    int                     TableStatus;
378
379
380    if (strlen (Signature) != ACPI_NAMESEG_SIZE)
381    {
382        fprintf (stderr,
383            "Invalid table signature [%s]: must be exactly 4 characters\n",
384            Signature);
385        return (-1);
386    }
387
388    /* Table signatures are expected to be uppercase */
389
390    strcpy (LocalSignature, Signature);
391    AcpiUtStrupr (LocalSignature);
392
393    /* To be friendly, handle tables whose signatures do not match the name */
394
395    if (ACPI_COMPARE_NAMESEG (LocalSignature, "FADT"))
396    {
397        strcpy (LocalSignature, ACPI_SIG_FADT);
398    }
399    else if (ACPI_COMPARE_NAMESEG (LocalSignature, "MADT"))
400    {
401        strcpy (LocalSignature, ACPI_SIG_MADT);
402    }
403
404    /* Dump all instances of this signature (to handle multiple SSDTs) */
405
406    for (Instance = 0; Instance < AP_MAX_ACPI_FILES; Instance++)
407    {
408        Status = AcpiOsGetTableByName (LocalSignature, Instance,
409            &Table, &Address);
410        if (ACPI_FAILURE (Status))
411        {
412            /* AE_LIMIT means that no more tables are available */
413
414            if (Status == AE_LIMIT)
415            {
416                return (0);
417            }
418
419            fprintf (stderr,
420                "Could not get ACPI table with signature [%s], %s\n",
421                LocalSignature, AcpiFormatException (Status));
422            return (-1);
423        }
424
425        TableStatus = ApDumpTableBuffer (Table, Instance, Address);
426        ACPI_FREE (Table);
427
428        if (TableStatus)
429        {
430            break;
431        }
432    }
433
434    /* Something seriously bad happened if the loop terminates here */
435
436    return (-1);
437}
438
439
440/******************************************************************************
441 *
442 * FUNCTION:    ApDumpTableFromFile
443 *
444 * PARAMETERS:  Pathname            - File containing the binary ACPI table
445 *
446 * RETURN:      Status
447 *
448 * DESCRIPTION: Dump an ACPI table from a binary file
449 *
450 ******************************************************************************/
451
452int
453ApDumpTableFromFile (
454    char                    *Pathname)
455{
456    ACPI_TABLE_HEADER       *Table;
457    UINT32                  FileSize = 0;
458    int                     TableStatus = -1;
459
460
461    /* Get the entire ACPI table from the file */
462
463    Table = ApGetTableFromFile (Pathname, &FileSize);
464    if (!Table)
465    {
466        return (-1);
467    }
468
469    if (!AcpiUtValidNameseg (Table->Signature))
470    {
471        fprintf (stderr,
472            "No valid ACPI signature was found in input file %s\n",
473            Pathname);
474    }
475
476    /* File must be at least as long as the table length */
477
478    if (Table->Length > FileSize)
479    {
480        fprintf (stderr,
481            "Table length (0x%X) is too large for input file (0x%X) %s\n",
482            Table->Length, FileSize, Pathname);
483        goto Exit;
484    }
485
486    if (Gbl_VerboseMode)
487    {
488        fprintf (stderr,
489            "Input file:  %s contains table [%4.4s], 0x%X (%u) bytes\n",
490            Pathname, Table->Signature, FileSize, FileSize);
491    }
492
493    TableStatus = ApDumpTableBuffer (Table, 0, 0);
494
495Exit:
496    ACPI_FREE (Table);
497    return (TableStatus);
498}
499