tbxface.c (15465B)
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 - 2022, 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 17ACPI_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 ******************************************************************************/ 32acpi_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 67acpi_status ACPI_INIT_FUNCTION 68acpi_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 117ACPI_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 ******************************************************************************/ 133acpi_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 &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 197ACPI_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 ******************************************************************************/ 215acpi_status 216acpi_get_table_header(char *signature, 217 u32 instance, struct acpi_table_header *out_table_header) 218{ 219 u32 i; 220 u32 j; 221 struct acpi_table_header *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(acpi_gbl_root_table_list. 249 tables[i].address, 250 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(header, 259 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 275ACPI_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 ******************************************************************************/ 296acpi_status 297acpi_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 342ACPI_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 ******************************************************************************/ 359void 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 389ACPI_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 ******************************************************************************/ 404acpi_status 405acpi_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(&acpi_gbl_root_table_list.tables[table_index], 435 out_table); 436 437unlock_and_exit: 438 (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); 439 return_ACPI_STATUS(status); 440} 441 442ACPI_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 ******************************************************************************/ 456acpi_status 457acpi_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 484cleanup: 485 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); 486 return_ACPI_STATUS(status); 487} 488 489ACPI_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 ******************************************************************************/ 503acpi_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 525cleanup: 526 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS); 527 return_ACPI_STATUS(status); 528} 529 530ACPI_EXPORT_SYMBOL(acpi_remove_table_handler)