1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: tbxfload - Table load/unload external interfaces |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #define EXPORT_ACPI_INTERFACES |
11 | |
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_TABLES |
19 | ACPI_MODULE_NAME("tbxfload" ) |
20 | |
21 | /******************************************************************************* |
22 | * |
23 | * FUNCTION: acpi_load_tables |
24 | * |
25 | * PARAMETERS: None |
26 | * |
27 | * RETURN: Status |
28 | * |
29 | * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT |
30 | * |
31 | ******************************************************************************/ |
32 | acpi_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 the |
40 | * handlers that are defined by the ACPI specification to be |
41 | * "always accessible" -- namely, system_memory, system_IO, and |
42 | * PCI_Config. This also means that no _REG methods need to be |
43 | * run for these address spaces. We need to have these handlers |
44 | * installed before any AML code can be executed, especially any |
45 | * module-level code (11/2015). |
46 | * Note that we allow OSPMs to install their own region handlers |
47 | * between acpi_initialize_subsystem() and acpi_load_tables() to use |
48 | * 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 of |
75 | * 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 | |
87 | ACPI_EXPORT_SYMBOL_INIT(acpi_load_tables) |
88 | |
89 | /******************************************************************************* |
90 | * |
91 | * FUNCTION: acpi_tb_load_namespace |
92 | * |
93 | * PARAMETERS: None |
94 | * |
95 | * RETURN: Status |
96 | * |
97 | * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in |
98 | * the RSDT/XSDT. |
99 | * |
100 | ******************************************************************************/ |
101 | acpi_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 and |
116 | * 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 memory |
129 | * address. We must take care here because the address of the .Tables |
130 | * 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 simply |
137 | * mapping it.) There are some BIOSs that corrupt or replace the original |
138 | * DSDT, creating the need for this option. Default is FALSE, do not copy |
139 | * the DSDT. |
140 | */ |
141 | if (acpi_gbl_copy_dsdt_locally) { |
142 | new_dsdt = acpi_tb_copy_dsdt(table_index: 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 corruption |
150 | * 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(table_index: acpi_gbl_dsdt_index, node: 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_NAMESEG |
174 | (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(table_index: i, node: 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_APPLICATION |
218 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "\n" )); |
219 | #endif |
220 | |
221 | unlock_and_exit: |
222 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
223 | return_ACPI_STATUS(status); |
224 | } |
225 | |
226 | /******************************************************************************* |
227 | * |
228 | * FUNCTION: acpi_install_table |
229 | * |
230 | * PARAMETERS: table - Pointer to the ACPI table to be installed. |
231 | * |
232 | * RETURN: Status |
233 | * |
234 | * DESCRIPTION: Dynamically install an ACPI table. |
235 | * Note: This function should only be invoked after |
236 | * acpi_initialize_tables() and before acpi_load_tables(). |
237 | * |
238 | ******************************************************************************/ |
239 | |
240 | acpi_status ACPI_INIT_FUNCTION |
241 | acpi_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: &table_index); |
252 | |
253 | return_ACPI_STATUS(status); |
254 | } |
255 | |
256 | ACPI_EXPORT_SYMBOL_INIT(acpi_install_table) |
257 | |
258 | /******************************************************************************* |
259 | * |
260 | * FUNCTION: acpi_install_physical_table |
261 | * |
262 | * PARAMETERS: address - Address of the ACPI table to be installed. |
263 | * |
264 | * RETURN: Status |
265 | * |
266 | * DESCRIPTION: Dynamically install an ACPI table. |
267 | * Note: This function should only be invoked after |
268 | * acpi_initialize_tables() and before acpi_load_tables(). |
269 | * |
270 | ******************************************************************************/ |
271 | acpi_status ACPI_INIT_FUNCTION |
272 | acpi_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: &table_index); |
283 | |
284 | return_ACPI_STATUS(status); |
285 | } |
286 | |
287 | ACPI_EXPORT_SYMBOL_INIT(acpi_install_physical_table) |
288 | |
289 | /******************************************************************************* |
290 | * |
291 | * FUNCTION: acpi_load_table |
292 | * |
293 | * PARAMETERS: table - Pointer to a buffer containing the ACPI |
294 | * table to be loaded. |
295 | * table_idx - Pointer to a u32 for storing the table |
296 | * index, might be NULL |
297 | * |
298 | * RETURN: Status |
299 | * |
300 | * DESCRIPTION: Dynamically load an ACPI table from the caller's buffer. Must |
301 | * 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 responsible |
304 | * to ensure that the table is not deleted or unmapped. |
305 | * |
306 | ******************************************************************************/ |
307 | acpi_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: &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 | |
340 | ACPI_EXPORT_SYMBOL(acpi_load_table) |
341 | |
342 | /******************************************************************************* |
343 | * |
344 | * FUNCTION: acpi_unload_parent_table |
345 | * |
346 | * PARAMETERS: object - Handle to any namespace object owned by |
347 | * the table to be unloaded |
348 | * |
349 | * RETURN: Status |
350 | * |
351 | * DESCRIPTION: Via any namespace object within an SSDT or OEMx table, unloads |
352 | * the table and deletes all namespace objects associated with |
353 | * that table. Unloading of the DSDT is not allowed. |
354 | * Note: Mainly intended to support hotplug removal of SSDTs. |
355 | * |
356 | ******************************************************************************/ |
357 | acpi_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 unload |
401 | * of the DSDT. No other types of tables should get here, since |
402 | * only these types can contain AML and thus are the only types |
403 | * that can create namespace objects. |
404 | */ |
405 | if (ACPI_COMPARE_NAMESEG |
406 | (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(table_index: 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 | |
422 | ACPI_EXPORT_SYMBOL(acpi_unload_parent_table) |
423 | /******************************************************************************* |
424 | * |
425 | * FUNCTION: acpi_unload_table |
426 | * |
427 | * PARAMETERS: table_index - Index as returned by acpi_load_table |
428 | * |
429 | * RETURN: Status |
430 | * |
431 | * DESCRIPTION: Via the table_index representing an SSDT or OEMx table, unloads |
432 | * the table and deletes all namespace objects associated with |
433 | * that table. Unloading of the DSDT is not allowed. |
434 | * Note: Mainly intended to support hotplug removal of SSDTs. |
435 | * |
436 | ******************************************************************************/ |
437 | acpi_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 | |
454 | ACPI_EXPORT_SYMBOL(acpi_unload_table) |
455 | |