Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acinterp.h"
0013 #include "acnamesp.h"
0014 #include "actables.h"
0015 #include "acdispat.h"
0016 #include "acevents.h"
0017 #include "amlcode.h"
0018 
0019 #define _COMPONENT          ACPI_EXECUTER
0020 ACPI_MODULE_NAME("exconfig")
0021 
0022 /* Local prototypes */
0023 static acpi_status
0024 acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle);
0025 
0026 static acpi_status
0027 acpi_ex_region_read(union acpi_operand_object *obj_desc,
0028             u32 length, u8 *buffer);
0029 
0030 /*******************************************************************************
0031  *
0032  * FUNCTION:    acpi_ex_add_table
0033  *
0034  * PARAMETERS:  table               - Pointer to raw table
0035  *              parent_node         - Where to load the table (scope)
0036  *              ddb_handle          - Where to return the table handle.
0037  *
0038  * RETURN:      Status
0039  *
0040  * DESCRIPTION: Common function to Install and Load an ACPI table with a
0041  *              returned table handle.
0042  *
0043  ******************************************************************************/
0044 
0045 static acpi_status
0046 acpi_ex_add_table(u32 table_index, union acpi_operand_object **ddb_handle)
0047 {
0048     union acpi_operand_object *obj_desc;
0049 
0050     ACPI_FUNCTION_TRACE(ex_add_table);
0051 
0052     /* Create an object to be the table handle */
0053 
0054     obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_REFERENCE);
0055     if (!obj_desc) {
0056         return_ACPI_STATUS(AE_NO_MEMORY);
0057     }
0058 
0059     /* Init the table handle */
0060 
0061     obj_desc->common.flags |= AOPOBJ_DATA_VALID;
0062     obj_desc->reference.class = ACPI_REFCLASS_TABLE;
0063     obj_desc->reference.value = table_index;
0064     *ddb_handle = obj_desc;
0065     return_ACPI_STATUS(AE_OK);
0066 }
0067 
0068 /*******************************************************************************
0069  *
0070  * FUNCTION:    acpi_ex_load_table_op
0071  *
0072  * PARAMETERS:  walk_state          - Current state with operands
0073  *              return_desc         - Where to store the return object
0074  *
0075  * RETURN:      Status
0076  *
0077  * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
0078  *
0079  ******************************************************************************/
0080 
0081 acpi_status
0082 acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
0083               union acpi_operand_object **return_desc)
0084 {
0085     acpi_status status;
0086     union acpi_operand_object **operand = &walk_state->operands[0];
0087     struct acpi_namespace_node *parent_node;
0088     struct acpi_namespace_node *start_node;
0089     struct acpi_namespace_node *parameter_node = NULL;
0090     union acpi_operand_object *return_obj;
0091     union acpi_operand_object *ddb_handle;
0092     u32 table_index;
0093 
0094     ACPI_FUNCTION_TRACE(ex_load_table_op);
0095 
0096     /* Create the return object */
0097 
0098     return_obj = acpi_ut_create_integer_object((u64)0);
0099     if (!return_obj) {
0100         return_ACPI_STATUS(AE_NO_MEMORY);
0101     }
0102 
0103     *return_desc = return_obj;
0104 
0105     /* Find the ACPI table in the RSDT/XSDT */
0106 
0107     acpi_ex_exit_interpreter();
0108     status = acpi_tb_find_table(operand[0]->string.pointer,
0109                     operand[1]->string.pointer,
0110                     operand[2]->string.pointer, &table_index);
0111     acpi_ex_enter_interpreter();
0112     if (ACPI_FAILURE(status)) {
0113         if (status != AE_NOT_FOUND) {
0114             return_ACPI_STATUS(status);
0115         }
0116 
0117         /* Table not found, return an Integer=0 and AE_OK */
0118 
0119         return_ACPI_STATUS(AE_OK);
0120     }
0121 
0122     /* Default nodes */
0123 
0124     start_node = walk_state->scope_info->scope.node;
0125     parent_node = acpi_gbl_root_node;
0126 
0127     /* root_path (optional parameter) */
0128 
0129     if (operand[3]->string.length > 0) {
0130         /*
0131          * Find the node referenced by the root_path_string. This is the
0132          * location within the namespace where the table will be loaded.
0133          */
0134         status = acpi_ns_get_node_unlocked(start_node,
0135                            operand[3]->string.pointer,
0136                            ACPI_NS_SEARCH_PARENT,
0137                            &parent_node);
0138         if (ACPI_FAILURE(status)) {
0139             return_ACPI_STATUS(status);
0140         }
0141     }
0142 
0143     /* parameter_path (optional parameter) */
0144 
0145     if (operand[4]->string.length > 0) {
0146         if ((operand[4]->string.pointer[0] != AML_ROOT_PREFIX) &&
0147             (operand[4]->string.pointer[0] != AML_PARENT_PREFIX)) {
0148             /*
0149              * Path is not absolute, so it will be relative to the node
0150              * referenced by the root_path_string (or the NS root if omitted)
0151              */
0152             start_node = parent_node;
0153         }
0154 
0155         /* Find the node referenced by the parameter_path_string */
0156 
0157         status = acpi_ns_get_node_unlocked(start_node,
0158                            operand[4]->string.pointer,
0159                            ACPI_NS_SEARCH_PARENT,
0160                            &parameter_node);
0161         if (ACPI_FAILURE(status)) {
0162             return_ACPI_STATUS(status);
0163         }
0164     }
0165 
0166     /* Load the table into the namespace */
0167 
0168     ACPI_INFO(("Dynamic OEM Table Load:"));
0169     acpi_ex_exit_interpreter();
0170     status = acpi_tb_load_table(table_index, parent_node);
0171     acpi_ex_enter_interpreter();
0172     if (ACPI_FAILURE(status)) {
0173         return_ACPI_STATUS(status);
0174     }
0175 
0176     status = acpi_ex_add_table(table_index, &ddb_handle);
0177     if (ACPI_FAILURE(status)) {
0178         return_ACPI_STATUS(status);
0179     }
0180 
0181     /* Complete the initialization/resolution of new objects */
0182 
0183     acpi_ex_exit_interpreter();
0184     acpi_ns_initialize_objects();
0185     acpi_ex_enter_interpreter();
0186 
0187     /* Parameter Data (optional) */
0188 
0189     if (parameter_node) {
0190 
0191         /* Store the parameter data into the optional parameter object */
0192 
0193         status = acpi_ex_store(operand[5],
0194                        ACPI_CAST_PTR(union acpi_operand_object,
0195                              parameter_node),
0196                        walk_state);
0197         if (ACPI_FAILURE(status)) {
0198             (void)acpi_ex_unload_table(ddb_handle);
0199 
0200             acpi_ut_remove_reference(ddb_handle);
0201             return_ACPI_STATUS(status);
0202         }
0203     }
0204 
0205     /* Remove the reference to ddb_handle created by acpi_ex_add_table above */
0206 
0207     acpi_ut_remove_reference(ddb_handle);
0208 
0209     /* Return -1 (non-zero) indicates success */
0210 
0211     return_obj->integer.value = 0xFFFFFFFFFFFFFFFF;
0212     return_ACPI_STATUS(status);
0213 }
0214 
0215 /*******************************************************************************
0216  *
0217  * FUNCTION:    acpi_ex_region_read
0218  *
0219  * PARAMETERS:  obj_desc        - Region descriptor
0220  *              length          - Number of bytes to read
0221  *              buffer          - Pointer to where to put the data
0222  *
0223  * RETURN:      Status
0224  *
0225  * DESCRIPTION: Read data from an operation region. The read starts from the
0226  *              beginning of the region.
0227  *
0228  ******************************************************************************/
0229 
0230 static acpi_status
0231 acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer)
0232 {
0233     acpi_status status;
0234     u64 value;
0235     u32 region_offset = 0;
0236     u32 i;
0237 
0238     /* Bytewise reads */
0239 
0240     for (i = 0; i < length; i++) {
0241         status =
0242             acpi_ev_address_space_dispatch(obj_desc, NULL, ACPI_READ,
0243                            region_offset, 8, &value);
0244         if (ACPI_FAILURE(status)) {
0245             return (status);
0246         }
0247 
0248         *buffer = (u8)value;
0249         buffer++;
0250         region_offset++;
0251     }
0252 
0253     return (AE_OK);
0254 }
0255 
0256 /*******************************************************************************
0257  *
0258  * FUNCTION:    acpi_ex_load_op
0259  *
0260  * PARAMETERS:  obj_desc        - Region or Buffer/Field where the table will be
0261  *                                obtained
0262  *              target          - Where the status of the load will be stored
0263  *              walk_state      - Current state
0264  *
0265  * RETURN:      Status
0266  *
0267  * DESCRIPTION: Load an ACPI table from a field or operation region
0268  *
0269  * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
0270  *       objects before this code is reached.
0271  *
0272  *       If source is an operation region, it must refer to system_memory, as
0273  *       per the ACPI specification.
0274  *
0275  ******************************************************************************/
0276 
0277 acpi_status
0278 acpi_ex_load_op(union acpi_operand_object *obj_desc,
0279         union acpi_operand_object *target,
0280         struct acpi_walk_state *walk_state)
0281 {
0282     union acpi_operand_object *ddb_handle;
0283     struct acpi_table_header *table_header;
0284     struct acpi_table_header *table;
0285     u32 table_index;
0286     acpi_status status;
0287     u32 length;
0288 
0289     ACPI_FUNCTION_TRACE(ex_load_op);
0290 
0291     if (target->common.descriptor_type == ACPI_DESC_TYPE_NAMED) {
0292         target =
0293             acpi_ns_get_attached_object(ACPI_CAST_PTR
0294                         (struct acpi_namespace_node,
0295                          target));
0296     }
0297     if (target->common.type != ACPI_TYPE_INTEGER) {
0298         ACPI_EXCEPTION((AE_INFO, AE_TYPE,
0299                 "Type not integer: %X\n", target->common.type));
0300         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0301     }
0302 
0303     target->integer.value = 0;
0304 
0305     /* Source Object can be either an op_region or a Buffer/Field */
0306 
0307     switch (obj_desc->common.type) {
0308     case ACPI_TYPE_REGION:
0309 
0310         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0311                   "Load table from Region %p\n", obj_desc));
0312 
0313         /* Region must be system_memory (from ACPI spec) */
0314 
0315         if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
0316             return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0317         }
0318 
0319         /*
0320          * If the Region Address and Length have not been previously
0321          * evaluated, evaluate them now and save the results.
0322          */
0323         if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
0324             status = acpi_ds_get_region_arguments(obj_desc);
0325             if (ACPI_FAILURE(status)) {
0326                 return_ACPI_STATUS(status);
0327             }
0328         }
0329 
0330         /* Get the table header first so we can get the table length */
0331 
0332         table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
0333         if (!table_header) {
0334             return_ACPI_STATUS(AE_NO_MEMORY);
0335         }
0336 
0337         status =
0338             acpi_ex_region_read(obj_desc,
0339                     sizeof(struct acpi_table_header),
0340                     ACPI_CAST_PTR(u8, table_header));
0341         length = table_header->length;
0342         ACPI_FREE(table_header);
0343 
0344         if (ACPI_FAILURE(status)) {
0345             return_ACPI_STATUS(status);
0346         }
0347 
0348         /* Must have at least an ACPI table header */
0349 
0350         if (length < sizeof(struct acpi_table_header)) {
0351             return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0352         }
0353 
0354         /*
0355          * The original implementation simply mapped the table, with no copy.
0356          * However, the memory region is not guaranteed to remain stable and
0357          * we must copy the table to a local buffer. For example, the memory
0358          * region is corrupted after suspend on some machines. Dynamically
0359          * loaded tables are usually small, so this overhead is minimal.
0360          *
0361          * The latest implementation (5/2009) does not use a mapping at all.
0362          * We use the low-level operation region interface to read the table
0363          * instead of the obvious optimization of using a direct mapping.
0364          * This maintains a consistent use of operation regions across the
0365          * entire subsystem. This is important if additional processing must
0366          * be performed in the (possibly user-installed) operation region
0367          * handler. For example, acpi_exec and ASLTS depend on this.
0368          */
0369 
0370         /* Allocate a buffer for the table */
0371 
0372         table = ACPI_ALLOCATE(length);
0373         if (!table) {
0374             return_ACPI_STATUS(AE_NO_MEMORY);
0375         }
0376 
0377         /* Read the entire table */
0378 
0379         status = acpi_ex_region_read(obj_desc, length,
0380                          ACPI_CAST_PTR(u8, table));
0381         if (ACPI_FAILURE(status)) {
0382             ACPI_FREE(table);
0383             return_ACPI_STATUS(status);
0384         }
0385         break;
0386 
0387     case ACPI_TYPE_BUFFER:  /* Buffer or resolved region_field */
0388 
0389         ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
0390                   "Load table from Buffer or Field %p\n",
0391                   obj_desc));
0392 
0393         /* Must have at least an ACPI table header */
0394 
0395         if (obj_desc->buffer.length < sizeof(struct acpi_table_header)) {
0396             return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0397         }
0398 
0399         /* Get the actual table length from the table header */
0400 
0401         table_header =
0402             ACPI_CAST_PTR(struct acpi_table_header,
0403                   obj_desc->buffer.pointer);
0404         length = table_header->length;
0405 
0406         /* Table cannot extend beyond the buffer */
0407 
0408         if (length > obj_desc->buffer.length) {
0409             return_ACPI_STATUS(AE_AML_BUFFER_LIMIT);
0410         }
0411         if (length < sizeof(struct acpi_table_header)) {
0412             return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
0413         }
0414 
0415         /*
0416          * Copy the table from the buffer because the buffer could be
0417          * modified or even deleted in the future
0418          */
0419         table = ACPI_ALLOCATE(length);
0420         if (!table) {
0421             return_ACPI_STATUS(AE_NO_MEMORY);
0422         }
0423 
0424         memcpy(table, table_header, length);
0425         break;
0426 
0427     default:
0428 
0429         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0430     }
0431 
0432     /* Install the new table into the local data structures */
0433 
0434     ACPI_INFO(("Dynamic OEM Table Load:"));
0435     acpi_ex_exit_interpreter();
0436     status = acpi_tb_install_and_load_table(ACPI_PTR_TO_PHYSADDR(table),
0437                         ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
0438                         table, TRUE, &table_index);
0439     acpi_ex_enter_interpreter();
0440     if (ACPI_FAILURE(status)) {
0441 
0442         /* Delete allocated table buffer */
0443 
0444         ACPI_FREE(table);
0445         return_ACPI_STATUS(status);
0446     }
0447 
0448     /*
0449      * Add the table to the namespace.
0450      *
0451      * Note: Load the table objects relative to the root of the namespace.
0452      * This appears to go against the ACPI specification, but we do it for
0453      * compatibility with other ACPI implementations.
0454      */
0455     status = acpi_ex_add_table(table_index, &ddb_handle);
0456     if (ACPI_FAILURE(status)) {
0457         return_ACPI_STATUS(status);
0458     }
0459 
0460     /* Complete the initialization/resolution of new objects */
0461 
0462     acpi_ex_exit_interpreter();
0463     acpi_ns_initialize_objects();
0464     acpi_ex_enter_interpreter();
0465 
0466     /* Remove the reference to ddb_handle created by acpi_ex_add_table above */
0467 
0468     acpi_ut_remove_reference(ddb_handle);
0469 
0470     /* Return -1 (non-zero) indicates success */
0471 
0472     target->integer.value = 0xFFFFFFFFFFFFFFFF;
0473     return_ACPI_STATUS(status);
0474 }
0475 
0476 /*******************************************************************************
0477  *
0478  * FUNCTION:    acpi_ex_unload_table
0479  *
0480  * PARAMETERS:  ddb_handle          - Handle to a previously loaded table
0481  *
0482  * RETURN:      Status
0483  *
0484  * DESCRIPTION: Unload an ACPI table
0485  *
0486  ******************************************************************************/
0487 
0488 acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
0489 {
0490     acpi_status status = AE_OK;
0491     union acpi_operand_object *table_desc = ddb_handle;
0492     u32 table_index;
0493 
0494     ACPI_FUNCTION_TRACE(ex_unload_table);
0495 
0496     /*
0497      * Temporarily emit a warning so that the ASL for the machine can be
0498      * hopefully obtained. This is to say that the Unload() operator is
0499      * extremely rare if not completely unused.
0500      */
0501     ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table"));
0502 
0503     /*
0504      * May 2018: Unload is no longer supported for the following reasons:
0505      * 1) A correct implementation on some hosts may not be possible.
0506      * 2) Other ACPI implementations do not correctly/fully support it.
0507      * 3) It requires host device driver support which does not exist.
0508      *    (To properly support namespace unload out from underneath.)
0509      * 4) This AML operator has never been seen in the field.
0510      */
0511     ACPI_EXCEPTION((AE_INFO, AE_NOT_IMPLEMENTED,
0512             "AML Unload operator is not supported"));
0513 
0514     /*
0515      * Validate the handle
0516      * Although the handle is partially validated in acpi_ex_reconfiguration()
0517      * when it calls acpi_ex_resolve_operands(), the handle is more completely
0518      * validated here.
0519      *
0520      * Handle must be a valid operand object of type reference. Also, the
0521      * ddb_handle must still be marked valid (table has not been previously
0522      * unloaded)
0523      */
0524     if ((!ddb_handle) ||
0525         (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
0526         (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) ||
0527         (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) {
0528         return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
0529     }
0530 
0531     /* Get the table index from the ddb_handle */
0532 
0533     table_index = table_desc->reference.value;
0534 
0535     /*
0536      * Release the interpreter lock so that the table lock won't have
0537      * strict order requirement against it.
0538      */
0539     acpi_ex_exit_interpreter();
0540     status = acpi_tb_unload_table(table_index);
0541     acpi_ex_enter_interpreter();
0542 
0543     /*
0544      * Invalidate the handle. We do this because the handle may be stored
0545      * in a named object and may not be actually deleted until much later.
0546      */
0547     if (ACPI_SUCCESS(status)) {
0548         ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID;
0549     }
0550     return_ACPI_STATUS(status);
0551 }