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 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 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 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