mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-26 22:24:09 +08:00
aa342261bd
ACPICA commit 47f5607c204719d9239a12b889df725225098c8f Module-level code refers to executable ASL code that runs during table load. This is typically used in ASL to declare named objects based on a condition evaluated during table load like so: definition_block(...) { opreation_region (OPR1, system_memory, ...) Field (OPR1) { FLD1, 8 /* Assume that FLD1's value is 0x1 */ } /* The if statement below is referred to as module-level code */ If (FLD1) { /* Declare DEV1 conditionally */ Device (DEV1) {...} } Device (DEV2) { ... } } In legacy module-level code, the execution of the If statement was deferred after other modules were loaded. The order of code execution for the table above is the following: 1.) Load OPR1 to the ACPI Namespace 2.) Load FLD1 to the ACPI Namespace (not intended for drivers) 3.) Load DEV2 to the ACPI Namespace 4.) Execute If (FLD1) and load DEV1 if the condition is true This legacy approach can be problematic for tables that look like the following: definition_block(...) { opreation_region (OPR1, system_memory, ...) Field (OPR1) { FLD1, 8 /* Assume that FLD1's value is 0x1 */ } /* The if statement below is referred to as module-level code */ If (FLD1) { /* Declare DEV1 conditionally */ Device (DEV1) {...} } Scope (DEV1) { /* Add objects DEV1's scope */ Name (OBJ1, 0x1234) } } When loading this in the legacy approach, Scope DEV1 gets evaluated before the If statement. The following is the order of execution: 1.) Load OPR1 to the ACPI Namespace 2.) Load FLD1 to the ACPI Namespace (not intended for drivers) 3.) Add OBJ1 under DEV1's scope -- ERROR. DEV1 does not exist 4.) Execute If (FLD1) and load DEV1 if the condition is true The legacy approach can never succeed for tables like this due to the deferral of the module-level code. Due to this limitation, a new module-level code was developed. This new approach exeutes if statements in the order that they appear in the definition block. With this approach, the order of execution for the above defintion block is as follows: 1.) Load OPR1 to the ACPI Namespace 2.) Load FLD1 to the ACPI Namespace (not intended for drivers) 3.) Execute If (FLD1) and load DEV1 because the condition is true 4.) Add OBJ1 under DEV1's scope. Since DEV1 is loaded in the namespace in step 3, step 4 executes successfully. This change removes support for the legacy module-level code execution. From this point onward, the new module-level code execution will be the official approach. Link: https://github.com/acpica/acpica/commit/47f5607c Signed-off-by: Erik Schmauss <erik.schmauss@intel.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
272 lines
7.5 KiB
C
272 lines
7.5 KiB
C
// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
|
|
/******************************************************************************
|
|
*
|
|
* Module Name: nsparse - namespace interface to AML parser
|
|
*
|
|
* Copyright (C) 2000 - 2019, Intel Corp.
|
|
*
|
|
*****************************************************************************/
|
|
|
|
#include <acpi/acpi.h>
|
|
#include "accommon.h"
|
|
#include "acnamesp.h"
|
|
#include "acparser.h"
|
|
#include "acdispat.h"
|
|
#include "actables.h"
|
|
#include "acinterp.h"
|
|
|
|
#define _COMPONENT ACPI_NAMESPACE
|
|
ACPI_MODULE_NAME("nsparse")
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: ns_execute_table
|
|
*
|
|
* PARAMETERS: table_desc - An ACPI table descriptor for table to parse
|
|
* start_node - Where to enter the table into the namespace
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Load ACPI/AML table by executing the entire table as a single
|
|
* large control method.
|
|
*
|
|
* NOTE: The point of this is to execute any module-level code in-place
|
|
* as the table is parsed. Some AML code depends on this behavior.
|
|
*
|
|
* It is a run-time option at this time, but will eventually become
|
|
* the default.
|
|
*
|
|
* Note: This causes the table to only have a single-pass parse.
|
|
* However, this is compatible with other ACPI implementations.
|
|
*
|
|
******************************************************************************/
|
|
acpi_status
|
|
acpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
|
|
{
|
|
acpi_status status;
|
|
struct acpi_table_header *table;
|
|
acpi_owner_id owner_id;
|
|
struct acpi_evaluate_info *info = NULL;
|
|
u32 aml_length;
|
|
u8 *aml_start;
|
|
union acpi_operand_object *method_obj = NULL;
|
|
|
|
ACPI_FUNCTION_TRACE(ns_execute_table);
|
|
|
|
status = acpi_get_table_by_index(table_index, &table);
|
|
if (ACPI_FAILURE(status)) {
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/* Table must consist of at least a complete header */
|
|
|
|
if (table->length < sizeof(struct acpi_table_header)) {
|
|
return_ACPI_STATUS(AE_BAD_HEADER);
|
|
}
|
|
|
|
aml_start = (u8 *)table + sizeof(struct acpi_table_header);
|
|
aml_length = table->length - sizeof(struct acpi_table_header);
|
|
|
|
status = acpi_tb_get_owner_id(table_index, &owner_id);
|
|
if (ACPI_FAILURE(status)) {
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/* Create, initialize, and link a new temporary method object */
|
|
|
|
method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
|
|
if (!method_obj) {
|
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
|
}
|
|
|
|
/* Allocate the evaluation information block */
|
|
|
|
info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
|
|
if (!info) {
|
|
status = AE_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
|
|
"%s: Create table pseudo-method for [%4.4s] @%p, method %p\n",
|
|
ACPI_GET_FUNCTION_NAME, table->signature, table,
|
|
method_obj));
|
|
|
|
method_obj->method.aml_start = aml_start;
|
|
method_obj->method.aml_length = aml_length;
|
|
method_obj->method.owner_id = owner_id;
|
|
method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
|
|
|
|
info->pass_number = ACPI_IMODE_EXECUTE;
|
|
info->node = start_node;
|
|
info->obj_desc = method_obj;
|
|
info->node_flags = info->node->flags;
|
|
info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE);
|
|
if (!info->full_pathname) {
|
|
status = AE_NO_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Optional object evaluation log */
|
|
|
|
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
|
|
"%-26s: (Definition Block level)\n",
|
|
"Module-level evaluation"));
|
|
|
|
status = acpi_ps_execute_table(info);
|
|
|
|
/* Optional object evaluation log */
|
|
|
|
ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
|
|
"%-26s: (Definition Block level)\n",
|
|
"Module-level complete"));
|
|
|
|
cleanup:
|
|
if (info) {
|
|
ACPI_FREE(info->full_pathname);
|
|
info->full_pathname = NULL;
|
|
}
|
|
ACPI_FREE(info);
|
|
acpi_ut_remove_reference(method_obj);
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: ns_one_complete_parse
|
|
*
|
|
* PARAMETERS: pass_number - 1 or 2
|
|
* table_desc - The table to be parsed.
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Perform one complete parse of an ACPI/AML table.
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status
|
|
acpi_ns_one_complete_parse(u32 pass_number,
|
|
u32 table_index,
|
|
struct acpi_namespace_node *start_node)
|
|
{
|
|
union acpi_parse_object *parse_root;
|
|
acpi_status status;
|
|
u32 aml_length;
|
|
u8 *aml_start;
|
|
struct acpi_walk_state *walk_state;
|
|
struct acpi_table_header *table;
|
|
acpi_owner_id owner_id;
|
|
|
|
ACPI_FUNCTION_TRACE(ns_one_complete_parse);
|
|
|
|
status = acpi_get_table_by_index(table_index, &table);
|
|
if (ACPI_FAILURE(status)) {
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/* Table must consist of at least a complete header */
|
|
|
|
if (table->length < sizeof(struct acpi_table_header)) {
|
|
return_ACPI_STATUS(AE_BAD_HEADER);
|
|
}
|
|
|
|
aml_start = (u8 *)table + sizeof(struct acpi_table_header);
|
|
aml_length = table->length - sizeof(struct acpi_table_header);
|
|
|
|
status = acpi_tb_get_owner_id(table_index, &owner_id);
|
|
if (ACPI_FAILURE(status)) {
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/* Create and init a Root Node */
|
|
|
|
parse_root = acpi_ps_create_scope_op(aml_start);
|
|
if (!parse_root) {
|
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
|
}
|
|
|
|
/* Create and initialize a new walk state */
|
|
|
|
walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
|
|
if (!walk_state) {
|
|
acpi_ps_free_op(parse_root);
|
|
return_ACPI_STATUS(AE_NO_MEMORY);
|
|
}
|
|
|
|
status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
|
|
aml_start, aml_length, NULL,
|
|
(u8)pass_number);
|
|
if (ACPI_FAILURE(status)) {
|
|
acpi_ds_delete_walk_state(walk_state);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* Found OSDT table, enable the namespace override feature */
|
|
|
|
if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_OSDT) &&
|
|
pass_number == ACPI_IMODE_LOAD_PASS1) {
|
|
walk_state->namespace_override = TRUE;
|
|
}
|
|
|
|
/* start_node is the default location to load the table */
|
|
|
|
if (start_node && start_node != acpi_gbl_root_node) {
|
|
status =
|
|
acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
|
|
walk_state);
|
|
if (ACPI_FAILURE(status)) {
|
|
acpi_ds_delete_walk_state(walk_state);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
/* Parse the AML */
|
|
|
|
ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
|
|
"*PARSE* pass %u parse\n", pass_number));
|
|
acpi_ex_enter_interpreter();
|
|
status = acpi_ps_parse_aml(walk_state);
|
|
acpi_ex_exit_interpreter();
|
|
|
|
cleanup:
|
|
acpi_ps_delete_parse_tree(parse_root);
|
|
return_ACPI_STATUS(status);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FUNCTION: acpi_ns_parse_table
|
|
*
|
|
* PARAMETERS: table_desc - An ACPI table descriptor for table to parse
|
|
* start_node - Where to enter the table into the namespace
|
|
*
|
|
* RETURN: Status
|
|
*
|
|
* DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
|
|
*
|
|
******************************************************************************/
|
|
|
|
acpi_status
|
|
acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
|
|
{
|
|
acpi_status status;
|
|
|
|
ACPI_FUNCTION_TRACE(ns_parse_table);
|
|
|
|
/*
|
|
* Executes the AML table as one large control method.
|
|
* The point of this is to execute any module-level code in-place
|
|
* as the table is parsed. Some AML code depends on this behavior.
|
|
*
|
|
* Note: This causes the table to only have a single-pass parse.
|
|
* However, this is compatible with other ACPI implementations.
|
|
*/
|
|
ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
|
|
"%s: **** Start table execution pass\n",
|
|
ACPI_GET_FUNCTION_NAME));
|
|
|
|
status = acpi_ns_execute_table(table_index, start_node);
|
|
|
|
return_ACPI_STATUS(status);
|
|
}
|