linux/drivers/acpi/acpica/tbxface.c
<<
>>
Prefs
   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 - 2021, 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)
 531