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 == 0) {
 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;
 812        acpi_physical_address first_table_address = 0;
 813        u32 table_length = 0;
 814        acpi_status status = AE_OK;
 815        u32 i;
 816
 817        /* Handle special tables whose addresses are not in RSDT/XSDT */
 818
 819        if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) ||
 820            ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) ||
 821            ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
 822            ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
 823            ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
 824
 825find_next_instance:
 826
 827                table_address = 0;
 828
 829                /*
 830                 * Get the appropriate address, either 32-bit or 64-bit. Be very
 831                 * careful about the FADT length and validate table addresses.
 832                 * Note: The 64-bit addresses have priority.
 833                 */
 834                if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
 835                        if (current_instance < 2) {
 836                                if ((gbl_fadt->header.length >=
 837                                     MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
 838                                    && current_instance == 0) {
 839                                        table_address =
 840                                            (acpi_physical_address)gbl_fadt->
 841                                            Xdsdt;
 842                                } else
 843                                    if ((gbl_fadt->header.length >=
 844                                         MIN_FADT_FOR_DSDT)
 845                                        && gbl_fadt->dsdt !=
 846                                        first_table_address) {
 847                                        table_address =
 848                                            (acpi_physical_address)gbl_fadt->
 849                                            dsdt;
 850                                }
 851                        }
 852                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
 853                        if (current_instance < 2) {
 854                                if ((gbl_fadt->header.length >=
 855                                     MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
 856                                    && current_instance == 0) {
 857                                        table_address =
 858                                            (acpi_physical_address)gbl_fadt->
 859                                            Xfacs;
 860                                } else
 861                                    if ((gbl_fadt->header.length >=
 862                                         MIN_FADT_FOR_FACS)
 863                                        && gbl_fadt->facs !=
 864                                        first_table_address) {
 865                                        table_address =
 866                                            (acpi_physical_address)gbl_fadt->
 867                                            facs;
 868                                }
 869                        }
 870                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
 871                        if (!gbl_revision) {
 872                                return (AE_BAD_SIGNATURE);
 873                        }
 874                        if (current_instance == 0) {
 875                                table_address =
 876                                    (acpi_physical_address)gbl_rsdp.
 877                                    xsdt_physical_address;
 878                        }
 879                } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
 880                        if (current_instance == 0) {
 881                                table_address =
 882                                    (acpi_physical_address)gbl_rsdp.
 883                                    rsdt_physical_address;
 884                        }
 885                } else {
 886                        if (current_instance == 0) {
 887                                table_address =
 888                                    (acpi_physical_address)gbl_rsdp_address;
 889                                signature = ACPI_SIG_RSDP;
 890                        }
 891                }
 892
 893                if (table_address == 0) {
 894                        goto exit_find_table;
 895                }
 896
 897                /* Now we can get the requested special table */
 898
 899                status = osl_map_table(table_address, signature, &mapped_table);
 900                if (ACPI_FAILURE(status)) {
 901                        return (status);
 902                }
 903
 904                table_length = ap_get_table_length(mapped_table);
 905                if (first_table_address == 0) {
 906                        first_table_address = table_address;
 907                }
 908
 909                /* Match table instance */
 910
 911                if (current_instance != instance) {
 912                        osl_unmap_table(mapped_table);
 913                        mapped_table = NULL;
 914                        current_instance++;
 915                        goto find_next_instance;
 916                }
 917        } else {                /* Case for a normal ACPI table */
 918
 919                if (osl_can_use_xsdt()) {
 920                        item_size = sizeof(u64);
 921                        table_data =
 922                            ACPI_CAST8(gbl_xsdt) +
 923                            sizeof(struct acpi_table_header);
 924                        number_of_tables =
 925                            (u8)((gbl_xsdt->header.length -
 926                                  sizeof(struct acpi_table_header))
 927                                 / item_size);
 928                } else {        /* Use RSDT if XSDT is not available */
 929
 930                        item_size = sizeof(u32);
 931                        table_data =
 932                            ACPI_CAST8(gbl_rsdt) +
 933                            sizeof(struct acpi_table_header);
 934                        number_of_tables =
 935                            (u8)((gbl_rsdt->header.length -
 936                                  sizeof(struct acpi_table_header))
 937                                 / item_size);
 938                }
 939
 940                /* Search RSDT/XSDT for the requested table */
 941
 942                for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
 943                        if (osl_can_use_xsdt()) {
 944                                table_address =
 945                                    (acpi_physical_address)(*ACPI_CAST64
 946                                                            (table_data));
 947                        } else {
 948                                table_address =
 949                                    (acpi_physical_address)(*ACPI_CAST32
 950                                                            (table_data));
 951                        }
 952
 953                        /* Skip NULL entries in RSDT/XSDT */
 954
 955                        if (table_address == 0) {
 956                                continue;
 957                        }
 958
 959                        status =
 960                            osl_map_table(table_address, NULL, &mapped_table);
 961                        if (ACPI_FAILURE(status)) {
 962                                return (status);
 963                        }
 964                        table_length = mapped_table->length;
 965
 966                        /* Does this table match the requested signature? */
 967
 968                        if (!ACPI_COMPARE_NAME
 969                            (mapped_table->signature, signature)) {
 970                                osl_unmap_table(mapped_table);
 971                                mapped_table = NULL;
 972                                continue;
 973                        }
 974
 975                        /* Match table instance (for SSDT/UEFI tables) */
 976
 977                        if (current_instance != instance) {
 978                                osl_unmap_table(mapped_table);
 979                                mapped_table = NULL;
 980                                current_instance++;
 981                                continue;
 982                        }
 983
 984                        break;
 985                }
 986        }
 987
 988exit_find_table:
 989
 990        if (!mapped_table) {
 991                return (AE_LIMIT);
 992        }
 993
 994        if (table_length == 0) {
 995                status = AE_BAD_HEADER;
 996                goto exit;
 997        }
 998
 999        /* Copy table to local buffer and return it */
