1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: tbxface - ACPI table-oriented 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 "actables.h" |
15 | |
16 | #define _COMPONENT ACPI_TABLES |
17 | ACPI_MODULE_NAME("tbxface" ) |
18 | |
19 | /******************************************************************************* |
20 | * |
21 | * FUNCTION: acpi_allocate_root_table |
22 | * |
23 | * PARAMETERS: initial_table_count - Size of initial_table_array, in number of |
24 | * struct acpi_table_desc structures |
25 | * |
26 | * RETURN: Status |
27 | * |
28 | * DESCRIPTION: Allocate a root table array. Used by iASL compiler and |
29 | * acpi_initialize_tables. |
30 | * |
31 | ******************************************************************************/ |
32 | acpi_status acpi_allocate_root_table(u32 initial_table_count) |
33 | { |
34 | |
35 | acpi_gbl_root_table_list.max_table_count = initial_table_count; |
36 | acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE; |
37 | |
38 | return (acpi_tb_resize_root_table_list()); |
39 | } |
40 | |
41 | /******************************************************************************* |
42 | * |
43 | * FUNCTION: acpi_initialize_tables |
44 | * |
45 | * PARAMETERS: initial_table_array - Pointer to an array of pre-allocated |
46 | * struct acpi_table_desc structures. If NULL, the |
47 | * array is dynamically allocated. |
48 | * initial_table_count - Size of initial_table_array, in number of |
49 | * struct acpi_table_desc structures |
50 | * allow_resize - Flag to tell Table Manager if resize of |
51 | * pre-allocated array is allowed. Ignored |
52 | * if initial_table_array is NULL. |
53 | * |
54 | * RETURN: Status |
55 | * |
56 | * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT. |
57 | * |
58 | * NOTE: Allows static allocation of the initial table array in order |
59 | * to avoid the use of dynamic memory in confined environments |
60 | * such as the kernel boot sequence where it may not be available. |
61 | * |
62 | * If the host OS memory managers are initialized, use NULL for |
63 | * initial_table_array, and the table will be dynamically allocated. |
64 | * |
65 | ******************************************************************************/ |
66 | |
67 | acpi_status ACPI_INIT_FUNCTION |
68 | acpi_initialize_tables(struct acpi_table_desc *initial_table_array, |
69 | u32 initial_table_count, u8 allow_resize) |
70 | { |
71 | acpi_physical_address rsdp_address; |
72 | acpi_status status; |
73 | |
74 | ACPI_FUNCTION_TRACE(acpi_initialize_tables); |
75 | |
76 | /* |
77 | * Setup the Root Table Array and allocate the table array |
78 | * if requested |
79 | */ |
80 | if (!initial_table_array) { |
81 | status = acpi_allocate_root_table(initial_table_count); |
82 | if (ACPI_FAILURE(status)) { |
83 | return_ACPI_STATUS(status); |
84 | } |
85 | } else { |
86 | /* Root Table Array has been statically allocated by the host */ |
87 | |
88 | memset(initial_table_array, 0, |
89 | (acpi_size)initial_table_count * |
90 | sizeof(struct acpi_table_desc)); |
91 | |
92 | acpi_gbl_root_table_list.tables = initial_table_array; |
93 | acpi_gbl_root_table_list.max_table_count = initial_table_count; |
94 | acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN; |
95 | if (allow_resize) { |
96 | acpi_gbl_root_table_list.flags |= |
97 | ACPI_ROOT_ALLOW_RESIZE; |
98 | } |
99 | } |
100 | |
101 | /* Get the address of the RSDP */ |
102 | |
103 | rsdp_address = acpi_os_get_root_pointer(); |
104 | if (!rsdp_address) { |
105 | return_ACPI_STATUS(AE_NOT_FOUND); |
106 | } |
107 | |
108 | /* |
109 | * Get the root table (RSDT or XSDT) and extract all entries to the local |
110 | * Root Table Array. This array contains the information of the RSDT/XSDT |
111 | * in a common, more usable format. |
112 | */ |
113 | status = acpi_tb_parse_root_table(rsdp_address); |
114 | return_ACPI_STATUS(status); |
115 | } |
116 | |
117 | ACPI_EXPORT_SYMBOL_INIT(acpi_initialize_tables) |
118 | |
119 | /******************************************************************************* |
120 | * |
121 | * FUNCTION: acpi_reallocate_root_table |
122 | * |
123 | * PARAMETERS: None |
124 | * |
125 | * RETURN: Status |
126 | * |
127 | * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the |
128 | * root list from the previously provided scratch area. Should |
129 | * be called once dynamic memory allocation is available in the |
130 | * kernel. |
131 | * |
132 | ******************************************************************************/ |
133 | acpi_status ACPI_INIT_FUNCTION acpi_reallocate_root_table(void) |
134 | { |
135 | acpi_status status; |
136 | struct acpi_table_desc *table_desc; |
137 | u32 i, j; |
138 | |
139 | ACPI_FUNCTION_TRACE(acpi_reallocate_root_table); |
140 | |
141 | /* |
142 | * If there are tables unverified, it is required to reallocate the |
143 | * root table list to clean up invalid table entries. Otherwise only |
144 | * reallocate the root table list if the host provided a static buffer |
145 | * for the table array in the call to acpi_initialize_tables(). |
146 | */ |
147 | if ((acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) && |
148 | acpi_gbl_enable_table_validation) { |
149 | return_ACPI_STATUS(AE_SUPPORT); |
150 | } |
151 | |
152 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
153 | |
154 | /* |
155 | * Ensure OS early boot logic, which is required by some hosts. If the |
156 | * table state is reported to be wrong, developers should fix the |
157 | * issue by invoking acpi_put_table() for the reported table during the |
158 | * early stage. |
159 | */ |
160 | for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { |
161 | table_desc = &acpi_gbl_root_table_list.tables[i]; |
162 | if (table_desc->pointer) { |
163 | ACPI_ERROR((AE_INFO, |
164 | "Table [%4.4s] is not invalidated during early boot stage" , |
165 | table_desc->signature.ascii)); |
166 | } |
167 | } |
168 | |
169 | if (!acpi_gbl_enable_table_validation) { |
170 | /* |
171 | * Now it's safe to do full table validation. We can do deferred |
172 | * table initialization here once the flag is set. |
173 | */ |
174 | acpi_gbl_enable_table_validation = TRUE; |
175 | for (i = 0; i < acpi_gbl_root_table_list.current_table_count; |
176 | ++i) { |
177 | table_desc = &acpi_gbl_root_table_list.tables[i]; |
178 | if (!(table_desc->flags & ACPI_TABLE_IS_VERIFIED)) { |
179 | status = |
180 | acpi_tb_verify_temp_table(table_desc, NULL, |
181 | table_index: &j); |
182 | if (ACPI_FAILURE(status)) { |
183 | acpi_tb_uninstall_table(table_desc); |
184 | } |
185 | } |
186 | } |
187 | } |
188 | |
189 | acpi_gbl_root_table_list.flags |= ACPI_ROOT_ALLOW_RESIZE; |
190 | status = acpi_tb_resize_root_table_list(); |
191 | acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED; |
192 | |
193 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
194 | return_ACPI_STATUS(status); |
195 | } |
196 | |
197 | ACPI_EXPORT_SYMBOL_INIT(acpi_reallocate_root_table) |
198 | |
199 | /******************************************************************************* |
200 | * |
201 | * FUNCTION: acpi_get_table_header |
202 | * |
203 | * PARAMETERS: signature - ACPI signature of needed table |
204 | * instance - Which instance (for SSDTs) |
205 | * out_table_header - The pointer to the where the table header |
206 | * is returned |
207 | * |
208 | * RETURN: Status and a copy of the table header |
209 | * |
210 | * DESCRIPTION: Finds and returns an ACPI table header. Caller provides the |
211 | * memory where a copy of the header is to be returned |
212 | * (fixed length). |
213 | * |
214 | ******************************************************************************/ |
215 | acpi_status |
216 | (char *signature, |
217 | u32 instance, struct acpi_table_header *) |
218 | { |
219 | u32 i; |
220 | u32 j; |
221 | struct acpi_table_header *; |
222 | |
223 | /* Parameter validation */ |
224 | |
225 | if (!signature || !out_table_header) { |
226 | return (AE_BAD_PARAMETER); |
227 | } |
228 | |
229 | /* Walk the root table list */ |
230 | |
231 | for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; |
232 | i++) { |
233 | if (!ACPI_COMPARE_NAMESEG |
234 | (&(acpi_gbl_root_table_list.tables[i].signature), |
235 | signature)) { |
236 | continue; |
237 | } |
238 | |
239 | if (++j < instance) { |
240 | continue; |
241 | } |
242 | |
243 | if (!acpi_gbl_root_table_list.tables[i].pointer) { |
244 | if ((acpi_gbl_root_table_list.tables[i].flags & |
245 | ACPI_TABLE_ORIGIN_MASK) == |
246 | ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) { |
247 | header = |
248 | acpi_os_map_memory(where: acpi_gbl_root_table_list. |
249 | tables[i].address, |
250 | length: sizeof(struct |
251 | acpi_table_header)); |
252 | if (!header) { |
253 | return (AE_NO_MEMORY); |
254 | } |
255 | |
256 | memcpy(out_table_header, header, |
257 | sizeof(struct acpi_table_header)); |
258 | acpi_os_unmap_memory(logical_address: header, |
259 | size: sizeof(struct |
260 | acpi_table_header)); |
261 | } else { |
262 | return (AE_NOT_FOUND); |
263 | } |
264 | } else { |
265 | memcpy(out_table_header, |
266 | acpi_gbl_root_table_list.tables[i].pointer, |
267 | sizeof(struct acpi_table_header)); |
268 | } |
269 | return (AE_OK); |
270 | } |
271 | |
272 | return (AE_NOT_FOUND); |
273 | } |
274 | |
275 | ACPI_EXPORT_SYMBOL(acpi_get_table_header) |
276 | |
277 | /******************************************************************************* |
278 | * |
279 | * FUNCTION: acpi_get_table |
280 | * |
281 | * PARAMETERS: signature - ACPI signature of needed table |
282 | * instance - Which instance (for SSDTs) |
283 | * out_table - Where the pointer to the table is returned |
284 | * |
285 | * RETURN: Status and pointer to the requested table |
286 | * |
287 | * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the |
288 | * RSDT/XSDT. |
289 | * Note that an early stage acpi_get_table() call must be paired |
290 | * with an early stage acpi_put_table() call. otherwise the table |
291 | * pointer mapped by the early stage mapping implementation may be |
292 | * erroneously unmapped by the late stage unmapping implementation |
293 | * in an acpi_put_table() invoked during the late stage. |
294 | * |
295 | ******************************************************************************/ |
296 | acpi_status |
297 | acpi_get_table(char *signature, |
298 | u32 instance, struct acpi_table_header ** out_table) |
299 | { |
300 | u32 i; |
301 | u32 j; |
302 | acpi_status status = AE_NOT_FOUND; |
303 | struct acpi_table_desc *table_desc; |
304 | |
305 | /* Parameter validation */ |
306 | |
307 | if (!signature || !out_table) { |
308 | return (AE_BAD_PARAMETER); |
309 | } |
310 | |
311 | /* |
312 | * Note that the following line is required by some OSPMs, they only |
313 | * check if the returned table is NULL instead of the returned status |
314 | * to determined if this function is succeeded. |
315 | */ |
316 | *out_table = NULL; |
317 | |
318 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
319 | |
320 | /* Walk the root table list */ |
321 | |
322 | for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; |
323 | i++) { |
324 | table_desc = &acpi_gbl_root_table_list.tables[i]; |
325 | |
326 | if (!ACPI_COMPARE_NAMESEG(&table_desc->signature, signature)) { |
327 | continue; |
328 | } |
329 | |
330 | if (++j < instance) { |
331 | continue; |
332 | } |
333 | |
334 | status = acpi_tb_get_table(table_desc, out_table); |
335 | break; |
336 | } |
337 | |
338 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
339 | return (status); |
340 | } |
341 | |
342 | ACPI_EXPORT_SYMBOL(acpi_get_table) |
343 | |
344 | /******************************************************************************* |
345 | * |
346 | * FUNCTION: acpi_put_table |
347 | * |
348 | * PARAMETERS: table - The pointer to the table |
349 | * |
350 | * RETURN: None |
351 | * |
352 | * DESCRIPTION: Release a table returned by acpi_get_table() and its clones. |
353 | * Note that it is not safe if this function was invoked after an |
354 | * uninstallation happened to the original table descriptor. |
355 | * Currently there is no OSPMs' requirement to handle such |
356 | * situations. |
357 | * |
358 | ******************************************************************************/ |
359 | void acpi_put_table(struct acpi_table_header *table) |
360 | { |
361 | u32 i; |
362 | struct acpi_table_desc *table_desc; |
363 | |
364 | ACPI_FUNCTION_TRACE(acpi_put_table); |
365 | |
366 | if (!table) { |
367 | return_VOID; |
368 | } |
369 | |
370 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
371 | |
372 | /* Walk the root table list */ |
373 | |
374 | for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { |
375 | table_desc = &acpi_gbl_root_table_list.tables[i]; |
376 | |
377 | if (table_desc->pointer != table) { |
378 | continue; |
379 | } |
380 | |
381 | acpi_tb_put_table(table_desc); |
382 | break; |
383 | } |
384 | |
385 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
386 | return_VOID; |
387 | } |
388 | |
389 | ACPI_EXPORT_SYMBOL(acpi_put_table) |
390 | |
391 | /******************************************************************************* |
392 | * |
393 | * FUNCTION: acpi_get_table_by_index |
394 | * |
395 | * PARAMETERS: table_index - Table index |
396 | * out_table - Where the pointer to the table is returned |
397 | * |
398 | * RETURN: Status and pointer to the requested table |
399 | * |
400 | * DESCRIPTION: Obtain a table by an index into the global table list. Used |
401 | * internally also. |
402 | * |
403 | ******************************************************************************/ |
404 | acpi_status |
405 | acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table) |
406 | { |
407 | acpi_status status; |
408 | |
409 | ACPI_FUNCTION_TRACE(acpi_get_table_by_index); |
410 | |
411 | /* Parameter validation */ |
412 | |
413 | if (!out_table) { |
414 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
415 | } |
416 | |
417 | /* |
418 | * Note that the following line is required by some OSPMs, they only |
419 | * check if the returned table is NULL instead of the returned status |
420 | * to determined if this function is succeeded. |
421 | */ |
422 | *out_table = NULL; |
423 | |
424 | (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); |
425 | |
426 | /* Validate index */ |
427 | |
428 | if (table_index >= acpi_gbl_root_table_list.current_table_count) { |
429 | status = AE_BAD_PARAMETER; |
430 | goto unlock_and_exit; |
431 | } |
432 | |
433 | status = |
434 | acpi_tb_get_table(table_desc: &acpi_gbl_root_table_list.tables[table_index], |
435 | out_table); |
436 | |
437 | unlock_and_exit: |
438 | (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); |
439 | return_ACPI_STATUS(status); |
440 | } |
441 | |
442 | ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) |
443 | |
444 | /******************************************************************************* |
445 | * |
446 | * FUNCTION: acpi_install_table_handler |
447 | * |
448 | * PARAMETERS: handler - Table event handler |
449 | * context - Value passed to the handler on each event |
450 | * |
451 | * RETURN: Status |
452 | * |
453 | * DESCRIPTION: Install a global table event handler. |
454 | * |
455 | ******************************************************************************/ |
456 | acpi_status |
457 | acpi_install_table_handler(acpi_table_handler handler, void *context) |
458 | { |
459 | acpi_status status; |
460 | |
461 | ACPI_FUNCTION_TRACE(acpi_install_table_handler); |
462 | |
463 | if (!handler) { |
464 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
465 | } |
466 | |
467 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
468 | if (ACPI_FAILURE(status)) { |
469 | return_ACPI_STATUS(status); |
470 | } |
471 | |
472 | /* Don't allow more than one handler */ |
473 | |
474 | if (acpi_gbl_table_handler) { |
475 | status = AE_ALREADY_EXISTS; |
476 | goto cleanup; |
477 | } |
478 | |
479 | /* Install the handler */ |
480 | |
481 | acpi_gbl_table_handler = handler; |
482 | acpi_gbl_table_handler_context = context; |
483 | |
484 | cleanup: |
485 | (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
486 | return_ACPI_STATUS(status); |
487 | } |
488 | |
489 | ACPI_EXPORT_SYMBOL(acpi_install_table_handler) |
490 | |
491 | /******************************************************************************* |
492 | * |
493 | * FUNCTION: acpi_remove_table_handler |
494 | * |
495 | * PARAMETERS: handler - Table event handler that was installed |
496 | * previously. |
497 | * |
498 | * RETURN: Status |
499 | * |
500 | * DESCRIPTION: Remove a table event handler |
501 | * |
502 | ******************************************************************************/ |
503 | acpi_status acpi_remove_table_handler(acpi_table_handler handler) |
504 | { |
505 | acpi_status status; |
506 | |
507 | ACPI_FUNCTION_TRACE(acpi_remove_table_handler); |
508 | |
509 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); |
510 | if (ACPI_FAILURE(status)) { |
511 | return_ACPI_STATUS(status); |
512 | } |
513 | |
514 | /* Make sure that the installed handler is the same */ |
515 | |
516 | if (!handler || handler != acpi_gbl_table_handler) { |
517 | status = AE_BAD_PARAMETER; |
518 | goto cleanup; |
519 | } |
520 | |
521 | /* Remove the handler */ |
522 | |
523 | acpi_gbl_table_handler = NULL; |
524 | |
525 | cleanup: |
526 | (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); |
527 | return_ACPI_STATUS(status); |
528 | } |
529 | |
530 | ACPI_EXPORT_SYMBOL(acpi_remove_table_handler) |
531 | |