root/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. osl_get_last_status
  2. acpi_os_get_table_by_address
  3. acpi_os_get_table_by_name
  4. osl_add_table_to_list
  5. acpi_os_get_table_by_index
  6. osl_find_rsdp_via_efi_by_keyword
  7. osl_find_rsdp_via_efi
  8. osl_load_rsdp
  9. osl_can_use_xsdt
  10. osl_table_initialize
  11. osl_list_bios_tables
  12. osl_get_bios_table
  13. osl_list_customized_tables
  14. osl_map_table
  15. osl_unmap_table
  16. osl_table_name_from_file
  17. osl_read_table_from_file
  18. osl_get_customized_table

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

/* [<][>][^][v][top][bottom][index][help] */