linux/drivers/acpi/acpica/tbutils.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: tbutils - ACPI Table utilities
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include <acpi/acpi.h>
  11#include "accommon.h"
  12#include "actables.h"
  13
  14#define _COMPONENT          ACPI_TABLES
  15ACPI_MODULE_NAME("tbutils")
  16
  17/* Local prototypes */
  18static acpi_physical_address
  19acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
  20
  21#if (!ACPI_REDUCED_HARDWARE)
  22/*******************************************************************************
  23 *
  24 * FUNCTION:    acpi_tb_initialize_facs
  25 *
  26 * PARAMETERS:  None
  27 *
  28 * RETURN:      Status
  29 *
  30 * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
  31 *              for accessing the Global Lock and Firmware Waking Vector
  32 *
  33 ******************************************************************************/
  34
  35acpi_status acpi_tb_initialize_facs(void)
  36{
  37        struct acpi_table_facs *facs;
  38
  39        /* If Hardware Reduced flag is set, there is no FACS */
  40
  41        if (acpi_gbl_reduced_hardware) {
  42                acpi_gbl_FACS = NULL;
  43                return (AE_OK);
  44        } else if (acpi_gbl_FADT.Xfacs &&
  45                   (!acpi_gbl_FADT.facs
  46                    || !acpi_gbl_use32_bit_facs_addresses)) {
  47                (void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
  48                                              ACPI_CAST_INDIRECT_PTR(struct
  49                                                                     acpi_table_header,
  50                                                                     &facs));
  51                acpi_gbl_FACS = facs;
  52        } else if (acpi_gbl_FADT.facs) {
  53                (void)acpi_get_table_by_index(acpi_gbl_facs_index,
  54                                              ACPI_CAST_INDIRECT_PTR(struct
  55                                                                     acpi_table_header,
  56                                                                     &facs));
  57                acpi_gbl_FACS = facs;
  58        }
  59
  60        /* If there is no FACS, just continue. There was already an error msg */
  61
  62        return (AE_OK);
  63}
  64#endif                          /* !ACPI_REDUCED_HARDWARE */
  65
  66/*******************************************************************************
  67 *
  68 * FUNCTION:    acpi_tb_check_dsdt_header
  69 *
  70 * PARAMETERS:  None
  71 *
  72 * RETURN:      None
  73 *
  74 * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
  75 *              if the DSDT has been replaced from outside the OS and/or if
  76 *              the DSDT header has been corrupted.
  77 *
  78 ******************************************************************************/
  79
  80void acpi_tb_check_dsdt_header(void)
  81{
  82
  83        /* Compare original length and checksum to current values */
  84
  85        if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length ||
  86            acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) {
  87                ACPI_BIOS_ERROR((AE_INFO,
  88                                 "The DSDT has been corrupted or replaced - "
  89                                 "old, new headers below"));
  90
  91                acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
  92                acpi_tb_print_table_header(0, acpi_gbl_DSDT);
  93
  94                ACPI_ERROR((AE_INFO,
  95                            "Please send DMI info to linux-acpi@vger.kernel.org\n"
  96                            "If system does not work as expected, please boot with acpi=copy_dsdt"));
  97
  98                /* Disable further error messages */
  99
 100                acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length;
 101                acpi_gbl_original_dsdt_header.checksum =
 102                    acpi_gbl_DSDT->checksum;
 103        }
 104}
 105
 106/*******************************************************************************
 107 *
 108 * FUNCTION:    acpi_tb_copy_dsdt
 109 *
 110 * PARAMETERS:  table_index         - Index of installed table to copy
 111 *
 112 * RETURN:      The copied DSDT
 113 *
 114 * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
 115 *              Some very bad BIOSs are known to either corrupt the DSDT or
 116 *              install a new, bad DSDT. This copy works around the problem.
 117 *
 118 ******************************************************************************/
 119
 120struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
 121{
 122        struct acpi_table_header *new_table;
 123        struct acpi_table_desc *table_desc;
 124
 125        table_desc = &acpi_gbl_root_table_list.tables[table_index];
 126
 127        new_table = ACPI_ALLOCATE(table_desc->length);
 128        if (!new_table) {
 129                ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X",
 130                            table_desc->length));
 131                return (NULL);
 132        }
 133
 134        memcpy(new_table, table_desc->pointer, table_desc->length);
 135        acpi_tb_uninstall_table(table_desc);
 136
 137        acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
 138                                      tables[acpi_gbl_dsdt_index],
 139                                      ACPI_PTR_TO_PHYSADDR(new_table),
 140                                      ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
 141                                      new_table);
 142
 143        ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
 144
 145        return (new_table);
 146}
 147
 148/*******************************************************************************
 149 *
 150 * FUNCTION:    acpi_tb_get_root_table_entry
 151 *
 152 * PARAMETERS:  table_entry         - Pointer to the RSDT/XSDT table entry
 153 *              table_entry_size    - sizeof 32 or 64 (RSDT or XSDT)
 154 *
 155 * RETURN:      Physical address extracted from the root table
 156 *
 157 * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
 158 *              both 32-bit and 64-bit platforms
 159 *
 160 * NOTE:        acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
 161 *              64-bit platforms.
 162 *
 163 ******************************************************************************/
 164
 165static acpi_physical_address
 166acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
 167{
 168        u64 address64;
 169
 170        /*
 171         * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
 172         * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
 173         */
 174        if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
 175                /*
 176                 * 32-bit platform, RSDT: Return 32-bit table entry
 177                 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
 178                 */
 179                return ((acpi_physical_address)
 180                        (*ACPI_CAST_PTR(u32, table_entry)));
 181        } else {
 182                /*
 183                 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
 184                 * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
 185                 *  return 64-bit
 186                 */
 187                ACPI_MOVE_64_TO_64(&address64, table_entry);
 188
 189#if ACPI_MACHINE_WIDTH == 32
 190                if (address64 > ACPI_UINT32_MAX) {
 191
 192                        /* Will truncate 64-bit address to 32 bits, issue warning */
 193
 194                        ACPI_BIOS_WARNING((AE_INFO,
 195                                           "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
 196                                           " truncating",
 197                                           ACPI_FORMAT_UINT64(address64)));
 198                }
 199#endif
 200                return ((acpi_physical_address)(address64));
 201        }
 202}
 203
 204/*******************************************************************************
 205 *
 206 * FUNCTION:    acpi_tb_parse_root_table
 207 *
 208 * PARAMETERS:  rsdp_address        - Pointer to the RSDP
 209 *
 210 * RETURN:      Status
 211 *
 212 * DESCRIPTION: This function is called to parse the Root System Description
 213 *              Table (RSDT or XSDT)
 214 *
 215 * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
 216 *              be mapped and cannot be copied because it contains the actual
 217 *              memory location of the ACPI Global Lock.
 218 *
 219 ******************************************************************************/
 220
 221acpi_status ACPI_INIT_FUNCTION
 222acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
 223{
 224        struct acpi_table_rsdp *rsdp;
 225        u32 table_entry_size;
 226        u32 i;
 227        u32 table_count;
 228        struct acpi_table_header *table;
 229        acpi_physical_address address;
 230        u32 length;
 231        u8 *table_entry;
 232        acpi_status status;
 233        u32 table_index;
 234
 235        ACPI_FUNCTION_TRACE(tb_parse_root_table);
 236
 237        /* Map the entire RSDP and extract the address of the RSDT or XSDT */
 238
 239        rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
 240        if (!rsdp) {
 241                return_ACPI_STATUS(AE_NO_MEMORY);
 242        }
 243
 244        acpi_tb_print_table_header(rsdp_address,
 245                                   ACPI_CAST_PTR(struct acpi_table_header,
 246                                                 rsdp));
 247
 248        /* Use XSDT if present and not overridden. Otherwise, use RSDT */
 249
 250        if ((rsdp->revision > 1) &&
 251            rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
 252                /*
 253                 * RSDP contains an XSDT (64-bit physical addresses). We must use
 254                 * the XSDT if the revision is > 1 and the XSDT pointer is present,
 255                 * as per the ACPI specification.
 256                 */
 257                address = (acpi_physical_address)rsdp->xsdt_physical_address;
 258                table_entry_size = ACPI_XSDT_ENTRY_SIZE;
 259        } else {
 260                /* Root table is an RSDT (32-bit physical addresses) */
 261
 262                address = (acpi_physical_address)rsdp->rsdt_physical_address;
 263                table_entry_size = ACPI_RSDT_ENTRY_SIZE;
 264        }
 265
 266        /*
 267         * It is not possible to map more than one entry in some environments,
 268         * so unmap the RSDP here before mapping other tables
 269         */
 270        acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
 271
 272        /* Map the RSDT/XSDT table header to get the full table length */
 273
 274        table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
 275        if (!table) {
 276                return_ACPI_STATUS(AE_NO_MEMORY);
 277        }
 278
 279        acpi_tb_print_table_header(address, table);
 280
 281        /*
 282         * Validate length of the table, and map entire table.
 283         * Minimum length table must contain at least one entry.
 284         */
 285        length = table->length;
 286        acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
 287
 288        if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
 289                ACPI_BIOS_ERROR((AE_INFO,
 290                                 "Invalid table length 0x%X in RSDT/XSDT",
 291                                 length));
 292                return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
 293        }
 294
 295        table = acpi_os_map_memory(address, length);
 296        if (!table) {
 297                return_ACPI_STATUS(AE_NO_MEMORY);
 298        }
 299
 300        /* Validate the root table checksum */
 301
 302        status = acpi_tb_verify_checksum(table, length);
 303        if (ACPI_FAILURE(status)) {
 304                acpi_os_unmap_memory(table, length);
 305                return_ACPI_STATUS(status);
 306        }
 307
 308        /* Get the number of entries and pointer to first entry */
 309
 310        table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
 311                            table_entry_size);
 312        table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
 313
 314        /* Initialize the root table array from the RSDT/XSDT */
 315
 316        for (i = 0; i < table_count; i++) {
 317
 318                /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
 319
 320                address =
 321                    acpi_tb_get_root_table_entry(table_entry, table_entry_size);
 322
 323                /* Skip NULL entries in RSDT/XSDT */
 324
 325                if (!address) {
 326                        goto next_table;
 327                }
 328
 329                status = acpi_tb_install_standard_table(address,
 330                                                        ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
 331                                                        FALSE, TRUE,
 332                                                        &table_index);
 333
 334                if (ACPI_SUCCESS(status) &&
 335                    ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list.
 336                                         tables[table_index].signature,
 337                                         ACPI_SIG_FADT)) {
 338                        acpi_gbl_fadt_index = table_index;
 339                        acpi_tb_parse_fadt();
 340                }
 341
 342next_table:
 343
 344                table_entry += table_entry_size;
 345        }
 346
 347        acpi_os_unmap_memory(table, length);
 348        return_ACPI_STATUS(AE_OK);
 349}
 350
 351/*******************************************************************************
 352 *
 353 * FUNCTION:    acpi_tb_get_table
 354 *
 355 * PARAMETERS:  table_desc          - Table descriptor
 356 *              out_table           - Where the pointer to the table is returned
 357 *
 358 * RETURN:      Status and pointer to the requested table
 359 *
 360 * DESCRIPTION: Increase a reference to a table descriptor and return the
 361 *              validated table pointer.
 362 *              If the table descriptor is an entry of the root table list,
 363 *              this API must be invoked with ACPI_MTX_TABLES acquired.
 364 *
 365 ******************************************************************************/
 366
 367acpi_status
 368acpi_tb_get_table(struct acpi_table_desc *table_desc,
 369                  struct acpi_table_header **out_table)
 370{
 371        acpi_status status;
 372
 373        ACPI_FUNCTION_TRACE(acpi_tb_get_table);
 374
 375        if (table_desc->validation_count == 0) {
 376
 377                /* Table need to be "VALIDATED" */
 378
 379                status = acpi_tb_validate_table(table_desc);
 380                if (ACPI_FAILURE(status)) {
 381                        return_ACPI_STATUS(status);
 382                }
 383        }
 384
 385        if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
 386                table_desc->validation_count++;
 387
 388                /*
 389                 * Detect validation_count overflows to ensure that the warning
 390                 * message will only be printed once.
 391                 */
 392                if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
 393                        ACPI_WARNING((AE_INFO,
 394                                      "Table %p, Validation count overflows\n",
 395                                      table_desc));
 396                }
 397        }
 398
 399        *out_table = table_desc->pointer;
 400        return_ACPI_STATUS(AE_OK);
 401}
 402
 403/*******************************************************************************
 404 *
 405 * FUNCTION:    acpi_tb_put_table
 406 *
 407 * PARAMETERS:  table_desc          - Table descriptor
 408 *
 409 * RETURN:      None
 410 *
 411 * DESCRIPTION: Decrease a reference to a table descriptor and release the
 412 *              validated table pointer if no references.
 413 *              If the table descriptor is an entry of the root table list,
 414 *              this API must be invoked with ACPI_MTX_TABLES acquired.
 415 *
 416 ******************************************************************************/
 417
 418void acpi_tb_put_table(struct acpi_table_desc *table_desc)
 419{
 420
 421        ACPI_FUNCTION_TRACE(acpi_tb_put_table);
 422
 423        if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
 424                table_desc->validation_count--;
 425
 426                /*
 427                 * Detect validation_count underflows to ensure that the warning
 428                 * message will only be printed once.
 429                 */
 430                if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
 431                        ACPI_WARNING((AE_INFO,
 432                                      "Table %p, Validation count underflows\n",
 433                                      table_desc));
 434                        return_VOID;
 435                }
 436        }
 437
 438        if (table_desc->validation_count == 0) {
 439
 440                /* Table need to be "INVALIDATED" */
 441
 442                acpi_tb_invalidate_table(table_desc);
 443        }
 444
 445        return_VOID;
 446}
 447