455 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: tbxfload - Table load/unload external interfaces5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#define EXPORT_ACPI_INTERFACES11 12#include <acpi/acpi.h>13#include "accommon.h"14#include "acnamesp.h"15#include "actables.h"16#include "acevents.h"17 18#define _COMPONENT ACPI_TABLES19ACPI_MODULE_NAME("tbxfload")20 21/*******************************************************************************22 *23 * FUNCTION: acpi_load_tables24 *25 * PARAMETERS: None26 *27 * RETURN: Status28 *29 * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT30 *31 ******************************************************************************/32acpi_status ACPI_INIT_FUNCTION acpi_load_tables(void)33{34 acpi_status status;35 36 ACPI_FUNCTION_TRACE(acpi_load_tables);37 38 /*39 * Install the default operation region handlers. These are the40 * handlers that are defined by the ACPI specification to be41 * "always accessible" -- namely, system_memory, system_IO, and42 * PCI_Config. This also means that no _REG methods need to be43 * run for these address spaces. We need to have these handlers44 * installed before any AML code can be executed, especially any45 * module-level code (11/2015).46 * Note that we allow OSPMs to install their own region handlers47 * between acpi_initialize_subsystem() and acpi_load_tables() to use48 * their customized default region handlers.49 */50 status = acpi_ev_install_region_handlers();51 if (ACPI_FAILURE(status)) {52 ACPI_EXCEPTION((AE_INFO, status,53 "During Region initialization"));54 return_ACPI_STATUS(status);55 }56 57 /* Load the namespace from the tables */58 59 status = acpi_tb_load_namespace();60 61 /* Don't let single failures abort the load */62 63 if (status == AE_CTRL_TERMINATE) {64 status = AE_OK;65 }66 67 if (ACPI_FAILURE(status)) {68 ACPI_EXCEPTION((AE_INFO, status,69 "While loading namespace from ACPI tables"));70 }71 72 /*73 * Initialize the objects in the namespace that remain uninitialized.74 * This runs the executable AML that may be part of the declaration of75 * these name objects:76 * operation_regions, buffer_fields, Buffers, and Packages.77 *78 */79 status = acpi_ns_initialize_objects();80 if (ACPI_SUCCESS(status)) {81 acpi_gbl_namespace_initialized = TRUE;82 }83 84 return_ACPI_STATUS(status);85}86 87ACPI_EXPORT_SYMBOL_INIT(acpi_load_tables)88 89/*******************************************************************************90 *91 * FUNCTION: acpi_tb_load_namespace92 *93 * PARAMETERS: None94 *95 * RETURN: Status96 *97 * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in98 * the RSDT/XSDT.99 *100 ******************************************************************************/101acpi_status acpi_tb_load_namespace(void)102{103 acpi_status status;104 u32 i;105 struct acpi_table_header *new_dsdt;106 struct acpi_table_desc *table;107 u32 tables_loaded = 0;108 u32 tables_failed = 0;109 110 ACPI_FUNCTION_TRACE(tb_load_namespace);111 112 (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);113 114 /*115 * Load the namespace. The DSDT is required, but any SSDT and116 * PSDT tables are optional. Verify the DSDT.117 */118 table = &acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index];119 120 if (!acpi_gbl_root_table_list.current_table_count ||121 !ACPI_COMPARE_NAMESEG(table->signature.ascii, ACPI_SIG_DSDT) ||122 ACPI_FAILURE(acpi_tb_validate_table(table))) {123 status = AE_NO_ACPI_TABLES;124 goto unlock_and_exit;125 }126 127 /*128 * Save the DSDT pointer for simple access. This is the mapped memory129 * address. We must take care here because the address of the .Tables130 * array can change dynamically as tables are loaded at run-time. Note:131 * .Pointer field is not validated until after call to acpi_tb_validate_table.132 */133 acpi_gbl_DSDT = table->pointer;134 135 /*136 * Optionally copy the entire DSDT to local memory (instead of simply137 * mapping it.) There are some BIOSs that corrupt or replace the original138 * DSDT, creating the need for this option. Default is FALSE, do not copy139 * the DSDT.140 */141 if (acpi_gbl_copy_dsdt_locally) {142 new_dsdt = acpi_tb_copy_dsdt(acpi_gbl_dsdt_index);143 if (new_dsdt) {144 acpi_gbl_DSDT = new_dsdt;145 }146 }147 148 /*149 * Save the original DSDT header for detection of table corruption150 * and/or replacement of the DSDT from outside the OS.151 */152 memcpy(&acpi_gbl_original_dsdt_header, acpi_gbl_DSDT,153 sizeof(struct acpi_table_header));154 155 /* Load and parse tables */156 157 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);158 status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node);159 (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);160 if (ACPI_FAILURE(status)) {161 ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed"));162 tables_failed++;163 } else {164 tables_loaded++;165 }166 167 /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */168 169 for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {170 table = &acpi_gbl_root_table_list.tables[i];171 172 if (!table->address ||173 (!ACPI_COMPARE_NAMESEG174 (table->signature.ascii, ACPI_SIG_SSDT)175 && !ACPI_COMPARE_NAMESEG(table->signature.ascii,176 ACPI_SIG_PSDT)177 && !ACPI_COMPARE_NAMESEG(table->signature.ascii,178 ACPI_SIG_OSDT))179 || ACPI_FAILURE(acpi_tb_validate_table(table))) {180 continue;181 }182 183 /* Ignore errors while loading tables, get as many as possible */184 185 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);186 status = acpi_ns_load_table(i, acpi_gbl_root_node);187 (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);188 if (ACPI_FAILURE(status)) {189 ACPI_EXCEPTION((AE_INFO, status,190 "(%4.4s:%8.8s) while loading table",191 table->signature.ascii,192 table->pointer->oem_table_id));193 194 tables_failed++;195 196 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,197 "Table [%4.4s:%8.8s] (id FF) - Table namespace load failed\n\n",198 table->signature.ascii,199 table->pointer->oem_table_id));200 } else {201 tables_loaded++;202 }203 }204 205 if (!tables_failed) {206 ACPI_INFO(("%u ACPI AML tables successfully acquired and loaded", tables_loaded));207 } else {208 ACPI_ERROR((AE_INFO,209 "%u table load failures, %u successful",210 tables_failed, tables_loaded));211 212 /* Indicate at least one failure */213 214 status = AE_CTRL_TERMINATE;215 }216 217#ifdef ACPI_APPLICATION218 ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\n"));219#endif220 221unlock_and_exit:222 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);223 return_ACPI_STATUS(status);224}225 226/*******************************************************************************227 *228 * FUNCTION: acpi_install_table229 *230 * PARAMETERS: table - Pointer to the ACPI table to be installed.231 *232 * RETURN: Status233 *234 * DESCRIPTION: Dynamically install an ACPI table.235 * Note: This function should only be invoked after236 * acpi_initialize_tables() and before acpi_load_tables().237 *238 ******************************************************************************/239 240acpi_status ACPI_INIT_FUNCTION241acpi_install_table(struct acpi_table_header *table)242{243 acpi_status status;244 u32 table_index;245 246 ACPI_FUNCTION_TRACE(acpi_install_table);247 248 status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),249 ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,250 table, FALSE, FALSE,251 &table_index);252 253 return_ACPI_STATUS(status);254}255 256ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)257 258/*******************************************************************************259 *260 * FUNCTION: acpi_install_physical_table261 *262 * PARAMETERS: address - Address of the ACPI table to be installed.263 *264 * RETURN: Status265 *266 * DESCRIPTION: Dynamically install an ACPI table.267 * Note: This function should only be invoked after268 * acpi_initialize_tables() and before acpi_load_tables().269 *270 ******************************************************************************/271acpi_status ACPI_INIT_FUNCTION272acpi_install_physical_table(acpi_physical_address address)273{274 acpi_status status;275 u32 table_index;276 277 ACPI_FUNCTION_TRACE(acpi_install_physical_table);278 279 status = acpi_tb_install_standard_table(address,280 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,281 NULL, FALSE, FALSE,282 &table_index);283 284 return_ACPI_STATUS(status);285}286 287ACPI_EXPORT_SYMBOL_INIT(acpi_install_physical_table)288 289/*******************************************************************************290 *291 * FUNCTION: acpi_load_table292 *293 * PARAMETERS: table - Pointer to a buffer containing the ACPI294 * table to be loaded.295 * table_idx - Pointer to a u32 for storing the table296 * index, might be NULL297 *298 * RETURN: Status299 *300 * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must301 * be a valid ACPI table with a valid ACPI table header.302 * Note1: Mainly intended to support hotplug addition of SSDTs.303 * Note2: Does not copy the incoming table. User is responsible304 * to ensure that the table is not deleted or unmapped.305 *306 ******************************************************************************/307acpi_status acpi_load_table(struct acpi_table_header *table, u32 *table_idx)308{309 acpi_status status;310 u32 table_index;311 312 ACPI_FUNCTION_TRACE(acpi_load_table);313 314 /* Parameter validation */315 316 if (!table) {317 return_ACPI_STATUS(AE_BAD_PARAMETER);318 }319 320 /* Install the table and load it into the namespace */321 322 ACPI_INFO(("Host-directed Dynamic ACPI Table Load:"));323 status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),324 ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,325 table, FALSE, &table_index);326 if (table_idx) {327 *table_idx = table_index;328 }329 330 if (ACPI_SUCCESS(status)) {331 332 /* Complete the initialization/resolution of new objects */333 334 acpi_ns_initialize_objects();335 }336 337 return_ACPI_STATUS(status);338}339 340ACPI_EXPORT_SYMBOL(acpi_load_table)341 342/*******************************************************************************343 *344 * FUNCTION: acpi_unload_parent_table345 *346 * PARAMETERS: object - Handle to any namespace object owned by347 * the table to be unloaded348 *349 * RETURN: Status350 *351 * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads352 * the table and deletes all namespace objects associated with353 * that table. Unloading of the DSDT is not allowed.354 * Note: Mainly intended to support hotplug removal of SSDTs.355 *356 ******************************************************************************/357acpi_status acpi_unload_parent_table(acpi_handle object)358{359 struct acpi_namespace_node *node =360 ACPI_CAST_PTR(struct acpi_namespace_node, object);361 acpi_status status = AE_NOT_EXIST;362 acpi_owner_id owner_id;363 u32 i;364 365 ACPI_FUNCTION_TRACE(acpi_unload_parent_table);366 367 /* Parameter validation */368 369 if (!object) {370 return_ACPI_STATUS(AE_BAD_PARAMETER);371 }372 373 /*374 * The node owner_id is currently the same as the parent table ID.375 * However, this could change in the future.376 */377 owner_id = node->owner_id;378 if (!owner_id) {379 380 /* owner_id==0 means DSDT is the owner. DSDT cannot be unloaded */381 382 return_ACPI_STATUS(AE_TYPE);383 }384 385 /* Must acquire the table lock during this operation */386 387 status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);388 if (ACPI_FAILURE(status)) {389 return_ACPI_STATUS(status);390 }391 392 /* Find the table in the global table list */393 394 for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {395 if (owner_id != acpi_gbl_root_table_list.tables[i].owner_id) {396 continue;397 }398 399 /*400 * Allow unload of SSDT and OEMx tables only. Do not allow unload401 * of the DSDT. No other types of tables should get here, since402 * only these types can contain AML and thus are the only types403 * that can create namespace objects.404 */405 if (ACPI_COMPARE_NAMESEG406 (acpi_gbl_root_table_list.tables[i].signature.ascii,407 ACPI_SIG_DSDT)) {408 status = AE_TYPE;409 break;410 }411 412 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);413 status = acpi_tb_unload_table(i);414 (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);415 break;416 }417 418 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);419 return_ACPI_STATUS(status);420}421 422ACPI_EXPORT_SYMBOL(acpi_unload_parent_table)423/*******************************************************************************424 *425 * FUNCTION: acpi_unload_table426 *427 * PARAMETERS: table_index - Index as returned by acpi_load_table428 *429 * RETURN: Status430 *431 * DESCRIPTION: Via the table_index representing an SSDT or OEMx table, unloads432 * the table and deletes all namespace objects associated with433 * that table. Unloading of the DSDT is not allowed.434 * Note: Mainly intended to support hotplug removal of SSDTs.435 *436 ******************************************************************************/437acpi_status acpi_unload_table(u32 table_index)438{439 acpi_status status;440 441 ACPI_FUNCTION_TRACE(acpi_unload_table);442 443 if (table_index == 1) {444 445 /* table_index==1 means DSDT is the owner. DSDT cannot be unloaded */446 447 return_ACPI_STATUS(AE_TYPE);448 }449 450 status = acpi_tb_unload_table(table_index);451 return_ACPI_STATUS(status);452}453 454ACPI_EXPORT_SYMBOL(acpi_unload_table)455