xref: /openbmc/linux/drivers/acpi/acpica/nsparse.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
195857638SErik Schmauss // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
295b482a8SLen Brown /******************************************************************************
395b482a8SLen Brown  *
495b482a8SLen Brown  * Module Name: nsparse - namespace interface to AML parser
595b482a8SLen Brown  *
6*612c2932SBob Moore  * Copyright (C) 2000 - 2023, Intel Corp.
795b482a8SLen Brown  *
895857638SErik Schmauss  *****************************************************************************/
995b482a8SLen Brown 
1095b482a8SLen Brown #include <acpi/acpi.h>
11e2f7a777SLen Brown #include "accommon.h"
12e2f7a777SLen Brown #include "acnamesp.h"
13e2f7a777SLen Brown #include "acparser.h"
14e2f7a777SLen Brown #include "acdispat.h"
15e2f7a777SLen Brown #include "actables.h"
1674f51b80SLv Zheng #include "acinterp.h"
1795b482a8SLen Brown 
1895b482a8SLen Brown #define _COMPONENT          ACPI_NAMESPACE
1995b482a8SLen Brown ACPI_MODULE_NAME("nsparse")
2095b482a8SLen Brown 
2195b482a8SLen Brown /*******************************************************************************
2295b482a8SLen Brown  *
23de56ba95SLv Zheng  * FUNCTION:    ns_execute_table
24de56ba95SLv Zheng  *
25de56ba95SLv Zheng  * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
26de56ba95SLv Zheng  *              start_node      - Where to enter the table into the namespace
27de56ba95SLv Zheng  *
28de56ba95SLv Zheng  * RETURN:      Status
29de56ba95SLv Zheng  *
30a406dea8SBob Moore  * DESCRIPTION: Load ACPI/AML table by executing the entire table as a single
31a406dea8SBob Moore  *              large control method.
32a406dea8SBob Moore  *
33a406dea8SBob Moore  * NOTE: The point of this is to execute any module-level code in-place
34a406dea8SBob Moore  * as the table is parsed. Some AML code depends on this behavior.
35a406dea8SBob Moore  *
36a406dea8SBob Moore  * It is a run-time option at this time, but will eventually become
37a406dea8SBob Moore  * the default.
38a406dea8SBob Moore  *
39a406dea8SBob Moore  * Note: This causes the table to only have a single-pass parse.
40a406dea8SBob Moore  * However, this is compatible with other ACPI implementations.
41de56ba95SLv Zheng  *
42de56ba95SLv Zheng  ******************************************************************************/
43de56ba95SLv Zheng acpi_status
acpi_ns_execute_table(u32 table_index,struct acpi_namespace_node * start_node)44de56ba95SLv Zheng acpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
45de56ba95SLv Zheng {
46de56ba95SLv Zheng 	acpi_status status;
47de56ba95SLv Zheng 	struct acpi_table_header *table;
48de56ba95SLv Zheng 	acpi_owner_id owner_id;
49de56ba95SLv Zheng 	struct acpi_evaluate_info *info = NULL;
50de56ba95SLv Zheng 	u32 aml_length;
51de56ba95SLv Zheng 	u8 *aml_start;
52de56ba95SLv Zheng 	union acpi_operand_object *method_obj = NULL;
53de56ba95SLv Zheng 
54de56ba95SLv Zheng 	ACPI_FUNCTION_TRACE(ns_execute_table);
55de56ba95SLv Zheng 
56de56ba95SLv Zheng 	status = acpi_get_table_by_index(table_index, &table);
57de56ba95SLv Zheng 	if (ACPI_FAILURE(status)) {
58de56ba95SLv Zheng 		return_ACPI_STATUS(status);
59de56ba95SLv Zheng 	}
60de56ba95SLv Zheng 
61de56ba95SLv Zheng 	/* Table must consist of at least a complete header */
62de56ba95SLv Zheng 
63de56ba95SLv Zheng 	if (table->length < sizeof(struct acpi_table_header)) {
64de56ba95SLv Zheng 		return_ACPI_STATUS(AE_BAD_HEADER);
65de56ba95SLv Zheng 	}
66de56ba95SLv Zheng 
67de56ba95SLv Zheng 	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
68de56ba95SLv Zheng 	aml_length = table->length - sizeof(struct acpi_table_header);
69de56ba95SLv Zheng 
70de56ba95SLv Zheng 	status = acpi_tb_get_owner_id(table_index, &owner_id);
71de56ba95SLv Zheng 	if (ACPI_FAILURE(status)) {
72de56ba95SLv Zheng 		return_ACPI_STATUS(status);
73de56ba95SLv Zheng 	}
74de56ba95SLv Zheng 
75de56ba95SLv Zheng 	/* Create, initialize, and link a new temporary method object */
76de56ba95SLv Zheng 
77de56ba95SLv Zheng 	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
78de56ba95SLv Zheng 	if (!method_obj) {
79de56ba95SLv Zheng 		return_ACPI_STATUS(AE_NO_MEMORY);
80de56ba95SLv Zheng 	}
81de56ba95SLv Zheng 
82de56ba95SLv Zheng 	/* Allocate the evaluation information block */
83de56ba95SLv Zheng 
84de56ba95SLv Zheng 	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
85de56ba95SLv Zheng 	if (!info) {
86de56ba95SLv Zheng 		status = AE_NO_MEMORY;
87de56ba95SLv Zheng 		goto cleanup;
88de56ba95SLv Zheng 	}
89de56ba95SLv Zheng 
901ef63231SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
911ef63231SBob Moore 			      "%s: Create table pseudo-method for [%4.4s] @%p, method %p\n",
921ef63231SBob Moore 			      ACPI_GET_FUNCTION_NAME, table->signature, table,
931ef63231SBob Moore 			      method_obj));
94de56ba95SLv Zheng 
95de56ba95SLv Zheng 	method_obj->method.aml_start = aml_start;
96de56ba95SLv Zheng 	method_obj->method.aml_length = aml_length;
97de56ba95SLv Zheng 	method_obj->method.owner_id = owner_id;
98de56ba95SLv Zheng 	method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
99de56ba95SLv Zheng 
100de56ba95SLv Zheng 	info->pass_number = ACPI_IMODE_EXECUTE;
101de56ba95SLv Zheng 	info->node = start_node;
102de56ba95SLv Zheng 	info->obj_desc = method_obj;
103de56ba95SLv Zheng 	info->node_flags = info->node->flags;
104de56ba95SLv Zheng 	info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE);
105de56ba95SLv Zheng 	if (!info->full_pathname) {
106de56ba95SLv Zheng 		status = AE_NO_MEMORY;
107de56ba95SLv Zheng 		goto cleanup;
108de56ba95SLv Zheng 	}
109de56ba95SLv Zheng 
1104c1379d7SBob Moore 	/* Optional object evaluation log */
1114c1379d7SBob Moore 
1124c1379d7SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
1134c1379d7SBob Moore 			      "%-26s:  (Definition Block level)\n",
1144c1379d7SBob Moore 			      "Module-level evaluation"));
1154c1379d7SBob Moore 
116de56ba95SLv Zheng 	status = acpi_ps_execute_table(info);
117de56ba95SLv Zheng 
1184c1379d7SBob Moore 	/* Optional object evaluation log */
1194c1379d7SBob Moore 
1204c1379d7SBob Moore 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
1214c1379d7SBob Moore 			      "%-26s:  (Definition Block level)\n",
1224c1379d7SBob Moore 			      "Module-level complete"));
1234c1379d7SBob Moore 
124de56ba95SLv Zheng cleanup:
125de56ba95SLv Zheng 	if (info) {
126de56ba95SLv Zheng 		ACPI_FREE(info->full_pathname);
127de56ba95SLv Zheng 		info->full_pathname = NULL;
128de56ba95SLv Zheng 	}
129de56ba95SLv Zheng 	ACPI_FREE(info);
130de56ba95SLv Zheng 	acpi_ut_remove_reference(method_obj);
131de56ba95SLv Zheng 	return_ACPI_STATUS(status);
132de56ba95SLv Zheng }
133de56ba95SLv Zheng 
134de56ba95SLv Zheng /*******************************************************************************
135de56ba95SLv Zheng  *
13695b482a8SLen Brown  * FUNCTION:    ns_one_complete_parse
13795b482a8SLen Brown  *
13895b482a8SLen Brown  * PARAMETERS:  pass_number             - 1 or 2
13995b482a8SLen Brown  *              table_desc              - The table to be parsed.
14095b482a8SLen Brown  *
14195b482a8SLen Brown  * RETURN:      Status
14295b482a8SLen Brown  *
14395b482a8SLen Brown  * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
14495b482a8SLen Brown  *
14595b482a8SLen Brown  ******************************************************************************/
146de56ba95SLv Zheng 
14795b482a8SLen Brown acpi_status
acpi_ns_one_complete_parse(u32 pass_number,u32 table_index,struct acpi_namespace_node * start_node)14895b482a8SLen Brown acpi_ns_one_complete_parse(u32 pass_number,
14995b482a8SLen Brown 			   u32 table_index,
15095b482a8SLen Brown 			   struct acpi_namespace_node *start_node)
15195b482a8SLen Brown {
15295b482a8SLen Brown 	union acpi_parse_object *parse_root;
15395b482a8SLen Brown 	acpi_status status;
15495b482a8SLen Brown 	u32 aml_length;
15595b482a8SLen Brown 	u8 *aml_start;
15695b482a8SLen Brown 	struct acpi_walk_state *walk_state;
15795b482a8SLen Brown 	struct acpi_table_header *table;
15895b482a8SLen Brown 	acpi_owner_id owner_id;
15995b482a8SLen Brown 
16095b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_one_complete_parse);
16195b482a8SLen Brown 
16262eb935bSLv Zheng 	status = acpi_get_table_by_index(table_index, &table);
16362eb935bSLv Zheng 	if (ACPI_FAILURE(status)) {
16462eb935bSLv Zheng 		return_ACPI_STATUS(status);
16562eb935bSLv Zheng 	}
16662eb935bSLv Zheng 
16762eb935bSLv Zheng 	/* Table must consist of at least a complete header */
16862eb935bSLv Zheng 
16962eb935bSLv Zheng 	if (table->length < sizeof(struct acpi_table_header)) {
17062eb935bSLv Zheng 		return_ACPI_STATUS(AE_BAD_HEADER);
17162eb935bSLv Zheng 	}
17262eb935bSLv Zheng 
17362eb935bSLv Zheng 	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
17462eb935bSLv Zheng 	aml_length = table->length - sizeof(struct acpi_table_header);
17562eb935bSLv Zheng 
17695b482a8SLen Brown 	status = acpi_tb_get_owner_id(table_index, &owner_id);
17795b482a8SLen Brown 	if (ACPI_FAILURE(status)) {
17895b482a8SLen Brown 		return_ACPI_STATUS(status);
17995b482a8SLen Brown 	}
18095b482a8SLen Brown 
18195b482a8SLen Brown 	/* Create and init a Root Node */
18295b482a8SLen Brown 
18362eb935bSLv Zheng 	parse_root = acpi_ps_create_scope_op(aml_start);
18495b482a8SLen Brown 	if (!parse_root) {
18595b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
18695b482a8SLen Brown 	}
18795b482a8SLen Brown 
18895b482a8SLen Brown 	/* Create and initialize a new walk state */
18995b482a8SLen Brown 
19095b482a8SLen Brown 	walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
19195b482a8SLen Brown 	if (!walk_state) {
19295b482a8SLen Brown 		acpi_ps_free_op(parse_root);
19395b482a8SLen Brown 		return_ACPI_STATUS(AE_NO_MEMORY);
19495b482a8SLen Brown 	}
19595b482a8SLen Brown 
19695b482a8SLen Brown 	status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
19795b482a8SLen Brown 				       aml_start, aml_length, NULL,
19895b482a8SLen Brown 				       (u8)pass_number);
19962eb935bSLv Zheng 	if (ACPI_FAILURE(status)) {
20062eb935bSLv Zheng 		acpi_ds_delete_walk_state(walk_state);
20162eb935bSLv Zheng 		goto cleanup;
20295b482a8SLen Brown 	}
20395b482a8SLen Brown 
204fe536995SBob Moore 	/* Found OSDT table, enable the namespace override feature */
205fe536995SBob Moore 
2065599fb69SBob Moore 	if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_OSDT) &&
207fe536995SBob Moore 	    pass_number == ACPI_IMODE_LOAD_PASS1) {
208fe536995SBob Moore 		walk_state->namespace_override = TRUE;
209fe536995SBob Moore 	}
210fe536995SBob Moore 
21195b482a8SLen Brown 	/* start_node is the default location to load the table */
21295b482a8SLen Brown 
21395b482a8SLen Brown 	if (start_node && start_node != acpi_gbl_root_node) {
21495b482a8SLen Brown 		status =
21595b482a8SLen Brown 		    acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
21695b482a8SLen Brown 					     walk_state);
21795b482a8SLen Brown 		if (ACPI_FAILURE(status)) {
21895b482a8SLen Brown 			acpi_ds_delete_walk_state(walk_state);
21995b482a8SLen Brown 			goto cleanup;
22095b482a8SLen Brown 		}
22195b482a8SLen Brown 	}
22295b482a8SLen Brown 
22395b482a8SLen Brown 	/* Parse the AML */
22495b482a8SLen Brown 
2251fad8738SBob Moore 	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
2261fad8738SBob Moore 			  "*PARSE* pass %u parse\n", pass_number));
22774f51b80SLv Zheng 	acpi_ex_enter_interpreter();
22895b482a8SLen Brown 	status = acpi_ps_parse_aml(walk_state);
22974f51b80SLv Zheng 	acpi_ex_exit_interpreter();
23095b482a8SLen Brown 
23195b482a8SLen Brown cleanup:
23295b482a8SLen Brown 	acpi_ps_delete_parse_tree(parse_root);
23395b482a8SLen Brown 	return_ACPI_STATUS(status);
23495b482a8SLen Brown }
23595b482a8SLen Brown 
23695b482a8SLen Brown /*******************************************************************************
23795b482a8SLen Brown  *
23895b482a8SLen Brown  * FUNCTION:    acpi_ns_parse_table
23995b482a8SLen Brown  *
24095b482a8SLen Brown  * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
24195b482a8SLen Brown  *              start_node      - Where to enter the table into the namespace
24295b482a8SLen Brown  *
24395b482a8SLen Brown  * RETURN:      Status
24495b482a8SLen Brown  *
24595b482a8SLen Brown  * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
24695b482a8SLen Brown  *
24795b482a8SLen Brown  ******************************************************************************/
24895b482a8SLen Brown 
24995b482a8SLen Brown acpi_status
acpi_ns_parse_table(u32 table_index,struct acpi_namespace_node * start_node)25095b482a8SLen Brown acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
25195b482a8SLen Brown {
25295b482a8SLen Brown 	acpi_status status;
25395b482a8SLen Brown 
25495b482a8SLen Brown 	ACPI_FUNCTION_TRACE(ns_parse_table);
25595b482a8SLen Brown 
256a406dea8SBob Moore 	/*
257aa342261SErik Schmauss 	 * Executes the AML table as one large control method.
258a406dea8SBob Moore 	 * The point of this is to execute any module-level code in-place
259a406dea8SBob Moore 	 * as the table is parsed. Some AML code depends on this behavior.
260a406dea8SBob Moore 	 *
261a406dea8SBob Moore 	 * Note: This causes the table to only have a single-pass parse.
262a406dea8SBob Moore 	 * However, this is compatible with other ACPI implementations.
263a406dea8SBob Moore 	 */
2645a8361f7SSchmauss, Erik 	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
2655a8361f7SSchmauss, Erik 			      "%s: **** Start table execution pass\n",
2665a8361f7SSchmauss, Erik 			      ACPI_GET_FUNCTION_NAME));
267de56ba95SLv Zheng 
268de56ba95SLv Zheng 	status = acpi_ns_execute_table(table_index, start_node);
26995b482a8SLen Brown 
27095b482a8SLen Brown 	return_ACPI_STATUS(status);
27195b482a8SLen Brown }
272