1374 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include "acpidump.h"11 12#define _COMPONENT ACPI_OS_SERVICES13ACPI_MODULE_NAME("oslinuxtbl")14 15#ifndef PATH_MAX16#define PATH_MAX 25617#endif18/* List of information about obtained ACPI tables */19typedef struct osl_table_info {20 struct osl_table_info *next;21 u32 instance;22 char signature[ACPI_NAMESEG_SIZE];23 24} osl_table_info;25 26/* Local prototypes */27 28static acpi_status osl_table_initialize(void);29 30static acpi_status31osl_table_name_from_file(char *filename, char *signature, u32 *instance);32 33static acpi_status osl_add_table_to_list(char *signature, u32 instance);34 35static acpi_status36osl_read_table_from_file(char *filename,37 acpi_size file_offset,38 struct acpi_table_header **table);39 40static acpi_status41osl_map_table(acpi_size address,42 char *signature, struct acpi_table_header **table);43 44static void osl_unmap_table(struct acpi_table_header *table);45 46static acpi_physical_address47osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);48 49static acpi_physical_address osl_find_rsdp_via_efi(void);50 51static acpi_status osl_load_rsdp(void);52 53static acpi_status osl_list_customized_tables(char *directory);54 55static acpi_status56osl_get_customized_table(char *pathname,57 char *signature,58 u32 instance,59 struct acpi_table_header **table,60 acpi_physical_address *address);61 62static acpi_status osl_list_bios_tables(void);63 64static acpi_status65osl_get_bios_table(char *signature,66 u32 instance,67 struct acpi_table_header **table,68 acpi_physical_address *address);69 70static acpi_status osl_get_last_status(acpi_status default_status);71 72/* File locations */73 74#define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic"75#define STATIC_TABLE_DIR "/sys/firmware/acpi/tables"76#define EFI_SYSTAB "/sys/firmware/efi/systab"77 78/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */79 80u8 gbl_dump_dynamic_tables = TRUE;81 82/* Initialization flags */83 84u8 gbl_table_list_initialized = FALSE;85 86/* Local copies of main ACPI tables */87 88struct acpi_table_rsdp gbl_rsdp;89struct acpi_table_fadt *gbl_fadt = NULL;90struct acpi_table_rsdt *gbl_rsdt = NULL;91struct acpi_table_xsdt *gbl_xsdt = NULL;92 93/* Table addresses */94 95acpi_physical_address gbl_fadt_address = 0;96acpi_physical_address gbl_rsdp_address = 0;97 98/* Revision of RSD PTR */99 100u8 gbl_revision = 0;101 102struct osl_table_info *gbl_table_list_head = NULL;103u32 gbl_table_count = 0;104 105/******************************************************************************106 *107 * FUNCTION: osl_get_last_status108 *109 * PARAMETERS: default_status - Default error status to return110 *111 * RETURN: Status; Converted from errno.112 *113 * DESCRIPTION: Get last errno and convert it to acpi_status.114 *115 *****************************************************************************/116 117static acpi_status osl_get_last_status(acpi_status default_status)118{119 120 switch (errno) {121 case EACCES:122 case EPERM:123 124 return (AE_ACCESS);125 126 case ENOENT:127 128 return (AE_NOT_FOUND);129 130 case ENOMEM:131 132 return (AE_NO_MEMORY);133 134 default:135 136 return (default_status);137 }138}139 140/******************************************************************************141 *142 * FUNCTION: acpi_os_get_table_by_address143 *144 * PARAMETERS: address - Physical address of the ACPI table145 * table - Where a pointer to the table is returned146 *147 * RETURN: Status; Table buffer is returned if AE_OK.148 * AE_NOT_FOUND: A valid table was not found at the address149 *150 * DESCRIPTION: Get an ACPI table via a physical memory address.151 *152 *****************************************************************************/153 154acpi_status155acpi_os_get_table_by_address(acpi_physical_address address,156 struct acpi_table_header **table)157{158 u32 table_length;159 struct acpi_table_header *mapped_table;160 struct acpi_table_header *local_table = NULL;161 acpi_status status = AE_OK;162 163 /* Get main ACPI tables from memory on first invocation of this function */164 165 status = osl_table_initialize();166 if (ACPI_FAILURE(status)) {167 return (status);168 }169 170 /* Map the table and validate it */171 172 status = osl_map_table(address, NULL, &mapped_table);173 if (ACPI_FAILURE(status)) {174 return (status);175 }176 177 /* Copy table to local buffer and return it */178 179 table_length = ap_get_table_length(mapped_table);180 if (table_length == 0) {181 status = AE_BAD_HEADER;182 goto exit;183 }184 185 local_table = calloc(1, table_length);186 if (!local_table) {187 status = AE_NO_MEMORY;188 goto exit;189 }190 191 memcpy(local_table, mapped_table, table_length);192 193exit:194 osl_unmap_table(mapped_table);195 *table = local_table;196 return (status);197}198 199/******************************************************************************200 *201 * FUNCTION: acpi_os_get_table_by_name202 *203 * PARAMETERS: signature - ACPI Signature for desired table. Must be204 * 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 returned208 * address - Where the table physical address is returned209 *210 * RETURN: Status; Table buffer and physical address returned if AE_OK.211 * AE_LIMIT: Instance is beyond valid limit212 * AE_NOT_FOUND: A table with the signature was not found213 *214 * NOTE: Assumes the input signature is uppercase.215 *216 *****************************************************************************/217 218acpi_status219acpi_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_list266 *267 * PARAMETERS: signature - Table signature268 * instance - Table instance269 *270 * RETURN: Status; Successfully added if AE_OK.271 * AE_NO_MEMORY: Memory allocation error272 *273 * DESCRIPTION: Insert a table structure into OSL table list.274 *275 *****************************************************************************/276 277static acpi_status osl_add_table_to_list(char *signature, u32 instance)278{279 struct osl_table_info *new_info;280 struct osl_table_info *next;281 u32 next_instance = 0;282 u8 found = FALSE;283 284 new_info = calloc(1, sizeof(struct osl_table_info));285 if (!new_info) {286 return (AE_NO_MEMORY);287 }288 289 ACPI_COPY_NAMESEG(new_info->signature, signature);290 291 if (!gbl_table_list_head) {292 gbl_table_list_head = new_info;293 } else {294 next = gbl_table_list_head;295 while (1) {296 if (ACPI_COMPARE_NAMESEG(next->signature, signature)) {297 if (next->instance == instance) {298 found = TRUE;299 }300 if (next->instance >= next_instance) {301 next_instance = next->instance + 1;302 }303 }304 305 if (!next->next) {306 break;307 }308 next = next->next;309 }310 next->next = new_info;311 }312 313 if (found) {314 if (instance) {315 fprintf(stderr,316 "%4.4s: Warning unmatched table instance %d, expected %d\n",317 signature, instance, next_instance);318 }319 instance = next_instance;320 }321 322 new_info->instance = instance;323 gbl_table_count++;324 325 return (AE_OK);326}327 328/******************************************************************************329 *330 * FUNCTION: acpi_os_get_table_by_index331 *332 * PARAMETERS: index - Which table to get333 * table - Where a pointer to the table is returned334 * instance - Where a pointer to the table instance no. is335 * returned336 * address - Where the table physical address is returned337 *338 * RETURN: Status; Table buffer and physical address returned if AE_OK.339 * AE_LIMIT: Index is beyond valid limit340 *341 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns342 * AE_LIMIT when an invalid index is reached. Index is not343 * necessarily an index into the RSDT/XSDT.344 *345 *****************************************************************************/346 347acpi_status348acpi_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_keyword390 *391 * PARAMETERS: keyword - Character string indicating ACPI GUID version392 * in the EFI table393 *394 * RETURN: RSDP address if found395 *396 * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI397 * GUID version.398 *399 *****************************************************************************/400 401static acpi_physical_address402osl_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_efi422 *423 * PARAMETERS: None424 *425 * RETURN: RSDP address if found426 *427 * DESCRIPTION: Find RSDP address via EFI.428 *429 *****************************************************************************/430 431static acpi_physical_address osl_find_rsdp_via_efi(void)432{433 FILE *file;434 acpi_physical_address address = 0;435 436 file = fopen(EFI_SYSTAB, "r");437 if (file) {438 address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");439 if (!address) {440 address =441 osl_find_rsdp_via_efi_by_keyword(file, "ACPI");442 }443 fclose(file);444 }445 446 return (address);447}448 449/******************************************************************************450 *451 * FUNCTION: osl_load_rsdp452 *453 * PARAMETERS: None454 *455 * RETURN: Status456 *457 * DESCRIPTION: Scan and load RSDP.458 *459 *****************************************************************************/460 461static acpi_status osl_load_rsdp(void)462{463 struct acpi_table_header *mapped_table;464 u8 *rsdp_address;465 acpi_physical_address rsdp_base;466 acpi_size rsdp_size;467 468 /* Get RSDP from memory */469 470 rsdp_size = sizeof(struct acpi_table_rsdp);471 if (gbl_rsdp_base) {472 rsdp_base = gbl_rsdp_base;473 } else {474 rsdp_base = osl_find_rsdp_via_efi();475 }476 477 if (!rsdp_base) {478 rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;479 rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;480 }481 482 rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);483 if (!rsdp_address) {484 return (osl_get_last_status(AE_BAD_ADDRESS));485 }486 487 /* Search low memory for the RSDP */488 489 mapped_table = ACPI_CAST_PTR(struct acpi_table_header,490 acpi_tb_scan_memory_for_rsdp(rsdp_address,491 rsdp_size));492 if (!mapped_table) {493 acpi_os_unmap_memory(rsdp_address, rsdp_size);494 return (AE_NOT_FOUND);495 }496 497 gbl_rsdp_address =498 rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);499 500 memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));501 acpi_os_unmap_memory(rsdp_address, rsdp_size);502 503 return (AE_OK);504}505 506/******************************************************************************507 *508 * FUNCTION: osl_can_use_xsdt509 *510 * PARAMETERS: None511 *512 * RETURN: TRUE if XSDT is allowed to be used.513 *514 * DESCRIPTION: This function collects logic that can be used to determine if515 * XSDT should be used instead of RSDT.516 *517 *****************************************************************************/518 519static u8 osl_can_use_xsdt(void)520{521 if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {522 return (TRUE);523 } else {524 return (FALSE);525 }526}527 528/******************************************************************************529 *530 * FUNCTION: osl_table_initialize531 *532 * PARAMETERS: None533 *534 * RETURN: Status535 *536 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to537 * local variables. Main ACPI tables include RSDT, FADT, RSDT,538 * and/or XSDT.539 *540 *****************************************************************************/541 542static acpi_status osl_table_initialize(void)543{544 acpi_status status;545 acpi_physical_address address;546 547 if (gbl_table_list_initialized) {548 return (AE_OK);549 }550 551 if (!gbl_dump_customized_tables) {552 553 /* Get RSDP from memory */554 555 status = osl_load_rsdp();556 if (ACPI_FAILURE(status)) {557 return (status);558 }559 560 /* Get XSDT from memory */561 562 if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {563 if (gbl_xsdt) {564 free(gbl_xsdt);565 gbl_xsdt = NULL;566 }567 568 gbl_revision = 2;569 status = osl_get_bios_table(ACPI_SIG_XSDT, 0,570 ACPI_CAST_PTR(struct571 acpi_table_header572 *, &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(struct589 acpi_table_header590 *, &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(struct606 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_tables674 *675 * PARAMETERS: None676 *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 the682 * addresses stored in RSDP/RSDT/XSDT/FADT.683 *684 *****************************************************************************/685 686static acpi_status osl_list_bios_tables(void)687{688 struct acpi_table_header *mapped_table = NULL;689 u8 *table_data;690 u8 number_of_tables;691 u8 item_size;692 acpi_physical_address table_address = 0;693 acpi_status status = AE_OK;694 u32 i;695 696 if (osl_can_use_xsdt()) {697 item_size = sizeof(u64);698 table_data =699 ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);700 number_of_tables =701 (u8)((gbl_xsdt->header.length -702 sizeof(struct acpi_table_header))703 / item_size);704 } else { /* Use RSDT if XSDT is not available */705 706 item_size = sizeof(u32);707 table_data =708 ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);709 number_of_tables =710 (u8)((gbl_rsdt->header.length -711 sizeof(struct acpi_table_header))712 / item_size);713 }714 715 /* Search RSDT/XSDT for the requested table */716 717 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {718 if (osl_can_use_xsdt()) {719 table_address =720 (acpi_physical_address)(*ACPI_CAST64(table_data));721 } else {722 table_address =723 (acpi_physical_address)(*ACPI_CAST32(table_data));724 }725 726 /* Skip NULL entries in RSDT/XSDT */727 728 if (table_address == 0) {729 continue;730 }731 732 status = osl_map_table(table_address, NULL, &mapped_table);733 if (ACPI_FAILURE(status)) {734 return (status);735 }736 737 osl_add_table_to_list(mapped_table->signature, 0);738 osl_unmap_table(mapped_table);739 }740 741 return (AE_OK);742}743 744/******************************************************************************745 *746 * FUNCTION: osl_get_bios_table747 *748 * PARAMETERS: signature - ACPI Signature for common table. Must be749 * 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 returned753 * address - Where the table physical address is returned754 *755 * RETURN: Status; Table buffer and physical address returned if AE_OK.756 * AE_LIMIT: Instance is beyond valid limit757 * AE_NOT_FOUND: A table with the signature was not found758 *759 * DESCRIPTION: Get a BIOS provided ACPI table760 *761 * NOTE: Assumes the input signature is uppercase.762 *763 *****************************************************************************/764 765static acpi_status766osl_get_bios_table(char *signature,767 u32 instance,768 struct acpi_table_header **table,769 acpi_physical_address *address)770{771 struct acpi_table_header *local_table = NULL;772 struct acpi_table_header *mapped_table = NULL;773 u8 *table_data;774 u8 number_of_tables;775 u8 item_size;776 u32 current_instance = 0;777 acpi_physical_address table_address;778 acpi_physical_address first_table_address = 0;779 u32 table_length = 0;780 acpi_status status = AE_OK;781 u32 i;782 783 /* Handle special tables whose addresses are not in RSDT/XSDT */784 785 if (ACPI_COMPARE_NAMESEG(signature, ACPI_RSDP_NAME) ||786 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT) ||787 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT) ||788 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT) ||789 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {790 791find_next_instance:792 793 table_address = 0;794 795 /*796 * Get the appropriate address, either 32-bit or 64-bit. Be very797 * 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->Xdsdt804 && current_instance == 0) {805 table_address =806 (acpi_physical_address)gbl_fadt->807 Xdsdt;808 } else809 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->Xfacs822 && current_instance == 0) {823 table_address =824 (acpi_physical_address)gbl_fadt->825 Xfacs;826 } else827 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_CAST64912 (table_data));913 } else {914 table_address =915 (acpi_physical_address)(*ACPI_CAST32916 (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_NAMESEG935 (mapped_table->signature, signature)) {936 osl_unmap_table(mapped_table);937 mapped_table = NULL;938 continue;939 }940 941 /* Match table instance (for SSDT/UEFI tables) */942 943 if (current_instance != instance) {944 osl_unmap_table(mapped_table);945 mapped_table = NULL;946 current_instance++;947 continue;948 }949 950 break;951 }952 }953 954exit_find_table:955 956 if (!mapped_table) {957 return (AE_LIMIT);958 }959 960 if (table_length == 0) {961 status = AE_BAD_HEADER;962 goto exit;963 }964 965 /* Copy table to local buffer and return it */966 967 local_table = calloc(1, table_length);968 if (!local_table) {969 status = AE_NO_MEMORY;970 goto exit;971 }972 973 memcpy(local_table, mapped_table, table_length);974 *address = table_address;975 *table = local_table;976 977exit:978 osl_unmap_table(mapped_table);979 return (status);980}981 982/******************************************************************************983 *984 * FUNCTION: osl_list_customized_tables985 *986 * PARAMETERS: directory - Directory that contains the tables987 *988 * RETURN: Status; Table list is initialized if AE_OK.989 *990 * DESCRIPTION: Add ACPI tables to the table list from a directory.991 *992 *****************************************************************************/993 994static acpi_status osl_list_customized_tables(char *directory)995{996 void *table_dir;997 u32 instance;998 char temp_name[ACPI_NAMESEG_SIZE];999 char *filename;1000 acpi_status status = AE_OK;1001 1002 /* Open the requested directory */1003 1004 table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);1005 if (!table_dir) {1006 return (osl_get_last_status(AE_NOT_FOUND));1007 }1008 1009 /* Examine all entries in this directory */1010 1011 while ((filename = acpi_os_get_next_filename(table_dir))) {1012 1013 /* Extract table name and instance number */1014 1015 status =1016 osl_table_name_from_file(filename, temp_name, &instance);1017 1018 /* Ignore meaningless files */1019 1020 if (ACPI_FAILURE(status)) {1021 continue;1022 }1023 1024 /* Add new info node to global table list */1025 1026 status = osl_add_table_to_list(temp_name, instance);1027 if (ACPI_FAILURE(status)) {1028 break;1029 }1030 }1031 1032 acpi_os_close_directory(table_dir);1033 return (status);1034}1035 1036/******************************************************************************1037 *1038 * FUNCTION: osl_map_table1039 *1040 * PARAMETERS: address - Address of the table in memory1041 * signature - Optional ACPI Signature for desired table.1042 * Null terminated 4-character string.1043 * table - Where a pointer to the mapped table is1044 * returned1045 *1046 * RETURN: Status; Mapped table is returned if AE_OK.1047 * AE_NOT_FOUND: A valid table was not found at the address1048 *1049 * DESCRIPTION: Map entire ACPI table into caller's address space.1050 *1051 *****************************************************************************/1052 1053static acpi_status1054osl_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->Length1068 * 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(struct1085 acpi_table_header));1086 return (AE_BAD_SIGNATURE);1087 }1088 } else1089 if (!ACPI_COMPARE_NAMESEG1090 (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_table1122 *1123 * PARAMETERS: table - A pointer to the mapped table1124 *1125 * RETURN: None1126 *1127 * DESCRIPTION: Unmap entire ACPI table.1128 *1129 *****************************************************************************/1130 1131static void osl_unmap_table(struct acpi_table_header *table)1132{1133 if (table) {1134 acpi_os_unmap_memory(table, ap_get_table_length(table));1135 }1136}1137 1138/******************************************************************************1139 *1140 * FUNCTION: osl_table_name_from_file1141 *1142 * PARAMETERS: filename - File that contains the desired table1143 * signature - Pointer to 4-character buffer to store1144 * extracted table signature.1145 * instance - Pointer to integer to store extracted1146 * 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 file1151 * name.1152 *1153 *****************************************************************************/1154 1155static acpi_status1156osl_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_file1184 *1185 * PARAMETERS: filename - File that contains the desired table1186 * file_offset - Offset of the table in file1187 * table - Where a pointer to the table is returned1188 *1189 * RETURN: Status; Table buffer is returned if AE_OK.1190 *1191 * DESCRIPTION: Read a ACPI table from a file.1192 *1193 *****************************************************************************/1194 1195static acpi_status1196osl_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_FUNCTIONS1227 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#endif1248 1249 table_length = ap_get_table_length(&header);1250 if (table_length == 0) {1251 status = AE_BAD_HEADER;1252 goto exit;1253 }1254 1255 /* Read the entire table into a local buffer */1256 1257 local_table = calloc(1, table_length);1258 if (!local_table) {1259 fprintf(stderr,1260 "%4.4s: Could not allocate buffer for table of length %X\n",1261 header.signature, table_length);1262 status = AE_NO_MEMORY;1263 goto exit;1264 }1265 1266 fseek(table_file, file_offset, SEEK_SET);1267 1268 count = fread(local_table, 1, table_length, table_file);1269 if (count != table_length) {1270 fprintf(stderr, "%4.4s: Could not read table content\n",1271 header.signature);1272 status = AE_INVALID_TABLE_LENGTH;1273 goto exit;1274 }1275 1276 /* Validate checksum */1277 1278 (void)ap_is_valid_checksum(local_table);1279 1280exit:1281 fclose(table_file);1282 *table = local_table;1283 return (status);1284}1285 1286/******************************************************************************1287 *1288 * FUNCTION: osl_get_customized_table1289 *1290 * PARAMETERS: pathname - Directory to find Linux customized table1291 * signature - ACPI Signature for desired table. Must be1292 * 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 returned1296 * address - Where the table physical address is returned1297 *1298 * RETURN: Status; Table buffer is returned if AE_OK.1299 * AE_LIMIT: Instance is beyond valid limit1300 * AE_NOT_FOUND: A table with the signature was not found1301 *1302 * DESCRIPTION: Get an OS customized table.1303 *1304 *****************************************************************************/1305 1306static acpi_status1307osl_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