linux/tools/power/acpi/tools/acpidump/apdump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: apdump - Dump routines for ACPI tables (acpidump)
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include "acpidump.h"
  11
  12/* Local prototypes */
  13
  14static int
  15ap_dump_table_buffer(struct acpi_table_header *table,
  16                     u32 instance, acpi_physical_address address);
  17
  18/******************************************************************************
  19 *
  20 * FUNCTION:    ap_is_valid_header
  21 *
  22 * PARAMETERS:  table               - Pointer to table to be validated
  23 *
  24 * RETURN:      TRUE if the header appears to be valid. FALSE otherwise
  25 *
  26 * DESCRIPTION: Check for a valid ACPI table header
  27 *
  28 ******************************************************************************/
  29
  30u8 ap_is_valid_header(struct acpi_table_header *table)
  31{
  32
  33        if (!ACPI_VALIDATE_RSDP_SIG(table->signature)) {
  34
  35                /* Make sure signature is all ASCII and a valid ACPI name */
  36
  37                if (!acpi_ut_valid_nameseg(table->signature)) {
  38                        fprintf(stderr,
  39                                "Table signature (0x%8.8X) is invalid\n",
  40                                *(u32 *)table->signature);
  41                        return (FALSE);
  42                }
  43
  44                /* Check for minimum table length */
  45
  46                if (table->length < sizeof(struct acpi_table_header)) {
  47                        fprintf(stderr, "Table length (0x%8.8X) is invalid\n",
  48                                table->length);
  49                        return (FALSE);
  50                }
  51        }
  52
  53        return (TRUE);
  54}
  55
  56/******************************************************************************
  57 *
  58 * FUNCTION:    ap_is_valid_checksum
  59 *
  60 * PARAMETERS:  table               - Pointer to table to be validated
  61 *
  62 * RETURN:      TRUE if the checksum appears to be valid. FALSE otherwise.
  63 *
  64 * DESCRIPTION: Check for a valid ACPI table checksum.
  65 *
  66 ******************************************************************************/
  67
  68u8 ap_is_valid_checksum(struct acpi_table_header *table)
  69{
  70        acpi_status status;
  71        struct acpi_table_rsdp *rsdp;
  72
  73        if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
  74                /*
  75                 * Checksum for RSDP.
  76                 * Note: Other checksums are computed during the table dump.
  77                 */
  78                rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
  79                status = acpi_tb_validate_rsdp(rsdp);
  80        } else {
  81                status = acpi_tb_verify_checksum(table, table->length);
  82        }
  83
  84        if (ACPI_FAILURE(status)) {
  85                fprintf(stderr, "%4.4s: Warning: wrong checksum in table\n",
  86                        table->signature);
  87        }
  88
  89        return (AE_OK);
  90}
  91
  92/******************************************************************************
  93 *
  94 * FUNCTION:    ap_get_table_length
  95 *
  96 * PARAMETERS:  table               - Pointer to the table
  97 *
  98 * RETURN:      Table length
  99 *
 100 * DESCRIPTION: Obtain table length according to table signature.
 101 *
 102 ******************************************************************************/
 103
 104u32 ap_get_table_length(struct acpi_table_header *table)
 105{
 106        struct acpi_table_rsdp *rsdp;
 107
 108        /* Check if table is valid */
 109
 110        if (!ap_is_valid_header(table)) {
 111                return (0);
 112        }
 113
 114        if (ACPI_VALIDATE_RSDP_SIG(table->signature)) {
 115                rsdp = ACPI_CAST_PTR(struct acpi_table_rsdp, table);
 116                return (acpi_tb_get_rsdp_length(rsdp));
 117        }
 118
 119        /* Normal ACPI table */
 120
 121        return (table->length);
 122}
 123
 124/******************************************************************************
 125 *
 126 * FUNCTION:    ap_dump_table_buffer
 127 *
 128 * PARAMETERS:  table               - ACPI table to be dumped
 129 *              instance            - ACPI table instance no. to be dumped
 130 *              address             - Physical address of the table
 131 *
 132 * RETURN:      None
 133 *
 134 * DESCRIPTION: Dump an ACPI table in standard ASCII hex format, with a
 135 *              header that is compatible with the acpi_xtract utility.
 136 *
 137 ******************************************************************************/
 138
 139static int
 140ap_dump_table_buffer(struct acpi_table_header *table,
 141                     u32 instance, acpi_physical_address address)
 142{
 143        u32 table_length;
 144
 145        table_length = ap_get_table_length(table);
 146
 147        /* Print only the header if requested */
 148
 149        if (gbl_summary_mode) {
 150                acpi_tb_print_table_header(address, table);
 151                return (0);
 152        }
 153
 154        /* Dump to binary file if requested */
 155
 156        if (gbl_binary_mode) {
 157                return (ap_write_to_binary_file(table, instance));
 158        }
 159
 160        /*
 161         * Dump the table with header for use with acpixtract utility.
 162         * Note: simplest to just always emit a 64-bit address. acpi_xtract
 163         * utility can handle this.
 164         */
 165        fprintf(gbl_output_file, "%4.4s @ 0x%8.8X%8.8X\n",
 166                table->signature, ACPI_FORMAT_UINT64(address));
 167
 168        acpi_ut_dump_buffer_to_file(gbl_output_file,
 169                                    ACPI_CAST_PTR(u8, table), table_length,
 170                                    DB_BYTE_DISPLAY, 0);
 171        fprintf(gbl_output_file, "\n");
 172        return (0);
 173}
 174
 175/******************************************************************************
 176 *
 177 * FUNCTION:    ap_dump_all_tables
 178 *
 179 * PARAMETERS:  None
 180 *
 181 * RETURN:      Status
 182 *
 183 * DESCRIPTION: Get all tables from the RSDT/XSDT (or at least all of the
 184 *              tables that we can possibly get).
 185 *
 186 ******************************************************************************/
 187
 188int ap_dump_all_tables(void)
 189{
 190        struct acpi_table_header *table;
 191        u32 instance = 0;
 192        acpi_physical_address address;
 193        acpi_status status;
 194        int table_status;
 195        u32 i;
 196
 197        /* Get and dump all available ACPI tables */
 198
 199        for (i = 0; i < AP_MAX_ACPI_FILES; i++) {
 200                status =
 201                    acpi_os_get_table_by_index(i, &table, &instance, &address);
 202                if (ACPI_FAILURE(status)) {
 203
 204                        /* AE_LIMIT means that no more tables are available */
 205
 206                        if (status == AE_LIMIT) {
 207                                return (0);
 208                        } else if (i == 0) {
 209                                fprintf(stderr,
 210                                        "Could not get ACPI tables, %s\n",
 211                                        acpi_format_exception(status));
 212                                return (-1);
 213                        } else {
 214                                fprintf(stderr,
 215                                        "Could not get ACPI table at index %u, %s\n",
 216                                        i, acpi_format_exception(status));
 217                                continue;
 218                        }
 219                }
 220
 221                table_status = ap_dump_table_buffer(table, instance, address);
 222                ACPI_FREE(table);
 223
 224                if (table_status) {
 225                        break;
 226                }
 227        }
 228
 229        /* Something seriously bad happened if the loop terminates here */
 230
 231        return (-1);
 232}
 233
 234/******************************************************************************
 235 *
 236 * FUNCTION:    ap_dump_table_by_address
 237 *
 238 * PARAMETERS:  ascii_address       - Address for requested ACPI table
 239 *
 240 * RETURN:      Status
 241 *
 242 * DESCRIPTION: Get an ACPI table via a physical address and dump it.
 243 *
 244 ******************************************************************************/
 245
 246int ap_dump_table_by_address(char *ascii_address)
 247{
 248        acpi_physical_address address;
 249        struct acpi_table_header *table;
 250        acpi_status status;
 251        int table_status;
 252        u64 long_address;
 253
 254        /* Convert argument to an integer physical address */
 255
 256        status = acpi_ut_strtoul64(ascii_address, &long_address);
 257        if (ACPI_FAILURE(status)) {
 258                fprintf(stderr, "%s: Could not convert to a physical address\n",
 259                        ascii_address);
 260                return (-1);
 261        }
 262
 263        address = (acpi_physical_address)long_address;
 264        status = acpi_os_get_table_by_address(address, &table);
 265        if (ACPI_FAILURE(status)) {
 266                fprintf(stderr, "Could not get table at 0x%8.8X%8.8X, %s\n",
 267                        ACPI_FORMAT_UINT64(address),
 268                        acpi_format_exception(status));
 269                return (-1);
 270        }
 271
 272        table_status = ap_dump_table_buffer(table, 0, address);
 273        ACPI_FREE(table);
 274        return (table_status);
 275}
 276
 277/******************************************************************************
 278 *
 279 * FUNCTION:    ap_dump_table_by_name
 280 *
 281 * PARAMETERS:  signature           - Requested ACPI table signature
 282 *
 283 * RETURN:      Status
 284 *
 285 * DESCRIPTION: Get an ACPI table via a signature and dump it. Handles
 286 *              multiple tables with the same signature (SSDTs).
 287 *
 288 ******************************************************************************/
 289
 290int ap_dump_table_by_name(char *signature)
 291{
 292        char local_signature[ACPI_NAMESEG_SIZE + 1];
 293        u32 instance;
 294        struct acpi_table_header *table;
 295        acpi_physical_address address;
 296        acpi_status status;
 297        int table_status;
 298
 299        if (strlen(signature) != ACPI_NAMESEG_SIZE) {
 300                fprintf(stderr,
 301                        "Invalid table signature [%s]: must be exactly 4 characters\n",
 302                        signature);
 303                return (-1);
 304        }
 305
 306        /* Table signatures are expected to be uppercase */
 307
 308        strcpy(local_signature, signature);
 309        acpi_ut_strupr(local_signature);
 310
 311        /* To be friendly, handle tables whose signatures do not match the name */
 312
 313        if (ACPI_COMPARE_NAMESEG(local_signature, "FADT")) {
 314                strcpy(local_signature, ACPI_SIG_FADT);
 315        } else if (ACPI_COMPARE_NAMESEG(local_signature, "MADT")) {
 316                strcpy(local_signature, ACPI_SIG_MADT);
 317        }
 318
 319        /* Dump all instances of this signature (to handle multiple SSDTs) */
 320
 321        for (instance = 0; instance < AP_MAX_ACPI_FILES; instance++) {
 322                status = acpi_os_get_table_by_name(local_signature, instance,
 323                                                   &table, &address);
 324                if (ACPI_FAILURE(status)) {
 325
 326                        /* AE_LIMIT means that no more tables are available */
 327
 328                        if (status == AE_LIMIT) {
 329                                return (0);
 330                        }
 331
 332                        fprintf(stderr,
 333                                "Could not get ACPI table with signature [%s], %s\n",
 334                                local_signature, acpi_format_exception(status));
 335                        return (-1);
 336                }
 337
 338                table_status = ap_dump_table_buffer(table, instance, address);
 339                ACPI_FREE(table);
 340
 341                if (table_status) {
 342                        break;
 343                }
 344        }
 345
 346        /* Something seriously bad happened if the loop terminates here */
 347
 348        return (-1);
 349}
 350
 351/******************************************************************************
 352 *
 353 * FUNCTION:    ap_dump_table_from_file
 354 *
 355 * PARAMETERS:  pathname            - File containing the binary ACPI table
 356 *
 357 * RETURN:      Status
 358 *
 359 * DESCRIPTION: Dump an ACPI table from a binary file
 360 *
 361 ******************************************************************************/
 362
 363int ap_dump_table_from_file(char *pathname)
 364{
 365        struct acpi_table_header *table;
 366        u32 file_size = 0;
 367        int table_status = -1;
 368
 369        /* Get the entire ACPI table from the file */
 370
 371        table = ap_get_table_from_file(pathname, &file_size);
 372        if (!table) {
 373                return (-1);
 374        }
 375
 376        if (!acpi_ut_valid_nameseg(table->signature)) {
 377                fprintf(stderr,
 378                        "No valid ACPI signature was found in input file %s\n",
 379                        pathname);
 380        }
 381
 382        /* File must be at least as long as the table length */
 383
 384        if (table->length > file_size) {
 385                fprintf(stderr,
 386                        "Table length (0x%X) is too large for input file (0x%X) %s\n",
 387                        table->length, file_size, pathname);
 388                goto exit;
 389        }
 390
 391        if (gbl_verbose_mode) {
 392                fprintf(stderr,
 393                        "Input file:  %s contains table [%4.4s], 0x%X (%u) bytes\n",
 394                        pathname, table->signature, file_size, file_size);
 395        }
 396
 397        table_status = ap_dump_table_buffer(table, 0, 0);
 398
 399exit:
 400        ACPI_FREE(table);
 401        return (table_status);
 402}
 403