brintos

brintos / linux-shallow public Read only

0
0
Text · 9.2 KiB · 0dc003c Raw
305 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: tbinstal - ACPI table installation and removal5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "actables.h"13 14#define _COMPONENT          ACPI_TABLES15ACPI_MODULE_NAME("tbinstal")16 17/*******************************************************************************18 *19 * FUNCTION:    acpi_tb_install_table_with_override20 *21 * PARAMETERS:  new_table_desc          - New table descriptor to install22 *              override                - Whether override should be performed23 *              table_index             - Where the table index is returned24 *25 * RETURN:      None26 *27 * DESCRIPTION: Install an ACPI table into the global data structure. The28 *              table override mechanism is called to allow the host29 *              OS to replace any table before it is installed in the root30 *              table array.31 *32 ******************************************************************************/33void34acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc,35				    u8 override, u32 *table_index)36{37	u32 i;38	acpi_status status;39 40	status = acpi_tb_get_next_table_descriptor(&i, NULL);41	if (ACPI_FAILURE(status)) {42		return;43	}44 45	/*46	 * ACPI Table Override:47	 *48	 * Before we install the table, let the host OS override it with a new49	 * one if desired. Any table within the RSDT/XSDT can be replaced,50	 * including the DSDT which is pointed to by the FADT.51	 */52	if (override) {53		acpi_tb_override_table(new_table_desc);54	}55 56	acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.tables[i],57				      new_table_desc->address,58				      new_table_desc->flags,59				      new_table_desc->pointer);60 61	acpi_tb_print_table_header(new_table_desc->address,62				   new_table_desc->pointer);63 64	/* This synchronizes acpi_gbl_dsdt_index */65 66	*table_index = i;67 68	/* Set the global integer width (based upon revision of the DSDT) */69 70	if (i == acpi_gbl_dsdt_index) {71		acpi_ut_set_integer_width(new_table_desc->pointer->revision);72	}73}74 75/*******************************************************************************76 *77 * FUNCTION:    acpi_tb_install_standard_table78 *79 * PARAMETERS:  address             - Address of the table (might be a virtual80 *                                    address depending on the table_flags)81 *              flags               - Flags for the table82 *              table               - Pointer to the table (required for virtual83 *                                    origins, optional for physical)84 *              reload              - Whether reload should be performed85 *              override            - Whether override should be performed86 *              table_index         - Where the table index is returned87 *88 * RETURN:      Status89 *90 * DESCRIPTION: This function is called to verify and install an ACPI table.91 *              When this function is called by "Load" or "LoadTable" opcodes,92 *              or by acpi_load_table() API, the "Reload" parameter is set.93 *              After successfully returning from this function, table is94 *              "INSTALLED" but not "VALIDATED".95 *96 ******************************************************************************/97 98acpi_status99acpi_tb_install_standard_table(acpi_physical_address address,100			       u8 flags,101			       struct acpi_table_header *table,102			       u8 reload, u8 override, u32 *table_index)103{104	u32 i;105	acpi_status status = AE_OK;106	struct acpi_table_desc new_table_desc;107 108	ACPI_FUNCTION_TRACE(tb_install_standard_table);109 110	/* Acquire a temporary table descriptor for validation */111 112	status =113	    acpi_tb_acquire_temp_table(&new_table_desc, address, flags, table);114	if (ACPI_FAILURE(status)) {115		ACPI_ERROR((AE_INFO,116			    "Could not acquire table length at %8.8X%8.8X",117			    ACPI_FORMAT_UINT64(address)));118		return_ACPI_STATUS(status);119	}120 121	/*122	 * Optionally do not load any SSDTs from the RSDT/XSDT. This can123	 * be useful for debugging ACPI problems on some machines.124	 */125	if (!reload &&126	    acpi_gbl_disable_ssdt_table_install &&127	    ACPI_COMPARE_NAMESEG(&new_table_desc.signature, ACPI_SIG_SSDT)) {128		ACPI_INFO(("Ignoring installation of %4.4s at %8.8X%8.8X",129			   new_table_desc.signature.ascii,130			   ACPI_FORMAT_UINT64(address)));131		goto release_and_exit;132	}133 134	/* Acquire the table lock */135 136	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);137 138	/* Validate and verify a table before installation */139 140	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i);141	if (ACPI_FAILURE(status)) {142		if (status == AE_CTRL_TERMINATE) {143			/*144			 * Table was unloaded, allow it to be reloaded.145			 * As we are going to return AE_OK to the caller, we should146			 * take the responsibility of freeing the input descriptor.147			 * Refill the input descriptor to ensure148			 * acpi_tb_install_table_with_override() can be called again to149			 * indicate the re-installation.150			 */151			acpi_tb_uninstall_table(&new_table_desc);152			(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);153			*table_index = i;154			return_ACPI_STATUS(AE_OK);155		}156		goto unlock_and_exit;157	}158 159	/* Add the table to the global root table list */160 161	acpi_tb_install_table_with_override(&new_table_desc, override,162					    table_index);163 164	/* Invoke table handler */165 166	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);167	acpi_tb_notify_table(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer);168	(void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);169 170unlock_and_exit:171 172	/* Release the table lock */173 174	(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);175 176release_and_exit:177 178	/* Release the temporary table descriptor */179 180	acpi_tb_release_temp_table(&new_table_desc);181	return_ACPI_STATUS(status);182}183 184/*******************************************************************************185 *186 * FUNCTION:    acpi_tb_override_table187 *188 * PARAMETERS:  old_table_desc      - Validated table descriptor to be189 *                                    overridden190 *191 * RETURN:      None192 *193 * DESCRIPTION: Attempt table override by calling the OSL override functions.194 *              Note: If the table is overridden, then the entire new table195 *              is acquired and returned by this function.196 *              Before/after invocation, the table descriptor is in a state197 *              that is "VALIDATED".198 *199 ******************************************************************************/200 201void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)202{203	acpi_status status;204	struct acpi_table_desc new_table_desc;205	struct acpi_table_header *table;206	acpi_physical_address address;207	u32 length;208	ACPI_ERROR_ONLY(char *override_type);209 210	/* (1) Attempt logical override (returns a logical address) */211 212	status = acpi_os_table_override(old_table_desc->pointer, &table);213	if (ACPI_SUCCESS(status) && table) {214		acpi_tb_acquire_temp_table(&new_table_desc,215					   ACPI_PTR_TO_PHYSADDR(table),216					   ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,217					   table);218		ACPI_ERROR_ONLY(override_type = "Logical");219		goto finish_override;220	}221 222	/* (2) Attempt physical override (returns a physical address) */223 224	status = acpi_os_physical_table_override(old_table_desc->pointer,225						 &address, &length);226	if (ACPI_SUCCESS(status) && address && length) {227		acpi_tb_acquire_temp_table(&new_table_desc, address,228					   ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,229					   NULL);230		ACPI_ERROR_ONLY(override_type = "Physical");231		goto finish_override;232	}233 234	return;			/* There was no override */235 236finish_override:237 238	/*239	 * Validate and verify a table before overriding, no nested table240	 * duplication check as it's too complicated and unnecessary.241	 */242	status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL);243	if (ACPI_FAILURE(status)) {244		return;245	}246 247	ACPI_INFO(("%4.4s 0x%8.8X%8.8X"248		   " %s table override, new table: 0x%8.8X%8.8X",249		   old_table_desc->signature.ascii,250		   ACPI_FORMAT_UINT64(old_table_desc->address),251		   override_type, ACPI_FORMAT_UINT64(new_table_desc.address)));252 253	/* We can now uninstall the original table */254 255	acpi_tb_uninstall_table(old_table_desc);256 257	/*258	 * Replace the original table descriptor and keep its state as259	 * "VALIDATED".260	 */261	acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address,262				      new_table_desc.flags,263				      new_table_desc.pointer);264	acpi_tb_validate_temp_table(old_table_desc);265 266	/* Release the temporary table descriptor */267 268	acpi_tb_release_temp_table(&new_table_desc);269}270 271/*******************************************************************************272 *273 * FUNCTION:    acpi_tb_uninstall_table274 *275 * PARAMETERS:  table_desc          - Table descriptor276 *277 * RETURN:      None278 *279 * DESCRIPTION: Delete one internal ACPI table280 *281 ******************************************************************************/282 283void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc)284{285 286	ACPI_FUNCTION_TRACE(tb_uninstall_table);287 288	/* Table must be installed */289 290	if (!table_desc->address) {291		return_VOID;292	}293 294	acpi_tb_invalidate_table(table_desc);295 296	if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==297	    ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) {298		ACPI_FREE(table_desc->pointer);299		table_desc->pointer = NULL;300	}301 302	table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);303	return_VOID;304}305