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