1  // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2  /******************************************************************************
3   *
4   * Module Name: nsparse - namespace interface to AML parser
5   *
6   * Copyright (C) 2000 - 2023, Intel Corp.
7   *
8   *****************************************************************************/
9  
10  #include <acpi/acpi.h>
11  #include "accommon.h"
12  #include "acnamesp.h"
13  #include "acparser.h"
14  #include "acdispat.h"
15  #include "actables.h"
16  #include "acinterp.h"
17  
18  #define _COMPONENT          ACPI_NAMESPACE
19  ACPI_MODULE_NAME("nsparse")
20  
21  /*******************************************************************************
22   *
23   * FUNCTION:    ns_execute_table
24   *
25   * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
26   *              start_node      - Where to enter the table into the namespace
27   *
28   * RETURN:      Status
29   *
30   * DESCRIPTION: Load ACPI/AML table by executing the entire table as a single
31   *              large control method.
32   *
33   * NOTE: The point of this is to execute any module-level code in-place
34   * as the table is parsed. Some AML code depends on this behavior.
35   *
36   * It is a run-time option at this time, but will eventually become
37   * the default.
38   *
39   * Note: This causes the table to only have a single-pass parse.
40   * However, this is compatible with other ACPI implementations.
41   *
42   ******************************************************************************/
43  acpi_status
acpi_ns_execute_table(u32 table_index,struct acpi_namespace_node * start_node)44  acpi_ns_execute_table(u32 table_index, struct acpi_namespace_node *start_node)
45  {
46  	acpi_status status;
47  	struct acpi_table_header *table;
48  	acpi_owner_id owner_id;
49  	struct acpi_evaluate_info *info = NULL;
50  	u32 aml_length;
51  	u8 *aml_start;
52  	union acpi_operand_object *method_obj = NULL;
53  
54  	ACPI_FUNCTION_TRACE(ns_execute_table);
55  
56  	status = acpi_get_table_by_index(table_index, &table);
57  	if (ACPI_FAILURE(status)) {
58  		return_ACPI_STATUS(status);
59  	}
60  
61  	/* Table must consist of at least a complete header */
62  
63  	if (table->length < sizeof(struct acpi_table_header)) {
64  		return_ACPI_STATUS(AE_BAD_HEADER);
65  	}
66  
67  	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
68  	aml_length = table->length - sizeof(struct acpi_table_header);
69  
70  	status = acpi_tb_get_owner_id(table_index, &owner_id);
71  	if (ACPI_FAILURE(status)) {
72  		return_ACPI_STATUS(status);
73  	}
74  
75  	/* Create, initialize, and link a new temporary method object */
76  
77  	method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
78  	if (!method_obj) {
79  		return_ACPI_STATUS(AE_NO_MEMORY);
80  	}
81  
82  	/* Allocate the evaluation information block */
83  
84  	info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
85  	if (!info) {
86  		status = AE_NO_MEMORY;
87  		goto cleanup;
88  	}
89  
90  	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
91  			      "%s: Create table pseudo-method for [%4.4s] @%p, method %p\n",
92  			      ACPI_GET_FUNCTION_NAME, table->signature, table,
93  			      method_obj));
94  
95  	method_obj->method.aml_start = aml_start;
96  	method_obj->method.aml_length = aml_length;
97  	method_obj->method.owner_id = owner_id;
98  	method_obj->method.info_flags |= ACPI_METHOD_MODULE_LEVEL;
99  
100  	info->pass_number = ACPI_IMODE_EXECUTE;
101  	info->node = start_node;
102  	info->obj_desc = method_obj;
103  	info->node_flags = info->node->flags;
104  	info->full_pathname = acpi_ns_get_normalized_pathname(info->node, TRUE);
105  	if (!info->full_pathname) {
106  		status = AE_NO_MEMORY;
107  		goto cleanup;
108  	}
109  
110  	/* Optional object evaluation log */
111  
112  	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
113  			      "%-26s:  (Definition Block level)\n",
114  			      "Module-level evaluation"));
115  
116  	status = acpi_ps_execute_table(info);
117  
118  	/* Optional object evaluation log */
119  
120  	ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
121  			      "%-26s:  (Definition Block level)\n",
122  			      "Module-level complete"));
123  
124  cleanup:
125  	if (info) {
126  		ACPI_FREE(info->full_pathname);
127  		info->full_pathname = NULL;
128  	}
129  	ACPI_FREE(info);
130  	acpi_ut_remove_reference(method_obj);
131  	return_ACPI_STATUS(status);
132  }
133  
134  /*******************************************************************************
135   *
136   * FUNCTION:    ns_one_complete_parse
137   *
138   * PARAMETERS:  pass_number             - 1 or 2
139   *              table_desc              - The table to be parsed.
140   *
141   * RETURN:      Status
142   *
143   * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
144   *
145   ******************************************************************************/
146  
147  acpi_status
acpi_ns_one_complete_parse(u32 pass_number,u32 table_index,struct acpi_namespace_node * start_node)148  acpi_ns_one_complete_parse(u32 pass_number,
149  			   u32 table_index,
150  			   struct acpi_namespace_node *start_node)
151  {
152  	union acpi_parse_object *parse_root;
153  	acpi_status status;
154  	u32 aml_length;
155  	u8 *aml_start;
156  	struct acpi_walk_state *walk_state;
157  	struct acpi_table_header *table;
158  	acpi_owner_id owner_id;
159  
160  	ACPI_FUNCTION_TRACE(ns_one_complete_parse);
161  
162  	status = acpi_get_table_by_index(table_index, &table);
163  	if (ACPI_FAILURE(status)) {
164  		return_ACPI_STATUS(status);
165  	}
166  
167  	/* Table must consist of at least a complete header */
168  
169  	if (table->length < sizeof(struct acpi_table_header)) {
170  		return_ACPI_STATUS(AE_BAD_HEADER);
171  	}
172  
173  	aml_start = (u8 *)table + sizeof(struct acpi_table_header);
174  	aml_length = table->length - sizeof(struct acpi_table_header);
175  
176  	status = acpi_tb_get_owner_id(table_index, &owner_id);
177  	if (ACPI_FAILURE(status)) {
178  		return_ACPI_STATUS(status);
179  	}
180  
181  	/* Create and init a Root Node */
182  
183  	parse_root = acpi_ps_create_scope_op(aml_start);
184  	if (!parse_root) {
185  		return_ACPI_STATUS(AE_NO_MEMORY);
186  	}
187  
188  	/* Create and initialize a new walk state */
189  
190  	walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
191  	if (!walk_state) {
192  		acpi_ps_free_op(parse_root);
193  		return_ACPI_STATUS(AE_NO_MEMORY);
194  	}
195  
196  	status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
197  				       aml_start, aml_length, NULL,
198  				       (u8)pass_number);
199  	if (ACPI_FAILURE(status)) {
200  		acpi_ds_delete_walk_state(walk_state);
201  		goto cleanup;
202  	}
203  
204  	/* Found OSDT table, enable the namespace override feature */
205  
206  	if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_OSDT) &&
207  	    pass_number == ACPI_IMODE_LOAD_PASS1) {
208  		walk_state->namespace_override = TRUE;
209  	}
210  
211  	/* start_node is the default location to load the table */
212  
213  	if (start_node && start_node != acpi_gbl_root_node) {
214  		status =
215  		    acpi_ds_scope_stack_push(start_node, ACPI_TYPE_METHOD,
216  					     walk_state);
217  		if (ACPI_FAILURE(status)) {
218  			acpi_ds_delete_walk_state(walk_state);
219  			goto cleanup;
220  		}
221  	}
222  
223  	/* Parse the AML */
224  
225  	ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
226  			  "*PARSE* pass %u parse\n", pass_number));
227  	acpi_ex_enter_interpreter();
228  	status = acpi_ps_parse_aml(walk_state);
229  	acpi_ex_exit_interpreter();
230  
231  cleanup:
232  	acpi_ps_delete_parse_tree(parse_root);
233  	return_ACPI_STATUS(status);
234  }
235  
236  /*******************************************************************************
237   *
238   * FUNCTION:    acpi_ns_parse_table
239   *
240   * PARAMETERS:  table_desc      - An ACPI table descriptor for table to parse
241   *              start_node      - Where to enter the table into the namespace
242   *
243   * RETURN:      Status
244   *
245   * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
246   *
247   ******************************************************************************/
248  
249  acpi_status
acpi_ns_parse_table(u32 table_index,struct acpi_namespace_node * start_node)250  acpi_ns_parse_table(u32 table_index, struct acpi_namespace_node *start_node)
251  {
252  	acpi_status status;
253  
254  	ACPI_FUNCTION_TRACE(ns_parse_table);
255  
256  	/*
257  	 * Executes the AML table as one large control method.
258  	 * The point of this is to execute any module-level code in-place
259  	 * as the table is parsed. Some AML code depends on this behavior.
260  	 *
261  	 * Note: This causes the table to only have a single-pass parse.
262  	 * However, this is compatible with other ACPI implementations.
263  	 */
264  	ACPI_DEBUG_PRINT_RAW((ACPI_DB_PARSE,
265  			      "%s: **** Start table execution pass\n",
266  			      ACPI_GET_FUNCTION_NAME));
267  
268  	status = acpi_ns_execute_table(table_index, start_node);
269  
270  	return_ACPI_STATUS(status);
271  }
272