1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: tbinstal - ACPI table installation and removal
5 *
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_TABLES
15ACPI_MODULE_NAME("tbinstal")
16
17/*******************************************************************************
18 *
19 * FUNCTION:    acpi_tb_install_table_with_override
20 *
21 * PARAMETERS:  new_table_desc          - New table descriptor to install
22 *              override                - Whether override should be performed
23 *              table_index             - Where the table index is returned
24 *
25 * RETURN:      None
26 *
27 * DESCRIPTION: Install an ACPI table into the global data structure. The
28 *              table override mechanism is called to allow the host
29 *              OS to replace any table before it is installed in the root
30 *              table array.
31 *
32 ******************************************************************************/
33void
34acpi_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 new
49	 * 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_table
78 *
79 * PARAMETERS:  address             - Address of the table (might be a virtual
80 *                                    address depending on the table_flags)
81 *              flags               - Flags for the table
82 *              table               - Pointer to the table (required for virtual
83 *                                    origins, optional for physical)
84 *              reload              - Whether reload should be performed
85 *              override            - Whether override should be performed
86 *              table_index         - Where the table index is returned
87 *
88 * RETURN:      Status
89 *
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 is
94 *              "INSTALLED" but not "VALIDATED".
95 *
96 ******************************************************************************/
97
98acpi_status
99acpi_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 can
123	 * 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 should
146			 * take the responsibility of freeing the input descriptor.
147			 * Refill the input descriptor to ensure
148			 * acpi_tb_install_table_with_override() can be called again to
149			 * 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_table
187 *
188 * PARAMETERS:  old_table_desc      - Validated table descriptor to be
189 *                                    overridden
190 *
191 * RETURN:      None
192 *
193 * DESCRIPTION: Attempt table override by calling the OSL override functions.
194 *              Note: If the table is overridden, then the entire new table
195 *              is acquired and returned by this function.
196 *              Before/after invocation, the table descriptor is in a state
197 *              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 table
240	 * 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 as
259	 * "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_table
274 *
275 * PARAMETERS:  table_desc          - Table descriptor
276 *
277 * RETURN:      None
278 *
279 * DESCRIPTION: Delete one internal ACPI table
280 *
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