linux/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
   5 *
   6 * Copyright (C) 2000 - 2021, Intel Corp.
   7 *
   8 *****************************************************************************/
   9
  10#include "acpidump.h"
  11
  12#define _COMPONENT          ACPI_OS_SERVICES
  13ACPI_MODULE_NAME("oslinuxtbl")
  14
  15#ifndef PATH_MAX
  16#define PATH_MAX 256
  17#endif
  18/* List of information about obtained ACPI tables */
  19typedef struct osl_table_info {
  20        struct osl_table_info *next;
  21        u32 instance;
  22        char signature[ACPI_NAMESEG_SIZE];
  23
  24} osl_table_info;
  25
  26/* Local prototypes */
  27
  28static acpi_status osl_table_initialize(void);
  29
  30static acpi_status
  31osl_table_name_from_file(char *filename, char *signature, u32 *instance);
  32
  33static acpi_status osl_add_table_to_list(char *signature, u32 instance);
  34
  35static acpi_status
  36osl_read_table_from_file(char *filename,
  37                         acpi_size file_offset,
  38                         struct acpi_table_header **table);
  39
  40static acpi_status
  41osl_map_table(acpi_size address,
  42              char *signature, struct acpi_table_header **table);
  43
  44static void osl_unmap_table(struct acpi_table_header *table);
  45
  46static acpi_physical_address
  47osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
  48
  49static acpi_physical_address osl_find_rsdp_via_efi(void);
  50
  51static acpi_status osl_load_rsdp(void);
  52
  53static acpi_status osl_list_customized_tables(char *directory);
  54
  55static acpi_status
  56osl_get_customized_table(char *pathname,
  57                         char *signature,
  58                         u32 instance,
  59                         struct acpi_table_header **table,
  60                         acpi_physical_address *address);
  61
  62static acpi_status osl_list_bios_tables(void);
  63
  64static acpi_status
  65osl_get_bios_table(char *signature,
  66                   u32 instance,
  67                   struct acpi_table_header **table,
  68                   acpi_physical_address *address);
  69
  70static acpi_status osl_get_last_status(acpi_status default_status);
  71
  72/* File locations */
  73
  74#define DYNAMIC_TABLE_DIR   "/sys/firmware/acpi/tables/dynamic"
  75#define STATIC_TABLE_DIR    "/sys/firmware/acpi/tables"
  76#define EFI_SYSTAB          "/sys/firmware/efi/systab"
  77
  78/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
  79
  80u8 gbl_dump_dynamic_tables = TRUE;
  81
  82/* Initialization flags */
  83
  84u8 gbl_table_list_initialized = FALSE;
  85
  86/* Local copies of main ACPI tables */
  87
  88struct acpi_table_rsdp gbl_rsdp;
  89struct acpi_table_fadt *gbl_fadt = NULL;
  90struct acpi_table_rsdt *gbl_rsdt = NULL;
  91struct acpi_table_xsdt *gbl_xsdt = NULL;
  92
  93/* Table addresses */
  94
  95acpi_physical_address gbl_fadt_address = 0;
  96acpi_physical_address gbl_rsdp_address = 0;
  97
  98/* Revision of RSD PTR */
  99
 100u8 gbl_revision = 0;
 101
 102struct osl_table_info *gbl_table_list_head = NULL;
 103u32 gbl_table_count = 0;
 104
 105/******************************************************************************
 106 *
 107 * FUNCTION:    osl_get_last_status
 108 *
 109 * PARAMETERS:  default_status  - Default error status to return
 110 *
 111 * RETURN:      Status; Converted from errno.
 112 *
 113 * DESCRIPTION: Get last errno and convert it to acpi_status.
 114 *
 115 *****************************************************************************/
 116
 117static acpi_status osl_get_last_status(acpi_status default_status)
 118{
 119
 120        switch (errno) {
 121        case EACCES:
 122        case EPERM:
 123
 124                return (AE_ACCESS);
 125
 126        case ENOENT:
 127
 128                return (AE_NOT_FOUND);
 129
 130        case ENOMEM:
 131
 132                return (AE_NO_MEMORY);
 133
 134        default:
 135
 136                return (default_status);
 137        }
 138}
 139
 140/******************************************************************************
 141 *
 142 * FUNCTION:    acpi_os_get_table_by_address
 143 *
 144 * PARAMETERS:  address         - Physical address of the ACPI table
 145 *              table           - Where a pointer to the table is returned
 146 *
 147 * RETURN:      Status; Table buffer is returned if AE_OK.
 148 *              AE_NOT_FOUND: A valid table was not found at the address
 149 *
 150 * DESCRIPTION: Get an ACPI table via a physical memory address.
 151 *
 152 *****************************************************************************/
 153
 154acpi_status
 155acpi_os_get_table_by_address(acpi_physical_address address,
 156                             struct acpi_table_header **table)
 157{
 158        u32 table_length;
 159        struct acpi_table_header *mapped_table;
 160        struct acpi_table_header *local_table = NULL;
 161        acpi_status status = AE_OK;
 162
 163        /* Get main ACPI tables from memory on first invocation of this function */
 164
 165        status = osl_table_initialize();
 166        if (ACPI_FAILURE(status)) {
 167                return (status);
 168        }
 169
 170        /* Map the table and validate it */
 171
 172        status = osl_map_table(address, NULL, &mapped_table);
 173        if (ACPI_FAILURE(status)) {
 174                return (status);
 175        }
 176
 177        /* Copy table to local buffer and return it */
 178
 179        table_length = ap_get_table_length(mapped_table);
 180        if (table_length == 0) {
 181                status = AE_BAD_HEADER;
 182                goto exit;
 183        }
 184
 185        local_table = calloc(1, table_length);
 186        if (!local_table) {
 187                status = AE_NO_MEMORY;
 188                goto exit;
 189        }
 190
 191        memcpy(local_table, mapped_table, table_length);
 192
 193exit:
 194        osl_unmap_table(mapped_table);
 195        *table = local_table;
 196        return (status);
 197}
 198
 199/******************************************************************************
 200 *
 201 * FUNCTION:    acpi_os_get_table_by_name
 202 *
 203 * PARAMETERS:  signature       - ACPI Signature for desired table. Must be
 204 *                                a null terminated 4-character string.
 205 *              instance        - Multiple table support for SSDT/UEFI (0...n)
 206 *                                Must be 0 for other tables.
 207 *              table           - Where a pointer to the table is returned
 208 *              address         - Where the table physical address is returned
 209 *
 210 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
 211 *              AE_LIMIT: Instance is beyond valid limit
 212 *              AE_NOT_FOUND: A table with the signature was not found
 213 *
 214 * NOTE:        Assumes the input signature is uppercase.
 215 *
 216 *****************************************************************************/
 217
 218acpi_status
 219acpi_os_get_table_by_name(char *signature,
 220                          u32 instance,
 221                          struct acpi_table_header **table,
 222                          acpi_physical_address *address)
 223{
 224        acpi_status status;
 225
 226        /* Get main ACPI tables from memory on first invocation of this function */
 227
 228        status = osl_table_initialize();
 229        if (ACPI_FAILURE(status)) {
 230                return (status);
 231        }
 232
 233        /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
 234
 235        if (!gbl_dump_customized_tables) {
 236
 237                /* Attempt to get the table from the memory */
 238
 239                status =
 240                    osl_get_bios_table(signature, instance, table, address);
 241        } else {
 242                /* Attempt to get the table from the static directory */
 243
 244                status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
 245                                                  instance, table, address);
 246        }
 247
 248        if (ACPI_FAILURE(status) && status == AE_LIMIT) {
 249                if (gbl_dump_dynamic_tables) {
 250
 251                        /* Attempt to get a dynamic table */
 252
 253                        status =
 254                            osl_get_customized_table(DYNAMIC_TABLE_DIR,
 255                                                     signature, instance, table,
 256                                                     address);
 257                }
 258        }
 259
 260        return (status);
 261}
 262
 263/******************************************************************************
 264 *
 265 * FUNCTION:    osl_add_table_to_list
 266 *
 267 * PARAMETERS:  signature       - Table signature
 268 *              instance        - Table instance
 269 *
 270 * RETURN:      Status; Successfully added if AE_OK.
 271 *              AE_NO_MEMORY: Memory allocation error
 272 *
 273 * DESCRIPTION: Insert a table structure into OSL table list.
 274 *
 275 *****************************************************************************/
 276
 277static acpi_status osl_add_table_to_list(char *signature, u32 instance)
 278{
 279        struct osl_table_info *new_info;
 280        struct osl_table_info *next;
 281        u32 next_instance = 0;
 282        u8 found = FALSE;
 283
 284        new_info = calloc(1, sizeof(struct osl_table_info));
 285        if (!new_info) {
 286                return (AE_NO_MEMORY);
 287        }
 288
 289        ACPI_COPY_NAMESEG(new_info->signature, signature);
 290
 291        if (!gbl_table_list_head) {
 292                gbl_table_list_head = new_info;
 293        } else {
 294                next = gbl_table_list_head;
 295                while (1) {
 296                        if (ACPI_COMPARE_NAMESEG(next->signature, signature)) {
 297                                if (next->instance == instance) {
 298                                        found = TRUE;
 299                                }
 300                                if (next->instance >= next_instance) {
 301                                        next_instance = next->instance + 1;
 302                                }
 303                        }
 304
 305                        if (!next->next) {
 306                                break;
 307                        }
 308                        next = next->next;
 309                }
 310                next->next = new_info;
 311        }
 312
 313        if (found) {
 314                if (instance) {
 315                        fprintf(stderr,
 316                                "%4.4s: Warning unmatched table instance %d, expected %d\n",
 317                                signature, instance, next_instance);
 318                }
 319                instance = next_instance;
 320        }
 321
 322        new_info->instance = instance;
 323        gbl_table_count++;
 324
 325        return (AE_OK);
 326}
 327
 328/******************************************************************************
 329 *
 330 * FUNCTION:    acpi_os_get_table_by_index
 331 *
 332 * PARAMETERS:  index           - Which table to get
 333 *              table           - Where a pointer to the table is returned
 334 *              instance        - Where a pointer to the table instance no. is
 335 *                                returned
 336 *              address         - Where the table physical address is returned
 337 *
 338 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
 339 *              AE_LIMIT: Index is beyond valid limit
 340 *
 341 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
 342 *              AE_LIMIT when an invalid index is reached. Index is not
 343 *              necessarily an index into the RSDT/XSDT.
 344 *
 345 *****************************************************************************/
 346
 347acpi_status
 348acpi_os_get_table_by_index(u32 index,
 349                           struct acpi_table_header **table,
 350                           u32 *instance, acpi_physical_address *address)
 351{
 352        struct osl_table_info *info;
 353        acpi_status status;
 354        u32 i;
 355
 356        /* Get main ACPI tables from memory on first invocation of this function */
 357
 358        status = osl_table_initialize();
 359        if (ACPI_FAILURE(status)) {
 360                return (status);
 361        }
 362
 363        /* Validate Index */
 364
 365        if (index >= gbl_table_count) {
 366                return (AE_LIMIT);
 367        }
 368
 369        /* Point to the table list entry specified by the Index argument */
 370
 371        info = gbl_table_list_head;
 372        for (i = 0; i < index; i++) {
 373                info = info->next;
 374        }
 375
 376        /* Now we can just get the table via the signature */
 377
 378        status = acpi_os_get_table_by_name(info->signature, info->instance,
 379                                           table, address);
 380
 381        if (ACPI_SUCCESS(status)) {
 382                *instance = info->instance;
 383        }
 384        return (status);
 385}
 386
 387/******************************************************************************
 388 *
 389 * FUNCTION:    osl_find_rsdp_via_efi_by_keyword
 390 *
 391 * PARAMETERS:  keyword         - Character string indicating ACPI GUID version
 392 *                                in the EFI table
 393 *
 394 * RETURN:      RSDP address if found
 395 *
 396 * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI
 397 *              GUID version.
 398 *
 399 *****************************************************************************/
 400
 401static acpi_physical_address
 402osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
 403{
 404        char buffer[80];
 405        unsigned long long address = 0;
 406        char format[32];
 407
 408        snprintf(format, 32, "%s=%s", keyword, "%llx");
 409        fseek(file, 0, SEEK_SET);
 410        while (fgets(buffer, 80, file)) {
 411                if (sscanf(buffer, format, &address) == 1) {
 412                        break;
 413                }
 414        }
 415
 416        return ((acpi_physical_address)(address));
 417}
 418
 419/******************************************************************************
 420 *
 421 * FUNCTION:    osl_find_rsdp_via_efi
 422 *
 423 * PARAMETERS:  None
 424 *
 425 * RETURN:      RSDP address if found
 426 *
 427 * DESCRIPTION: Find RSDP address via EFI.
 428 *
 429 *****************************************************************************/
 430
 431static acpi_physical_address osl_find_rsdp_via_efi(void)
 432{
 433        FILE *file;
 434        acpi_physical_address address = 0;
 435
 436        file = fopen(EFI_SYSTAB, "r");
 437        if (file) {
 438                address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
 439                if (!address) {
 440                        address =
 441                            osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
 442                }
 443                fclose(file);
 444        }
 445
 446        return (address);
 447}
 448
 449/******************************************************************************
 450 *
 451 * FUNCTION:    osl_load_rsdp
 452 *
 453 * PARAMETERS:  None
 454 *
 455 * RETURN:      Status
 456 *
 457 * DESCRIPTION: Scan and load RSDP.
 458 *
 459 *****************************************************************************/
 460
 461static acpi_status osl_load_rsdp(void)
 462{
 463        struct acpi_table_header *mapped_table;
 464        u8 *rsdp_address;
 465        acpi_physical_address rsdp_base;
 466        acpi_size rsdp_size;
 467
 468        /* Get RSDP from memory */
 469
 470        rsdp_size = sizeof(struct acpi_table_rsdp);
 471        if (gbl_rsdp_base) {
 472                rsdp_base = gbl_rsdp_base;
 473        } else {
 474                rsdp_base = osl_find_rsdp_via_efi();
 475        }
 476
 477        if (!rsdp_base) {
 478                rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
 479                rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
 480        }
 481
 482        rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
 483        if (!rsdp_address) {
 484                return (osl_get_last_status(AE_BAD_ADDRESS));
 485        }
 486
 487        /* Search low memory for the RSDP */
 488
 489        mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
 490                                     acpi_tb_scan_memory_for_rsdp(rsdp_address,
 491                                                                  rsdp_size));
 492        if (!mapped_table) {
 493                acpi_os_unmap_memory(rsdp_address, rsdp_size);
 494                return (AE_NOT_FOUND);
 495        }
 496
 497        gbl_rsdp_address =
 498            rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
 499
 500        memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
 501        acpi_os_unmap_memory(rsdp_address, rsdp_size);
 502
 503        return (AE_OK);
 504}
 505
 506/******************************************************************************
 507 *
 508 * FUNCTION:    osl_can_use_xsdt
 509 *
 510 * PARAMETERS:  None
 511 *
 512 * RETURN:      TRUE if XSDT is allowed to be used.
 513 *
 514 * DESCRIPTION: This function collects logic that can be used to determine if
 515 *              XSDT should be used instead of RSDT.
 516 *
 517 *****************************************************************************/
 518
 519static u8 osl_can_use_xsdt(void)
 520{
 521        if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
 522                return (TRUE);
 523        } else {
 524                return (FALSE);
 525        }
 526}
 527
 528/******************************************************************************
 529 *
 530 * FUNCTION:    osl_table_initialize
 531 *
 532 * PARAMETERS:  None
 533 *
 534 * RETURN:      Status
 535 *
 536 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
 537 *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
 538 *              and/or XSDT.
 539 *
 540 *****************************************************************************/
 541
 542static acpi_status osl_table_initialize(void)
 543{
 544        acpi_status status;
 545        acpi_physical_address address;
 546
 547        if (gbl_table_list_initialized) {
 548                return (AE_OK);
 549        }
 550
 551        if (!gbl_dump_customized_tables) {
 552
 553                /* Get RSDP from memory */
 554
 555                status = osl_load_rsdp();
 556                if (ACPI_FAILURE(status)) {
 557                        return (status);
 558                }
 559
 560                /* Get XSDT from memory */
 561
 562                if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {
 563                        if (gbl_xsdt) {
 564                                free(gbl_xsdt);
 565                                gbl_xsdt = NULL;
 566                        }
 567
 568                        gbl_revision = 2;
 569                        status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
 570                                                    ACPI_CAST_PTR(struct
 571                                                                  acpi_table_header
 572                                                                  *, &gbl_xsdt),
 573                                                    &address);
 574                        if (ACPI_FAILURE(status)) {
 575                                return (status);
 576                        }
 577                }
 578
 579                /* Get RSDT from memory */
 580
 581                if (gbl_rsdp.rsdt_physical_address) {
 582                        if (gbl_rsdt) {
 583                                free(gbl_rsdt);
 584                                gbl_rsdt = NULL;
 585                        }
 586
 587                        status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
 588                                                    ACPI_CAST_PTR(struct
 589                                                                  acpi_table_header
 590                                                                  *, &gbl_rsdt),
 591                                                    &address);
 592                        if (ACPI_FAILURE(status)) {
 593                                return (status);
 594                        }
 595                }
 596
 597                /* Get FADT from memory */
 598
 599                if (gbl_fadt) {
 600                        free(gbl_fadt);
 601                        gbl_fadt = NULL;
 602                }
 603
 604                status = osl_get_bios_table(ACPI_SIG_FADT, 0,
 605                                            ACPI_CAST_PTR(struct
 606                                                          acpi_table_header *,
 607                                                          &gbl_fadt),
 608                                            &gbl_fadt_address);
 609                if (ACPI_FAILURE(status)) {
 610                        return (status);
 611                }
 612
 613                /* Add mandatory tables to global table list first */
 614
 615                status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
 616                if (ACPI_FAILURE(status)) {
 617                        return (status);
 618                }
 619
 620                status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
 621                if (ACPI_FAILURE(status)) {
 622                        return (status);
 623                }
 624
 625                if (gbl_revision == 2) {
 626                        status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
 627                        if (ACPI_FAILURE(status)) {
 628                                return (status);
 629                        }
 630                }
 631
 632                status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
 633                if (ACPI_FAILURE(status)) {
 634                        return (status);
 635                }
 636
 637                status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
 638                if (ACPI_FAILURE(status)) {
 639                        return (status);
 640                }
 641
 642                /* Add all tables found in the memory */
 643
 644                status = osl_list_bios_tables();
 645                if (ACPI_FAILURE(status)) {
 646                        return (status);
 647                }
 648        } else {
 649                /* Add all tables found in the static directory */
 650
 651                status = osl_list_customized_tables(STATIC_TABLE_DIR);
 652                if (ACPI_FAILURE(status)) {
 653                        return (status);
 654                }
 655        }
 656
 657        if (gbl_dump_dynamic_tables) {
 658
 659                /* Add all dynamically loaded tables in the dynamic directory */
 660
 661                status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
 662                if (ACPI_FAILURE(status)) {
 663                        return (status);
 664                }
 665        }
 666
 667        gbl_table_list_initialized = TRUE;
 668        return (AE_OK);
 669}
 670
 671/******************************************************************************
 672 *
 673 * FUNCTION:    osl_list_bios_tables
 674 *
 675 * PARAMETERS:  None
 676 *
 677 * RETURN:      Status; Table list is initialized if AE_OK.
 678 *
 679 * DESCRIPTION: Add ACPI tables to the table list from memory.
 680 *
 681 * NOTE:        This works on Linux as table customization does not modify the
 682 *              addresses stored in RSDP/RSDT/XSDT/FADT.
 683 *
 684 *****************************************************************************/
 685
 686static acpi_status osl_list_bios_tables(void)
 687{
 688        struct acpi_table_header *mapped_table = NULL;
 689        u8 *table_data;
 690        u8 number_of_tables;
 691        u8 item_size;
 692        acpi_physical_address table_address = 0;
 693        acpi_status status = AE_OK;
 694        u32 i;
 695
 696        if (osl_can_use_xsdt()) {
 697                item_size = sizeof(u64);
 698                table_data =
 699                    ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
 700                number_of_tables =
 701                    (u8)((gbl_xsdt->header.length -
 702                          sizeof(struct acpi_table_header))
 703                         / item_size);
 704        } else {                /* Use RSDT if XSDT is not available */
 705
 706                item_size = sizeof(u32);
 707                table_data =
 708                    ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
 709                number_of_tables =
 710                    (u8)((gbl_rsdt->header.length -
 711                          sizeof(struct acpi_table_header))
 712                         / item_size);
 713        }
 714
 715        /* Search RSDT/XSDT for the requested table */
 716
 717        for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
 718                if (osl_can_use_xsdt()) {
 719                        table_address =
 720                            (acpi_physical_address)(*ACPI_CAST64(table_data));
 721                } else {
 722                        table_address =
 723                            (acpi_physical_address)(*ACPI_CAST32(table_data));
 724                }
 725
 726                /* Skip NULL entries in RSDT/XSDT */
 727
 728                if (table_address == 0) {
 729                        continue;
 730                }
 731
 732                status = osl_map_table(table_address, NULL, &mapped_table);
 733                if (ACPI_FAILURE(status)) {
 734                        return (status);
 735                }
 736
 737                osl_add_table_to_list(mapped_table->signature, 0);
 738                osl_unmap_table(mapped_table);
 739        }
 740
 741        return (AE_OK);
 742}
 743
 744/******************************************************************************
 745 *
 746 * FUNCTION:    osl_get_bios_table
 747 *
 748 * PARAMETERS:  signature       - ACPI Signature for common table. Must be
 749 *                                a null terminated 4-character string.
 750 *              instance        - Multiple table support for SSDT/UEFI (0...n)
 751 *                                Must be 0 for other tables.
 752 *              table           - Where a pointer to the table is returned
 753 *              address         - Where the table physical address is returned
 754 *
 755 * RETURN:      Status; Table buffer and physical address returned if AE_OK.
 756 *              AE_LIMIT: Instance is beyond valid limit
 757 *              AE_NOT_FOUND: A table with the signature was not found
 758 *
 759 * DESCRIPTION: Get a BIOS provided ACPI table
 760 *
 761 * NOTE:        Assumes the input signature is uppercase.
 762 *
 763 *****************************************************************************/
 764
 765static acpi_status
 766osl_get_bios_table(char *signature,
 767                   u32 instance,
 768                   struct acpi_table_header **table,
 769                   acpi_physical_address *address)
 770{
 771        struct acpi_table_header *local_table = NULL;
 772        struct acpi_table_header *mapped_table = NULL;
 773        u8 *table_data;
 774        u8 number_of_tables;
 775        u8 item_size;
 776        u32 current_instance = 0;
 777        acpi_physical_address table_address;
 778        acpi_physical_address first_table_address = 0;
 779        u32 table_length = 0;
 780        acpi_status status = AE_OK;
 781        u32 i;
 782
 783        /* Handle special tables whose addresses are not in RSDT/XSDT */
 784
 785        if (ACPI_COMPARE_NAMESEG(signature, ACPI_RSDP_NAME) ||
 786            ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT) ||
 787            ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT) ||
 788            ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT) ||
 789            ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
 790
 791find_next_instance:
 792
 793                table_address = 0;
 794
 795                /*
 796                 * Get the appropriate address, either 32-bit or 64-bit. Be very
 797                 * careful about the FADT length and validate table addresses.
 798                 * Note: The 64-bit addresses have priority.
 799                 */
 800                if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT)) {
 801                        if (current_instance < 2) {
 802                                if ((gbl_fadt->header.length >=
 803                                     MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
 804                                    && current_instance == 0) {
 805                                        table_address =
 806                                            (acpi_physical_address)gbl_fadt->
 807                                            Xdsdt;
 808                                } else
 809                                    if ((gbl_fadt->header.length >=
 810                                         MIN_FADT_FOR_DSDT)
 811                                        && gbl_fadt->dsdt !=
 812                                        first_table_address) {
 813                                        table_address =
 814                                            (acpi_physical_address)gbl_fadt->
 815                                            dsdt;
 816                                }
 817                        }
 818                } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
 819                        if (current_instance < 2) {
 820                                if ((gbl_fadt->header.length >=
 821                                     MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
 822                                    && current_instance == 0) {
 823                                        table_address =
 824                                            (acpi_physical_address)gbl_fadt->
 825                                            Xfacs;
 826                                } else
 827                                    if ((gbl_fadt->header.length >=
 828                                         MIN_FADT_FOR_FACS)
 829                                        && gbl_fadt->facs !=
 830                                        first_table_address) {
 831                                        table_address =
 832                                            (acpi_physical_address)gbl_fadt->
 833                                            facs;
 834                                }
 835                        }
 836                } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT)) {
 837                        if (!gbl_revision) {
 838                                return (AE_BAD_SIGNATURE);
 839                        }
 840                        if (current_instance == 0) {
 841                                table_address =
 842                                    (acpi_physical_address)gbl_rsdp.
 843                                    xsdt_physical_address;
 844                        }
 845                } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT)) {
 846                        if (current_instance == 0) {
 847                                table_address =
 848                                    (acpi_physical_address)gbl_rsdp.
 849                                    rsdt_physical_address;
 850                        }
 851                } else {
 852                        if (current_instance == 0) {
 853                                table_address =
 854                                    (acpi_physical_address)gbl_rsdp_address;
 855                                signature = ACPI_SIG_RSDP;
 856                        }
 857                }
 858
 859                if (table_address == 0) {
 860                        goto exit_find_table;
 861                }
 862
 863                /* Now we can get the requested special table */
 864
 865                status = osl_map_table(table_address, signature, &mapped_table);
 866                if (ACPI_FAILURE(status)) {
 867                        return (status);
 868                }
 869
 870                table_length = ap_get_table_length(mapped_table);
 871                if (first_table_address == 0) {
 872                        first_table_address = table_address;
 873                }
 874
 875                /* Match table instance */
 876
 877                if (current_instance != instance) {
 878                        osl_unmap_table(mapped_table);
 879                        mapped_table = NULL;
 880                        current_instance++;
 881                        goto find_next_instance;
 882                }
 883        } else {                /* Case for a normal ACPI table */
 884
 885                if (osl_can_use_xsdt()) {
 886                        item_size = sizeof(u64);
 887                        table_data =
 888                            ACPI_CAST8(gbl_xsdt) +
 889                            sizeof(struct acpi_table_header);
 890                        number_of_tables =
 891                            (u8)((gbl_xsdt->header.length -
 892                                  sizeof(struct acpi_table_header))
 893                                 / item_size);
 894                } else {        /* Use RSDT if XSDT is not available */
 895
 896                        item_size = sizeof(u32);
 897                        table_data =
 898                            ACPI_CAST8(gbl_rsdt) +
 899                            sizeof(struct acpi_table_header);
 900                        number_of_tables =
 901                            (u8)((gbl_rsdt->header.length -
 902                                  sizeof(struct acpi_table_header))
 903                                 / item_size);
 904                }
 905
 906                /* Search RSDT/XSDT for the requested table */
 907
 908                for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
 909                        if (osl_can_use_xsdt()) {
 910                                table_address =
 911                                    (acpi_physical_address)(*ACPI_CAST64
 912                                                            (table_data));
 913                        } else {
 914                                table_address =
 915                                    (acpi_physical_address)(*ACPI_CAST32
 916                                                            (table_data));
 917                        }
 918
 919                        /* Skip NULL entries in RSDT/XSDT */
 920
 921                        if (table_address == 0) {
 922                                continue;
 923                        }
 924
 925                        status =
 926                            osl_map_table(table_address, NULL, &mapped_table);
 927                        if (ACPI_FAILURE(status)) {
 928                                return (status);
 929                        }
 930                        table_length = mapped_table->length;
 931
 932                        /* Does this table match the requested signature? */
 933
 934                        if (!ACPI_COMPARE_NAMESEG
 935                            (mapped_table->signature, signature)) {
 936                                osl_unmap_table(mapped_table);
 937                                mapped_table = NULL;
 938                                continue;
 939                        }
 940
 941                        /* Match table instance (for SSDT/UEFI tables) */
 942
 943                        if (current_instance != instance) {
 944                                osl_unmap_table(mapped_table);
 945                                mapped_table = NULL;
 946                                current_instance++;
 947                                continue;
 948                        }
 949
 950                        break;
 951                }
 952        }
 953
 954exit_find_table:
 955
 956        if (!mapped_table) {
 957                return (AE_LIMIT);
 958        }
 959
 960        if (table_length == 0) {
 961                status = AE_BAD_HEADER;
 962                goto exit;
 963        }
 964
 965        /* Copy table to local buffer and return it */
 966
 967        local_table = calloc(1, table_length);
 968        if (!local_table) {
 969                status = AE_NO_MEMORY;
 970                goto exit;
 971        }
 972
 973        memcpy(local_table, mapped_table, table_length);
 974        *address = table_address;
 975        *table = local_table;
 976
 977exit:
 978        osl_unmap_table(mapped_table);
 979        return (status);
 980}
 981
 982/******************************************************************************
 983 *
 984 * FUNCTION:    osl_list_customized_tables
 985 *
 986 * PARAMETERS:  directory           - Directory that contains the tables
 987 *
 988 * RETURN:      Status; Table list is initialized if AE_OK.
 989 *
 990 * DESCRIPTION: Add ACPI tables to the table list from a directory.
 991 *
 992 *****************************************************************************/
 993
 994static acpi_status osl_list_customized_tables(char *directory)
 995{
 996        void *table_dir;
 997        u32 instance;
 998        char temp_name[ACPI_NAMESEG_SIZE];
 999        char *filename;
1000        acpi_status status = AE_OK;
1001
1002        /* Open the requested directory */
1003
1004        table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
1005        if (!table_dir) {
1006                return (osl_get_last_status(AE_NOT_FOUND));
1007        }
1008
1009        /* Examine all entries in this directory */
1010
1011        while ((filename = acpi_os_get_next_filename(table_dir))) {
1012
1013                /* Extract table name and instance number */
1014
1015                status =
1016                    osl_table_name_from_file(filename, temp_name, &instance);
1017
1018                /* Ignore meaningless files */
1019
1020                if (ACPI_FAILURE(status)) {
1021                        continue;
1022                }
1023
1024                /* Add new info node to global table list */
1025
1026                status = osl_add_table_to_list(temp_name, instance);
1027                if (ACPI_FAILURE(status)) {
1028                        break;
1029                }
1030        }
1031
1032        acpi_os_close_directory(table_dir);
1033        return (status);
1034}
1035
1036/******************************************************************************
1037 *
1038 * FUNCTION:    osl_map_table
1039 *
1040 * PARAMETERS:  address             - Address of the table in memory
1041 *              signature           - Optional ACPI Signature for desired table.
1042 *                                    Null terminated 4-character string.
1043 *              table               - Where a pointer to the mapped table is
1044 *                                    returned
1045 *
1046 * RETURN:      Status; Mapped table is returned if AE_OK.
1047 *              AE_NOT_FOUND: A valid table was not found at the address
1048 *
1049 * DESCRIPTION: Map entire ACPI table into caller's address space.
1050 *
1051 *****************************************************************************/
1052
1053static acpi_status
1054osl_map_table(acpi_size address,
1055              char *signature, struct acpi_table_header **table)
1056{
1057        struct acpi_table_header *mapped_table;
1058        u32 length;
1059
1060        if (!address) {
1061                return (AE_BAD_ADDRESS);
1062        }
1063
1064        /*
1065         * Map the header so we can get the table length.
1066         * Use sizeof (struct acpi_table_header) as:
1067         * 1. it is bigger than 24 to include RSDP->Length
1068         * 2. it is smaller than sizeof (struct acpi_table_rsdp)
1069         */
1070        mapped_table =
1071            acpi_os_map_memory(address, sizeof(struct acpi_table_header));
1072        if (!mapped_table) {
1073                fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1074                        ACPI_FORMAT_UINT64(address));
1075                return (osl_get_last_status(AE_BAD_ADDRESS));
1076        }
1077
1078        /* If specified, signature must match */
1079
1080        if (signature) {
1081                if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1082                        if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
1083                                acpi_os_unmap_memory(mapped_table,
1084                                                     sizeof(struct
1085                                                            acpi_table_header));
1086                                return (AE_BAD_SIGNATURE);
1087                        }
1088                } else
1089                    if (!ACPI_COMPARE_NAMESEG
1090                        (signature, mapped_table->signature)) {
1091                        acpi_os_unmap_memory(mapped_table,
1092                                             sizeof(struct acpi_table_header));
1093                        return (AE_BAD_SIGNATURE);
1094                }
1095        }
1096
1097        /* Map the entire table */
1098
1099        length = ap_get_table_length(mapped_table);
1100        acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
1101        if (length == 0) {
1102                return (AE_BAD_HEADER);
1103        }
1104
1105        mapped_table = acpi_os_map_memory(address, length);
1106        if (!mapped_table) {
1107                fprintf(stderr,
1108                        "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1109                        ACPI_FORMAT_UINT64(address), length);
1110                return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
1111        }
1112
1113        (void)ap_is_valid_checksum(mapped_table);
1114
1115        *table = mapped_table;
1116        return (AE_OK);
1117}
1118
1119/******************************************************************************
1120 *
1121 * FUNCTION:    osl_unmap_table
1122 *
1123 * PARAMETERS:  table               - A pointer to the mapped table
1124 *
1125 * RETURN:      None
1126 *
1127 * DESCRIPTION: Unmap entire ACPI table.
1128 *
1129 *****************************************************************************/
1130
1131static void osl_unmap_table(struct acpi_table_header *table)
1132{
1133        if (table) {
1134                acpi_os_unmap_memory(table, ap_get_table_length(table));
1135        }
1136}
1137
1138/******************************************************************************
1139 *
1140 * FUNCTION:    osl_table_name_from_file
1141 *
1142 * PARAMETERS:  filename            - File that contains the desired table
1143 *              signature           - Pointer to 4-character buffer to store
1144 *                                    extracted table signature.
1145 *              instance            - Pointer to integer to store extracted
1146 *                                    table instance number.
1147 *
1148 * RETURN:      Status; Table name is extracted if AE_OK.
1149 *
1150 * DESCRIPTION: Extract table signature and instance number from a table file
1151 *              name.
1152 *
1153 *****************************************************************************/
1154
1155static acpi_status
1156osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1157{
1158
1159        /* Ignore meaningless files */
1160
1161        if (strlen(filename) < ACPI_NAMESEG_SIZE) {
1162                return (AE_BAD_SIGNATURE);
1163        }
1164
1165        /* Extract instance number */
1166
1167        if (isdigit((int)filename[ACPI_NAMESEG_SIZE])) {
1168                sscanf(&filename[ACPI_NAMESEG_SIZE], "%u", instance);
1169        } else if (strlen(filename) != ACPI_NAMESEG_SIZE) {
1170                return (AE_BAD_SIGNATURE);
1171        } else {
1172                *instance = 0;
1173        }
1174
1175        /* Extract signature */
1176
1177        ACPI_COPY_NAMESEG(signature, filename);
1178        return (AE_OK);
1179}
1180
1181/******************************************************************************
1182 *
1183 * FUNCTION:    osl_read_table_from_file
1184 *
1185 * PARAMETERS:  filename            - File that contains the desired table
1186 *              file_offset         - Offset of the table in file
1187 *              table               - Where a pointer to the table is returned
1188 *
1189 * RETURN:      Status; Table buffer is returned if AE_OK.
1190 *
1191 * DESCRIPTION: Read a ACPI table from a file.
1192 *
1193 *****************************************************************************/
1194
1195static acpi_status
1196osl_read_table_from_file(char *filename,
1197                         acpi_size file_offset,
1198                         struct acpi_table_header **table)
1199{
1200        FILE *table_file;
1201        struct acpi_table_header header;
1202        struct acpi_table_header *local_table = NULL;
1203        u32 table_length;
1204        s32 count;
1205        acpi_status status = AE_OK;
1206
1207        /* Open the file */
1208
1209        table_file = fopen(filename, "rb");
1210        if (table_file == NULL) {
1211                fprintf(stderr, "Could not open table file: %s\n", filename);
1212                return (osl_get_last_status(AE_NOT_FOUND));
1213        }
1214
1215        fseek(table_file, file_offset, SEEK_SET);
1216
1217        /* Read the Table header to get the table length */
1218
1219        count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1220        if (count != sizeof(struct acpi_table_header)) {
1221                fprintf(stderr, "Could not read table header: %s\n", filename);
1222                status = AE_BAD_HEADER;
1223                goto exit;
1224        }
1225
1226#ifdef ACPI_OBSOLETE_FUNCTIONS
1227
1228        /* If signature is specified, it must match the table */
1229
1230        if (signature) {
1231                if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1232                        if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
1233                                fprintf(stderr,
1234                                        "Incorrect RSDP signature: found %8.8s\n",
1235                                        header.signature);
1236                                status = AE_BAD_SIGNATURE;
1237                                goto exit;
1238                        }
1239                } else if (!ACPI_COMPARE_NAMESEG(signature, header.signature)) {
1240                        fprintf(stderr,
1241                                "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1242                                signature, header.signature);
1243                        status = AE_BAD_SIGNATURE;
1244                        goto exit;
1245                }
1246        }
1247#endif
1248
1249        table_length = ap_get_table_length(&header);
1250        if (table_length == 0) {
1251                status = AE_BAD_HEADER;
1252                goto exit;
1253        }
1254
1255        /* Read the entire table into a local buffer */
1256
1257        local_table = calloc(1, table_length);
1258        if (!local_table) {
1259                fprintf(stderr,
1260                        "%4.4s: Could not allocate buffer for table of length %X\n",
1261                        header.signature, table_length);
1262                status = AE_NO_MEMORY;
1263                goto exit;
1264        }
1265
1266        fseek(table_file, file_offset, SEEK_SET);
1267
1268        count = fread(local_table, 1, table_length, table_file);
1269        if (count != table_length) {
1270                fprintf(stderr, "%4.4s: Could not read table content\n",
1271                        header.signature);
1272                status = AE_INVALID_TABLE_LENGTH;
1273                goto exit;
1274        }
1275
1276        /* Validate checksum */
1277
1278        (void)ap_is_valid_checksum(local_table);
1279
1280exit:
1281        fclose(table_file);
1282        *table = local_table;
1283        return (status);
1284}
1285
1286/******************************************************************************
1287 *
1288 * FUNCTION:    osl_get_customized_table
1289 *
1290 * PARAMETERS:  pathname        - Directory to find Linux customized table
1291 *              signature       - ACPI Signature for desired table. Must be
1292 *                                a null terminated 4-character string.
1293 *              instance        - Multiple table support for SSDT/UEFI (0...n)
1294 *                                Must be 0 for other tables.
1295 *              table           - Where a pointer to the table is returned
1296 *              address         - Where the table physical address is returned
1297 *
1298 * RETURN:      Status; Table buffer is returned if AE_OK.
1299 *              AE_LIMIT: Instance is beyond valid limit
1300 *              AE_NOT_FOUND: A table with the signature was not found
1301 *
1302 * DESCRIPTION: Get an OS customized table.
1303 *
1304 *****************************************************************************/
1305
1306static acpi_status
1307osl_get_customized_table(char *pathname,
1308                         char *signature,
1309                         u32 instance,
1310                         struct acpi_table_header **table,
1311                         acpi_physical_address *address)
1312{
1313        void *table_dir;
1314        u32 current_instance = 0;
1315        char temp_name[ACPI_NAMESEG_SIZE];
1316        char table_filename[PATH_MAX];
1317        char *filename;
1318        acpi_status status;
1319
1320        /* Open the directory for customized tables */
1321
1322        table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1323        if (!table_dir) {
1324                return (osl_get_last_status(AE_NOT_FOUND));
1325        }
1326
1327        /* Attempt to find the table in the directory */
1328
1329        while ((filename = acpi_os_get_next_filename(table_dir))) {
1330
1331                /* Ignore meaningless files */
1332
1333                if (!ACPI_COMPARE_NAMESEG(filename, signature)) {
1334                        continue;
1335                }
1336
1337                /* Extract table name and instance number */
1338
1339                status =
1340                    osl_table_name_from_file(filename, temp_name,
1341                                             &current_instance);
1342
1343                /* Ignore meaningless files */
1344
1345                if (ACPI_FAILURE(status) || current_instance != instance) {
1346                        continue;
1347                }
1348
1349                /* Create the table pathname */
1350
1351                if (instance != 0) {
1352                        sprintf(table_filename, "%s/%4.4s%d", pathname,
1353                                temp_name, instance);
1354                } else {
1355                        sprintf(table_filename, "%s/%4.4s", pathname,
1356                                temp_name);
1357                }
1358                break;
1359        }
1360
1361        acpi_os_close_directory(table_dir);
1362
1363        if (!filename) {
1364                return (AE_LIMIT);
1365        }
1366
1367        /* There is no physical address saved for customized tables, use zero */
1368
1369        *address = 0;
1370        status = osl_read_table_from_file(table_filename, 0, table);
1371
1372        return (status);
1373}
1374