162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: nsparse - namespace interface to AML parser
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acnamesp.h"
1362306a36Sopenharmony_ci#include "acparser.h"
1462306a36Sopenharmony_ci#include "acdispat.h"
1562306a36Sopenharmony_ci#include "actables.h"
1662306a36Sopenharmony_ci#include "acinterp.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define _COMPONENT          ACPI_NAMESPACE
1962306a36Sopenharmony_ciACPI_MODULE_NAME("nsparse")
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*******************************************************************************
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * FUNCTION:    ns_execute_table
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
2662306a36Sopenharmony_ci *              start_node      - Where to enter the table into the namespace
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * RETURN:      Status
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * DESCRIPTION: Load ACPI/AML table by executing the entire table as a single
3162306a36Sopenharmony_ci *              large control method.
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * NOTE: The point of this is to execute any module-level code in-place
3462306a36Sopenharmony_ci * as the table is parsed. Some AML code depends on this behavior.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * It is a run-time option at this time, but will eventually become
3762306a36Sopenharmony_ci * the default.
3862306a36Sopenharmony_ci *
3962306a36Sopenharmony_ci * Note: This causes the table to only have a single-pass parse.
4062306a36Sopenharmony_ci * However, this is compatible with other ACPI implementations.
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci ******************************************************************************/
4362306a36Sopenharmony_ciacpi_status
4462306a36Sopenharmony_ciacpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	acpi_status status;
4762306a36Sopenharmony_ci	struct acpi_table_header *table;
4862306a36Sopenharmony_ci	acpi_owner_id owner_id;
4962306a36Sopenharmony_ci	struct acpi_evaluate_info *info = NULL;
5062306a36Sopenharmony_ci	u32 aml_length;
5162306a36Sopenharmony_ci	u8 *aml_start;
5262306a36Sopenharmony_ci	union acpi_operand_object *method_obj = NULL;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_execute_table);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	status = acpi_get_table_by_index(table_index, &table);
5762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
5862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
5962306a36Sopenharmony_ci	}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* Table must consist of at least a complete header */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (table->length < sizeof(struct acpi_table_header)) {
6462306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_HEADER);
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
6862306a36Sopenharmony_ci	aml_length = table->length - sizeof(struct acpi_table_header);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	status = acpi_tb_get_owner_id(table_index, &owner_id);
7162306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
7262306a36Sopenharmony_ci		return_ACPI_STATUS(status);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	/* Create, initialize, and link a new temporary method object */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
7862306a36Sopenharmony_ci	if (!method_obj) {
7962306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/* Allocate the evaluation information block */
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
8562306a36Sopenharmony_ci	if (!info) {
8662306a36Sopenharmony_ci		status = AE_NO_MEMORY;
8762306a36Sopenharmony_ci		goto cleanup;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
9162306a36Sopenharmony_ci			      "%s: Create table pseudo-method for [%4.4s] @%p, method %p\n",
9262306a36Sopenharmony_ci			      ACPI_GET_FUNCTION_NAME, table->signature, table,
9362306a36Sopenharmony_ci			      method_obj));
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	method_obj->method.aml_start = aml_start;
9662306a36Sopenharmony_ci	method_obj->method.aml_length = aml_length;
9762306a36Sopenharmony_ci	method_obj->method.owner_id = owner_id;
9862306a36Sopenharmony_ci	method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	info->pass_number = ACPI_IMODE_EXECUTE;
10162306a36Sopenharmony_ci	info->node = start_node;
10262306a36Sopenharmony_ci	info->obj_desc = method_obj;
10362306a36Sopenharmony_ci	info->node_flags = info->node->flags;
10462306a36Sopenharmony_ci	info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE);
10562306a36Sopenharmony_ci	if (!info->full_pathname) {
10662306a36Sopenharmony_ci		status = AE_NO_MEMORY;
10762306a36Sopenharmony_ci		goto cleanup;
10862306a36Sopenharmony_ci	}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Optional object evaluation log */
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
11362306a36Sopenharmony_ci			      "%-26s:  (Definition Block level)\n",
11462306a36Sopenharmony_ci			      "Module-level evaluation"));
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	status = acpi_ps_execute_table(info);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* Optional object evaluation log */
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
12162306a36Sopenharmony_ci			      "%-26s:  (Definition Block level)\n",
12262306a36Sopenharmony_ci			      "Module-level complete"));
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cicleanup:
12562306a36Sopenharmony_ci	if (info) {
12662306a36Sopenharmony_ci		ACPI_FREE(info->full_pathname);
12762306a36Sopenharmony_ci		info->full_pathname = NULL;
12862306a36Sopenharmony_ci	}
12962306a36Sopenharmony_ci	ACPI_FREE(info);
13062306a36Sopenharmony_ci	acpi_ut_remove_reference(method_obj);
13162306a36Sopenharmony_ci	return_ACPI_STATUS(status);
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci/*******************************************************************************
13562306a36Sopenharmony_ci *
13662306a36Sopenharmony_ci * FUNCTION:    ns_one_complete_parse
13762306a36Sopenharmony_ci *
13862306a36Sopenharmony_ci * PARAMETERS:  pass_number             - 1 or 2
13962306a36Sopenharmony_ci *              table_desc              - The table to be parsed.
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * RETURN:      Status
14262306a36Sopenharmony_ci *
14362306a36Sopenharmony_ci * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
14462306a36Sopenharmony_ci *
14562306a36Sopenharmony_ci ******************************************************************************/
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ciacpi_status
14862306a36Sopenharmony_ciacpi_ns_one_complete_parse(u32 pass_number,
14962306a36Sopenharmony_ci			   u32 table_index,
15062306a36Sopenharmony_ci			   struct acpi_namespace_node *start_node)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	union acpi_parse_object *parse_root;
15362306a36Sopenharmony_ci	acpi_status status;
15462306a36Sopenharmony_ci	u32 aml_length;
15562306a36Sopenharmony_ci	u8 *aml_start;
15662306a36Sopenharmony_ci	struct acpi_walk_state *walk_state;
15762306a36Sopenharmony_ci	struct acpi_table_header *table;
15862306a36Sopenharmony_ci	acpi_owner_id owner_id;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_one_complete_parse);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	status = acpi_get_table_by_index(table_index, &table);
16362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
16462306a36Sopenharmony_ci		return_ACPI_STATUS(status);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	/* Table must consist of at least a complete header */
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (table->length < sizeof(struct acpi_table_header)) {
17062306a36Sopenharmony_ci		return_ACPI_STATUS(AE_BAD_HEADER);
17162306a36Sopenharmony_ci	}
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
17462306a36Sopenharmony_ci	aml_length = table->length - sizeof(struct acpi_table_header);
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	status = acpi_tb_get_owner_id(table_index, &owner_id);
17762306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
17862306a36Sopenharmony_ci		return_ACPI_STATUS(status);
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	/* Create and init a Root Node */
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	parse_root = acpi_ps_create_scope_op(aml_start);
18462306a36Sopenharmony_ci	if (!parse_root) {
18562306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	/* Create and initialize a new walk state */
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
19162306a36Sopenharmony_ci	if (!walk_state) {
19262306a36Sopenharmony_ci		acpi_ps_free_op(parse_root);
19362306a36Sopenharmony_ci		return_ACPI_STATUS(AE_NO_MEMORY);
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
19762306a36Sopenharmony_ci				       aml_start, aml_length, NULL,
19862306a36Sopenharmony_ci				       (u8)pass_number);
19962306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
20062306a36Sopenharmony_ci		acpi_ds_delete_walk_state(walk_state);
20162306a36Sopenharmony_ci		goto cleanup;
20262306a36Sopenharmony_ci	}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Found OSDT table, enable the namespace override feature */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_OSDT) &&
20762306a36Sopenharmony_ci	    pass_number == ACPI_IMODE_LOAD_PASS1) {
20862306a36Sopenharmony_ci		walk_state->namespace_override = TRUE;
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	/* start_node is the default location to load the table */
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (start_node && start_node != acpi_gbl_root_node) {
21462306a36Sopenharmony_ci		status =
21562306a36Sopenharmony_ci		    acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
21662306a36Sopenharmony_ci					     walk_state);
21762306a36Sopenharmony_ci		if (ACPI_FAILURE(status)) {
21862306a36Sopenharmony_ci			acpi_ds_delete_walk_state(walk_state);
21962306a36Sopenharmony_ci			goto cleanup;
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci	}
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	/* Parse the AML */
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
22662306a36Sopenharmony_ci			  "*PARSE* pass %u parse\n", pass_number));
22762306a36Sopenharmony_ci	acpi_ex_enter_interpreter();
22862306a36Sopenharmony_ci	status = acpi_ps_parse_aml(walk_state);
22962306a36Sopenharmony_ci	acpi_ex_exit_interpreter();
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cicleanup:
23262306a36Sopenharmony_ci	acpi_ps_delete_parse_tree(parse_root);
23362306a36Sopenharmony_ci	return_ACPI_STATUS(status);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*******************************************************************************
23762306a36Sopenharmony_ci *
23862306a36Sopenharmony_ci * FUNCTION:    acpi_ns_parse_table
23962306a36Sopenharmony_ci *
24062306a36Sopenharmony_ci * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
24162306a36Sopenharmony_ci *              start_node      - Where to enter the table into the namespace
24262306a36Sopenharmony_ci *
24362306a36Sopenharmony_ci * RETURN:      Status
24462306a36Sopenharmony_ci *
24562306a36Sopenharmony_ci * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
24662306a36Sopenharmony_ci *
24762306a36Sopenharmony_ci ******************************************************************************/
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ciacpi_status
25062306a36Sopenharmony_ciacpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
25162306a36Sopenharmony_ci{
25262306a36Sopenharmony_ci	acpi_status status;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	ACPI_FUNCTION_TRACE(ns_parse_table);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	/*
25762306a36Sopenharmony_ci	 * Executes the AML table as one large control method.
25862306a36Sopenharmony_ci	 * The point of this is to execute any module-level code in-place
25962306a36Sopenharmony_ci	 * as the table is parsed. Some AML code depends on this behavior.
26062306a36Sopenharmony_ci	 *
26162306a36Sopenharmony_ci	 * Note: This causes the table to only have a single-pass parse.
26262306a36Sopenharmony_ci	 * However, this is compatible with other ACPI implementations.
26362306a36Sopenharmony_ci	 */
26462306a36Sopenharmony_ci	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
26562306a36Sopenharmony_ci			      "%s: **** Start table execution pass\n",
26662306a36Sopenharmony_ci			      ACPI_GET_FUNCTION_NAME));
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	status = acpi_ns_execute_table(table_index, start_node);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	return_ACPI_STATUS(status);
27162306a36Sopenharmony_ci}
272