162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 262306a36Sopenharmony_ci/****************************************************************************** 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Module Name: tbinstal - ACPI table installation and removal 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci *****************************************************************************/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <acpi/acpi.h> 1162306a36Sopenharmony_ci#include "accommon.h" 1262306a36Sopenharmony_ci#include "actables.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define _COMPONENT ACPI_TABLES 1562306a36Sopenharmony_ciACPI_MODULE_NAME("tbinstal") 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/******************************************************************************* 1862306a36Sopenharmony_ci * 1962306a36Sopenharmony_ci * FUNCTION: acpi_tb_install_table_with_override 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * PARAMETERS: new_table_desc - New table descriptor to install 2262306a36Sopenharmony_ci * override - Whether override should be performed 2362306a36Sopenharmony_ci * table_index - Where the table index is returned 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * RETURN: None 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * DESCRIPTION: Install an ACPI table into the global data structure. The 2862306a36Sopenharmony_ci * table override mechanism is called to allow the host 2962306a36Sopenharmony_ci * OS to replace any table before it is installed in the root 3062306a36Sopenharmony_ci * table array. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci ******************************************************************************/ 3362306a36Sopenharmony_civoid 3462306a36Sopenharmony_ciacpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, 3562306a36Sopenharmony_ci u8 override, u32 *table_index) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci u32 i; 3862306a36Sopenharmony_ci acpi_status status; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci status = acpi_tb_get_next_table_descriptor(&i, NULL); 4162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* 4662306a36Sopenharmony_ci * ACPI Table Override: 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Before we install the table, let the host OS override it with a new 4962306a36Sopenharmony_ci * one if desired. Any table within the RSDT/XSDT can be replaced, 5062306a36Sopenharmony_ci * including the DSDT which is pointed to by the FADT. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci if (override) { 5362306a36Sopenharmony_ci acpi_tb_override_table(new_table_desc); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.tables[i], 5762306a36Sopenharmony_ci new_table_desc->address, 5862306a36Sopenharmony_ci new_table_desc->flags, 5962306a36Sopenharmony_ci new_table_desc->pointer); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci acpi_tb_print_table_header(new_table_desc->address, 6262306a36Sopenharmony_ci new_table_desc->pointer); 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci /* This synchronizes acpi_gbl_dsdt_index */ 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci *table_index = i; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* Set the global integer width (based upon revision of the DSDT) */ 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (i == acpi_gbl_dsdt_index) { 7162306a36Sopenharmony_ci acpi_ut_set_integer_width(new_table_desc->pointer->revision); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/******************************************************************************* 7662306a36Sopenharmony_ci * 7762306a36Sopenharmony_ci * FUNCTION: acpi_tb_install_standard_table 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * PARAMETERS: address - Address of the table (might be a virtual 8062306a36Sopenharmony_ci * address depending on the table_flags) 8162306a36Sopenharmony_ci * flags - Flags for the table 8262306a36Sopenharmony_ci * table - Pointer to the table (required for virtual 8362306a36Sopenharmony_ci * origins, optional for physical) 8462306a36Sopenharmony_ci * reload - Whether reload should be performed 8562306a36Sopenharmony_ci * override - Whether override should be performed 8662306a36Sopenharmony_ci * table_index - Where the table index is returned 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * RETURN: Status 8962306a36Sopenharmony_ci * 9062306a36Sopenharmony_ci * DESCRIPTION: This function is called to verify and install an ACPI table. 9162306a36Sopenharmony_ci * When this function is called by "Load" or "LoadTable" opcodes, 9262306a36Sopenharmony_ci * or by acpi_load_table() API, the "Reload" parameter is set. 9362306a36Sopenharmony_ci * After successfully returning from this function, table is 9462306a36Sopenharmony_ci * "INSTALLED" but not "VALIDATED". 9562306a36Sopenharmony_ci * 9662306a36Sopenharmony_ci ******************************************************************************/ 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ciacpi_status 9962306a36Sopenharmony_ciacpi_tb_install_standard_table(acpi_physical_address address, 10062306a36Sopenharmony_ci u8 flags, 10162306a36Sopenharmony_ci struct acpi_table_header *table, 10262306a36Sopenharmony_ci u8 reload, u8 override, u32 *table_index) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci u32 i; 10562306a36Sopenharmony_ci acpi_status status = AE_OK; 10662306a36Sopenharmony_ci struct acpi_table_desc new_table_desc; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_install_standard_table); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* Acquire a temporary table descriptor for validation */ 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci status = 11362306a36Sopenharmony_ci acpi_tb_acquire_temp_table(&new_table_desc, address, flags, table); 11462306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 11562306a36Sopenharmony_ci ACPI_ERROR((AE_INFO, 11662306a36Sopenharmony_ci "Could not acquire table length at %8.8X%8.8X", 11762306a36Sopenharmony_ci ACPI_FORMAT_UINT64(address))); 11862306a36Sopenharmony_ci return_ACPI_STATUS(status); 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci /* 12262306a36Sopenharmony_ci * Optionally do not load any SSDTs from the RSDT/XSDT. This can 12362306a36Sopenharmony_ci * be useful for debugging ACPI problems on some machines. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_ci if (!reload && 12662306a36Sopenharmony_ci acpi_gbl_disable_ssdt_table_install && 12762306a36Sopenharmony_ci ACPI_COMPARE_NAMESEG(&new_table_desc.signature, ACPI_SIG_SSDT)) { 12862306a36Sopenharmony_ci ACPI_INFO(("Ignoring installation of %4.4s at %8.8X%8.8X", 12962306a36Sopenharmony_ci new_table_desc.signature.ascii, 13062306a36Sopenharmony_ci ACPI_FORMAT_UINT64(address))); 13162306a36Sopenharmony_ci goto release_and_exit; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* Acquire the table lock */ 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci /* Validate and verify a table before installation */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci status = acpi_tb_verify_temp_table(&new_table_desc, NULL, &i); 14162306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 14262306a36Sopenharmony_ci if (status == AE_CTRL_TERMINATE) { 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * Table was unloaded, allow it to be reloaded. 14562306a36Sopenharmony_ci * As we are going to return AE_OK to the caller, we should 14662306a36Sopenharmony_ci * take the responsibility of freeing the input descriptor. 14762306a36Sopenharmony_ci * Refill the input descriptor to ensure 14862306a36Sopenharmony_ci * acpi_tb_install_table_with_override() can be called again to 14962306a36Sopenharmony_ci * indicate the re-installation. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci acpi_tb_uninstall_table(&new_table_desc); 15262306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 15362306a36Sopenharmony_ci *table_index = i; 15462306a36Sopenharmony_ci return_ACPI_STATUS(AE_OK); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci goto unlock_and_exit; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Add the table to the global root table list */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci acpi_tb_install_table_with_override(&new_table_desc, override, 16262306a36Sopenharmony_ci table_index); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Invoke table handler */ 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 16762306a36Sopenharmony_ci acpi_tb_notify_table(ACPI_TABLE_EVENT_INSTALL, new_table_desc.pointer); 16862306a36Sopenharmony_ci (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ciunlock_and_exit: 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Release the table lock */ 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cirelease_and_exit: 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Release the temporary table descriptor */ 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci acpi_tb_release_temp_table(&new_table_desc); 18162306a36Sopenharmony_ci return_ACPI_STATUS(status); 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/******************************************************************************* 18562306a36Sopenharmony_ci * 18662306a36Sopenharmony_ci * FUNCTION: acpi_tb_override_table 18762306a36Sopenharmony_ci * 18862306a36Sopenharmony_ci * PARAMETERS: old_table_desc - Validated table descriptor to be 18962306a36Sopenharmony_ci * overridden 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * RETURN: None 19262306a36Sopenharmony_ci * 19362306a36Sopenharmony_ci * DESCRIPTION: Attempt table override by calling the OSL override functions. 19462306a36Sopenharmony_ci * Note: If the table is overridden, then the entire new table 19562306a36Sopenharmony_ci * is acquired and returned by this function. 19662306a36Sopenharmony_ci * Before/after invocation, the table descriptor is in a state 19762306a36Sopenharmony_ci * that is "VALIDATED". 19862306a36Sopenharmony_ci * 19962306a36Sopenharmony_ci ******************************************************************************/ 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_civoid acpi_tb_override_table(struct acpi_table_desc *old_table_desc) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci acpi_status status; 20462306a36Sopenharmony_ci struct acpi_table_desc new_table_desc; 20562306a36Sopenharmony_ci struct acpi_table_header *table; 20662306a36Sopenharmony_ci acpi_physical_address address; 20762306a36Sopenharmony_ci u32 length; 20862306a36Sopenharmony_ci ACPI_ERROR_ONLY(char *override_type); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* (1) Attempt logical override (returns a logical address) */ 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci status = acpi_os_table_override(old_table_desc->pointer, &table); 21362306a36Sopenharmony_ci if (ACPI_SUCCESS(status) && table) { 21462306a36Sopenharmony_ci acpi_tb_acquire_temp_table(&new_table_desc, 21562306a36Sopenharmony_ci ACPI_PTR_TO_PHYSADDR(table), 21662306a36Sopenharmony_ci ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL, 21762306a36Sopenharmony_ci table); 21862306a36Sopenharmony_ci ACPI_ERROR_ONLY(override_type = "Logical"); 21962306a36Sopenharmony_ci goto finish_override; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* (2) Attempt physical override (returns a physical address) */ 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci status = acpi_os_physical_table_override(old_table_desc->pointer, 22562306a36Sopenharmony_ci &address, &length); 22662306a36Sopenharmony_ci if (ACPI_SUCCESS(status) && address && length) { 22762306a36Sopenharmony_ci acpi_tb_acquire_temp_table(&new_table_desc, address, 22862306a36Sopenharmony_ci ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, 22962306a36Sopenharmony_ci NULL); 23062306a36Sopenharmony_ci ACPI_ERROR_ONLY(override_type = "Physical"); 23162306a36Sopenharmony_ci goto finish_override; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return; /* There was no override */ 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cifinish_override: 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* 23962306a36Sopenharmony_ci * Validate and verify a table before overriding, no nested table 24062306a36Sopenharmony_ci * duplication check as it's too complicated and unnecessary. 24162306a36Sopenharmony_ci */ 24262306a36Sopenharmony_ci status = acpi_tb_verify_temp_table(&new_table_desc, NULL, NULL); 24362306a36Sopenharmony_ci if (ACPI_FAILURE(status)) { 24462306a36Sopenharmony_ci return; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ACPI_INFO(("%4.4s 0x%8.8X%8.8X" 24862306a36Sopenharmony_ci " %s table override, new table: 0x%8.8X%8.8X", 24962306a36Sopenharmony_ci old_table_desc->signature.ascii, 25062306a36Sopenharmony_ci ACPI_FORMAT_UINT64(old_table_desc->address), 25162306a36Sopenharmony_ci override_type, ACPI_FORMAT_UINT64(new_table_desc.address))); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* We can now uninstall the original table */ 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci acpi_tb_uninstall_table(old_table_desc); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* 25862306a36Sopenharmony_ci * Replace the original table descriptor and keep its state as 25962306a36Sopenharmony_ci * "VALIDATED". 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address, 26262306a36Sopenharmony_ci new_table_desc.flags, 26362306a36Sopenharmony_ci new_table_desc.pointer); 26462306a36Sopenharmony_ci acpi_tb_validate_temp_table(old_table_desc); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci /* Release the temporary table descriptor */ 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci acpi_tb_release_temp_table(&new_table_desc); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/******************************************************************************* 27262306a36Sopenharmony_ci * 27362306a36Sopenharmony_ci * FUNCTION: acpi_tb_uninstall_table 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * PARAMETERS: table_desc - Table descriptor 27662306a36Sopenharmony_ci * 27762306a36Sopenharmony_ci * RETURN: None 27862306a36Sopenharmony_ci * 27962306a36Sopenharmony_ci * DESCRIPTION: Delete one internal ACPI table 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci ******************************************************************************/ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_civoid acpi_tb_uninstall_table(struct acpi_table_desc *table_desc) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci ACPI_FUNCTION_TRACE(tb_uninstall_table); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* Table must be installed */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (!table_desc->address) { 29162306a36Sopenharmony_ci return_VOID; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci acpi_tb_invalidate_table(table_desc); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) == 29762306a36Sopenharmony_ci ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) { 29862306a36Sopenharmony_ci ACPI_FREE(table_desc->pointer); 29962306a36Sopenharmony_ci table_desc->pointer = NULL; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL); 30362306a36Sopenharmony_ci return_VOID; 30462306a36Sopenharmony_ci} 305