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 - 2023, 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 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 convert 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 * table - Where a pointer to the table is returned 1188 * 1189 * RETURN: Status; Table buffer is returned if AE_OK. 1190 * 1191 * DESCRIPTION: Read a ACPI table from a file. 1192 * 1193 *****************************************************************************/ 1194 1195 static acpi_status 1196 osl_read_table_from_file(char *filename, 1197 acpi_size file_offset, 1198 struct acpi_table_header **table) 1199 { 1200 FILE *table_file; 1201 struct acpi_table_header header; 1202 struct acpi_table_header *local_table = NULL; 1203 u32 table_length; 1204 s32 count; 1205 acpi_status status = AE_OK; 1206 1207 /* Open the file */ 1208 1209 table_file = fopen(filename, "rb"); 1210 if (table_file == NULL) { 1211 fprintf(stderr, "Could not open table file: %s\n", filename); 1212 return (osl_get_last_status(AE_NOT_FOUND)); 1213 } 1214 1215 fseek(table_file, file_offset, SEEK_SET); 1216 1217 /* Read the Table header to get the table length */ 1218 1219 count = fread(&header, 1, sizeof(struct acpi_table_header), table_file); 1220 if (count != sizeof(struct acpi_table_header)) { 1221 fprintf(stderr, "Could not read table header: %s\n", filename); 1222 status = AE_BAD_HEADER; 1223 goto exit; 1224 } 1225 1226 #ifdef ACPI_OBSOLETE_FUNCTIONS 1227 1228 /* If signature is specified, it must match the table */ 1229 1230 if (signature) { 1231 if (ACPI_VALIDATE_RSDP_SIG(signature)) { 1232 if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) { 1233 fprintf(stderr, 1234 "Incorrect RSDP signature: found %8.8s\n", 1235 header.signature); 1236 status = AE_BAD_SIGNATURE; 1237 goto exit; 1238 } 1239 } else if (!ACPI_COMPARE_NAMESEG(signature, header.signature)) { 1240 fprintf(stderr, 1241 "Incorrect signature: Expecting %4.4s, found %4.4s\n", 1242 signature, header.signature); 1243 status = AE_BAD_SIGNATURE; 1244 goto exit; 1245 } 1246 } 1247 #endif 1248 1249 table_length = ap_get_table_length(&header); 1250 if (table_length == 0) { 1251 status = AE_BAD_HEADER; 1252 goto exit; 1253 } 1254 1255 /* Read the entire table into a local buffer */ 1256 1257 local_table = calloc(1, table_length); 1258 if (!local_table) { 1259 fprintf(stderr, 1260 "%4.4s: Could not allocate buffer for table of length %X\n", 1261 header.signature, table_length); 1262 status = AE_NO_MEMORY; 1263 goto exit; 1264 } 1265 1266 fseek(table_file, file_offset, SEEK_SET); 1267 1268 count = fread(local_table, 1, table_length, table_file); 1269 if (count != table_length) { 1270 fprintf(stderr, "%4.4s: Could not read table content\n", 1271 header.signature); 1272 status = AE_INVALID_TABLE_LENGTH; 1273 goto exit; 1274 } 1275 1276 /* Validate checksum */ 1277 1278 (void)ap_is_valid_checksum(local_table); 1279 1280 exit: 1281 fclose(table_file); 1282 *table = local_table; 1283 return (status); 1284 } 1285 1286 /****************************************************************************** 1287 * 1288 * FUNCTION: osl_get_customized_table 1289 * 1290 * PARAMETERS: pathname - Directory to find Linux customized table 1291 * signature - ACPI Signature for desired table. Must be 1292 * a null terminated 4-character string. 1293 * instance - Multiple table support for SSDT/UEFI (0...n) 1294 * Must be 0 for other tables. 1295 * table - Where a pointer to the table is returned 1296 * address - Where the table physical address is returned 1297 * 1298 * RETURN: Status; Table buffer is returned if AE_OK. 1299 * AE_LIMIT: Instance is beyond valid limit 1300 * AE_NOT_FOUND: A table with the signature was not found 1301 * 1302 * DESCRIPTION: Get an OS customized table. 1303 * 1304 *****************************************************************************/ 1305 1306 static acpi_status 1307 osl_get_customized_table(char *pathname, 1308 char *signature, 1309 u32 instance, 1310 struct acpi_table_header **table, 1311 acpi_physical_address *address) 1312 { 1313 void *table_dir; 1314 u32 current_instance = 0; 1315 char temp_name[ACPI_NAMESEG_SIZE]; 1316 char table_filename[PATH_MAX]; 1317 char *filename; 1318 acpi_status status; 1319 1320 /* Open the directory for customized tables */ 1321 1322 table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY); 1323 if (!table_dir) { 1324 return (osl_get_last_status(AE_NOT_FOUND)); 1325 } 1326 1327 /* Attempt to find the table in the directory */ 1328 1329 while ((filename = acpi_os_get_next_filename(table_dir))) { 1330 1331 /* Ignore meaningless files */ 1332 1333 if (!ACPI_COMPARE_NAMESEG(filename, signature)) { 1334 continue; 1335 } 1336 1337 /* Extract table name and instance number */ 1338 1339 status = 1340 osl_table_name_from_file(filename, temp_name, 1341 ¤t_instance); 1342 1343 /* Ignore meaningless files */ 1344 1345 if (ACPI_FAILURE(status) || current_instance != instance) { 1346 continue; 1347 } 1348 1349 /* Create the table pathname */ 1350 1351 if (instance != 0) { 1352 sprintf(table_filename, "%s/%4.4s%d", pathname, 1353 temp_name, instance); 1354 } else { 1355 sprintf(table_filename, "%s/%4.4s", pathname, 1356 temp_name); 1357 } 1358 break; 1359 } 1360 1361 acpi_os_close_directory(table_dir); 1362 1363 if (!filename) { 1364 return (AE_LIMIT); 1365 } 1366 1367 /* There is no physical address saved for customized tables, use zero */ 1368 1369 *address = 0; 1370 status = osl_read_table_from_file(table_filename, 0, table); 1371 1372 return (status); 1373 } 1374
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.