1000
1001        local_table = calloc(1, table_length);
1002        if (!local_table) {
1003                status = AE_NO_MEMORY;
1004                goto exit;
1005        }
1006
1007        memcpy(local_table, mapped_table, table_length);
1008        *address = table_address;
1009        *table = local_table;
1010
1011exit:
1012        osl_unmap_table(mapped_table);
1013        return (status);
1014}
1015
1016/******************************************************************************
1017 *
1018 * FUNCTION:    osl_list_customized_tables
1019 *
1020 * PARAMETERS:  directory           - Directory that contains the tables
1021 *
1022 * RETURN:      Status; Table list is initialized if AE_OK.
1023 *
1024 * DESCRIPTION: Add ACPI tables to the table list from a directory.
1025 *
1026 *****************************************************************************/
1027
1028static acpi_status osl_list_customized_tables(char *directory)
1029{
1030        void *table_dir;
1031        u32 instance;
1032        char temp_name[ACPI_NAME_SIZE];
1033        char *filename;
1034        acpi_status status = AE_OK;
1035
1036        /* Open the requested directory */
1037
1038        table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
1039        if (!table_dir) {
1040                return (osl_get_last_status(AE_NOT_FOUND));
1041        }
1042
1043        /* Examine all entries in this directory */
1044
1045        while ((filename = acpi_os_get_next_filename(table_dir))) {
1046
1047                /* Extract table name and instance number */
1048
1049                status =
1050                    osl_table_name_from_file(filename, temp_name, &instance);
1051
1052                /* Ignore meaningless files */
1053
1054                if (ACPI_FAILURE(status)) {
1055                        continue;
1056                }
1057
1058                /* Add new info node to global table list */
1059
1060                status = osl_add_table_to_list(temp_name, instance);
1061                if (ACPI_FAILURE(status)) {
1062                        break;
1063                }
1064        }
1065
1066        acpi_os_close_directory(table_dir);
1067        return (status);
1068}
1069
1070/******************************************************************************
1071 *
1072 * FUNCTION:    osl_map_table
1073 *
1074 * PARAMETERS:  address             - Address of the table in memory
1075 *              signature           - Optional ACPI Signature for desired table.
1076 *                                    Null terminated 4-character string.
1077 *              table               - Where a pointer to the mapped table is
1078 *                                    returned
1079 *
1080 * RETURN:      Status; Mapped table is returned if AE_OK.
1081 *              AE_NOT_FOUND: A valid table was not found at the address
1082 *
1083 * DESCRIPTION: Map entire ACPI table into caller's address space.
1084 *
1085 *****************************************************************************/
1086
1087static acpi_status
1088osl_map_table(acpi_size address,
1089              char *signature, struct acpi_table_header **table)
1090{
1091        struct acpi_table_header *mapped_table;
1092        u32 length;
1093
1094        if (!address) {
1095                return (AE_BAD_ADDRESS);
1096        }
1097
1098        /*
1099         * Map the header so we can get the table length.
1100         * Use sizeof (struct acpi_table_header) as:
1101         * 1. it is bigger than 24 to include RSDP->Length
1102         * 2. it is smaller than sizeof (struct acpi_table_rsdp)
1103         */
1104        mapped_table =
1105            acpi_os_map_memory(address, sizeof(struct acpi_table_header));
1106        if (!mapped_table) {
1107                fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1108                        ACPI_FORMAT_UINT64(address));
1109                return (osl_get_last_status(AE_BAD_ADDRESS));
1110        }
1111
1112        /* If specified, signature must match */
1113
1114        if (signature) {
1115                if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1116                        if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
1117                                acpi_os_unmap_memory(mapped_table,
1118                                                     sizeof(struct
1119                                                            acpi_table_header));
1120                                return (AE_BAD_SIGNATURE);
1121                        }
1122                } else
1123                    if (!ACPI_COMPARE_NAME(signature, mapped_table->signature))
1124                {
1125                        acpi_os_unmap_memory(mapped_table,
1126                                             sizeof(struct acpi_table_header));
1127                        return (AE_BAD_SIGNATURE);
1128                }
1129        }
1130
1131        /* Map the entire table */
1132
1133        length = ap_get_table_length(mapped_table);
1134        acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
1135        if (length == 0) {
1136                return (AE_BAD_HEADER);
1137        }
1138
1139        mapped_table = acpi_os_map_memory(address, length);
1140        if (!mapped_table) {
1141                fprintf(stderr,
1142                        "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1143                        ACPI_FORMAT_UINT64(address), length);
1144                return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
1145        }
1146
1147        (void)ap_is_valid_checksum(mapped_table);
1148
1149        *table = mapped_table;
1150        return (AE_OK);
1151}
1152
1153/******************************************************************************
1154 *
1155 * FUNCTION:    osl_unmap_table
1156 *
1157 * PARAMETERS:  table               - A pointer to the mapped table
1158 *
1159 * RETURN:      None
1160 *
1161 * DESCRIPTION: Unmap entire ACPI table.
1162 *
1163 *****************************************************************************/
1164
1165static void osl_unmap_table(struct acpi_table_header *table)
1166{
1167        if (table) {
1168                acpi_os_unmap_memory(table, ap_get_table_length(table));
1169        }
1170}
1171
1172/******************************************************************************
1173 *
1174 * FUNCTION:    osl_table_name_from_file
1175 *
1176 * PARAMETERS:  filename            - File that contains the desired table
1177 *              signature           - Pointer to 4-character buffer to store
1178 *                                    extracted table signature.
1179 *              instance            - Pointer to integer to store extracted
1180 *                                    table instance number.
1181 *
1182 * RETURN:      Status; Table name is extracted if AE_OK.
1183 *
1184 * DESCRIPTION: Extract table signature and instance number from a table file
1185 *              name.
1186 *
1187 *****************************************************************************/
1188
1189static acpi_status
1190osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1191{
1192
1193        /* Ignore meaningless files */
1194
1195        if (strlen(filename) < ACPI_NAME_SIZE) {
1196                return (AE_BAD_SIGNATURE);
1197        }
1198
1199        /* Extract instance number */
1200
1201        if (isdigit((int)filename[ACPI_NAME_SIZE])) {
1202                sscanf(&filename[ACPI_NAME_SIZE], "%u", instance);
1203        } else if (strlen(filename) != ACPI_NAME_SIZE) {
1204                return (AE_BAD_SIGNATURE);
1205        } else {
1206                *instance = 0;
1207        }
1208
1209        /* Extract signature */
1210
1211        ACPI_MOVE_NAME(signature, filename);
1212        return (AE_OK);
1213}
1214
1215/******************************************************************************
1216 *
1217 * FUNCTION:    osl_read_table_from_file
1218 *
1219 * PARAMETERS:  filename            - File that contains the desired table
1220 *              file_offset         - Offset of the table in file
1221 *              signature           - Optional ACPI Signature for desired table.
1222 *                                    A null terminated 4-character string.
1223 *              table               - Where a pointer to the table is returned
1224 *
1225 * RETURN:      Status; Table buffer is returned if AE_OK.
1226 *
1227 * DESCRIPTION: Read a ACPI table from a file.
1228 *
1229 *****************************************************************************/
1230
1231static acpi_status
1232osl_read_table_from_file(char *filename,
1233                         acpi_size file_offset,
1234                         char *signature, struct acpi_table_header **table)
1235{
1236        FILE *table_file;
1237        struct acpi_table_header header;
1238        struct acpi_table_header *local_table = NULL;
1239        u32 table_length;
1240        s32 count;
1241        acpi_status status = AE_OK;
1242
1243        /* Open the file */
1244
1245        table_file = fopen(filename, "rb");
1246        if (table_file == NULL) {
1247                fprintf(stderr, "Could not open table file: %s\n", filename);
1248                return (osl_get_last_status(AE_NOT_FOUND));
1249        }
1250
1251        fseek(table_file, file_offset, SEEK_SET);
1252
1253        /* Read the Table header to get the table length */
1254
1255        count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1256        if (count != sizeof(struct acpi_table_header)) {
1257                fprintf(stderr, "Could not read table header: %s\n", filename);
1258                status = AE_BAD_HEADER;
1259                goto exit;
1260        }
1261
1262        /* If signature is specified, it must match the table */
1263
1264        if (signature) {
1265                if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1266                        if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
1267                                fprintf(stderr,
1268                                        "Incorrect RSDP signature: found %8.8s\n",
1269                                        header.signature);
1270                                status = AE_BAD_SIGNATURE;
1271                                goto exit;
1272                        }
1273                } else if (!ACPI_COMPARE_NAME(signature, header.signature)) {
1274                        fprintf(stderr,
1275                                "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1276                                signature, header.signature);
1277                        status = AE_BAD_SIGNATURE;
1278                        goto exit;
1279                }
1280        }
1281
1282        table_length = ap_get_table_length(&header);
1283        if (table_length == 0) {
1284                status = AE_BAD_HEADER;
1285                goto exit;
1286        }
1287
1288        /* Read the entire table into a local buffer */
1289
1290        local_table = calloc(1, table_length);
1291        if (!local_table) {
1292                fprintf(stderr,
1293                        "%4.4s: Could not allocate buffer for table of length %X\n",
1294                        header.signature, table_length);
1295                status = AE_NO_MEMORY;
1296                goto exit;
1297        }
1298
1299        fseek(table_file, file_offset, SEEK_SET);
1300
1301        count = fread(local_table, 1, table_length, table_file);
1302        if (count != table_length) {
1303                fprintf(stderr, "%4.4s: Could not read table content\n",
1304                        header.signature);
1305                status = AE_INVALID_TABLE_LENGTH;
1306                goto exit;
1307        }
1308
1309        /* Validate checksum */
1310
1311        (void)ap_is_valid_checksum(local_table);
1312
1313exit:
1314        fclose(table_file);
1315        *table = local_table;
1316        return (status);
1317}
1318
1319/******************************************************************************
1320 *
1321 * FUNCTION:    osl_get_customized_table
1322 *
1323 * PARAMETERS:  pathname        - Directory to find Linux customized table
1324 *              signature       - ACPI Signature for desired table. Must be
1325 *                                a null terminated 4-character string.
1326 *              instance        - Multiple table support for SSDT/UEFI (0...n)
1327 *                                Must be 0 for other tables.
1328 *              table           - Where a pointer to the table is returned
1329 *              address         - Where the table physical address is returned
1330 *
1331 * RETURN:      Status; Table buffer is returned if AE_OK.
1332 *              AE_LIMIT: Instance is beyond valid limit
1333 *              AE_NOT_FOUND: A table with the signature was not found
1334 *
1335 * DESCRIPTION: Get an OS customized table.
1336 *
1337 *****************************************************************************/
1338
1339static acpi_status
1340osl_get_customized_table(char *pathname,
1341                         char *signature,
1342                         u32 instance,
1343                         struct acpi_table_header **table,
1344                         acpi_physical_address *address)
1345{
1346        void *table_dir;
1347        u32 current_instance = 0;
1348        char temp_name[ACPI_NAME_SIZE];
1349        char table_filename[PATH_MAX];
1350        char *filename;
1351        acpi_status status;
1352
1353        /* Open the directory for customized tables */
1354
1355        table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1356        if (!table_dir) {
1357                return (osl_get_last_status(AE_NOT_FOUND));
1358        }
1359
1360        /* Attempt to find the table in the directory */
1361
1362        while ((filename = acpi_os_get_next_filename(table_dir))) {
1363
1364                /* Ignore meaningless files */
1365
1366                if (!ACPI_COMPARE_NAME(filename, signature)) {
1367                        continue;
1368                }
1369
1370                /* Extract table name and instance number */
1371
1372                status =
1373                    osl_table_name_from_file(filename, temp_name,
1374                                             &current_instance);
1375
1376                /* Ignore meaningless files */
1377
1378                if (ACPI_FAILURE(status) || current_instance != instance) {
1379                        continue;
1380                }
1381
1382                /* Create the table pathname */
1383
1384                if (instance != 0) {
1385                        sprintf(table_filename, "%s/%4.4s%d", pathname,
1386                                temp_name, instance);
1387                } else {
1388                        sprintf(table_filename, "%s/%4.4s", pathname,
1389                                temp_name);
1390                }
1391                break;
1392        }
1393
1394        acpi_os_close_directory(table_dir);
1395
1396        if (!filename) {
1397                return (AE_LIMIT);
1398        }
1399
1400        /* There is no physical address saved for customized tables, use zero */
1401
1402        *address = 0;
1403        status = osl_read_table_from_file(table_filename, 0, NULL, table);
1404
1405        return (status);
1406}
1407