brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · 0f2a734 Raw
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