1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: psxface - Parser external interfaces 5 * 6 * Copyright (C) 2000 - 2023, Intel Corp. 7 * 8 *****************************************************************************/ 9 10 #include <acpi/acpi.h> 11 #include "accommon.h" 12 #include "acparser.h" 13 #include "acdispat.h" 14 #include "acinterp.h" 15 #include "actables.h" 16 #include "acnamesp.h" 17 18 #define _COMPONENT ACPI_PARSER 19 ACPI_MODULE_NAME("psxface") 20 21 /* Local Prototypes */ 22 static void 23 acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); 24 25 /******************************************************************************* 26 * 27 * FUNCTION: acpi_debug_trace 28 * 29 * PARAMETERS: method_name - Valid ACPI name string 30 * debug_level - Optional level mask. 0 to use default 31 * debug_layer - Optional layer mask. 0 to use default 32 * flags - bit 1: one shot(1) or persistent(0) 33 * 34 * RETURN: Status 35 * 36 * DESCRIPTION: External interface to enable debug tracing during control 37 * method execution 38 * 39 ******************************************************************************/ 40 41 acpi_status 42 acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags) 43 { 44 acpi_status status; 45 46 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); 47 if (ACPI_FAILURE(status)) { 48 return (status); 49 } 50 51 acpi_gbl_trace_method_name = name; 52 acpi_gbl_trace_flags = flags; 53 acpi_gbl_trace_dbg_level = debug_level; 54 acpi_gbl_trace_dbg_layer = debug_layer; 55 status = AE_OK; 56 57 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 58 return (status); 59 } 60 61 /******************************************************************************* 62 * 63 * FUNCTION: acpi_ps_execute_method 64 * 65 * PARAMETERS: info - Method info block, contains: 66 * node - Method Node to execute 67 * obj_desc - Method object 68 * parameters - List of parameters to pass to the method, 69 * terminated by NULL. Params itself may be 70 * NULL if no parameters are being passed. 71 * return_object - Where to put method's return value (if 72 * any). If NULL, no value is returned. 73 * parameter_type - Type of Parameter list 74 * return_object - Where to put method's return value (if 75 * any). If NULL, no value is returned. 76 * pass_number - Parse or execute pass 77 * 78 * RETURN: Status 79 * 80 * DESCRIPTION: Execute a control method 81 * 82 ******************************************************************************/ 83 84 acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) 85 { 86 acpi_status status; 87 union acpi_parse_object *op; 88 struct acpi_walk_state *walk_state; 89 90 ACPI_FUNCTION_TRACE(ps_execute_method); 91 92 /* Quick validation of DSDT header */ 93 94 acpi_tb_check_dsdt_header(); 95 96 /* Validate the Info and method Node */ 97 98 if (!info || !info->node) { 99 return_ACPI_STATUS(AE_NULL_ENTRY); 100 } 101 102 /* Init for new method, wait on concurrency semaphore */ 103 104 status = 105 acpi_ds_begin_method_execution(info->node, info->obj_desc, NULL); 106 if (ACPI_FAILURE(status)) { 107 return_ACPI_STATUS(status); 108 } 109 110 /* 111 * The caller "owns" the parameters, so give each one an extra reference 112 */ 113 acpi_ps_update_parameter_list(info, REF_INCREMENT); 114 115 /* 116 * Execute the method. Performs parse simultaneously 117 */ 118 ACPI_DEBUG_PRINT((ACPI_DB_PARSE, 119 "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n", 120 info->node->name.ascii, info->node, info->obj_desc)); 121 122 /* Create and init a Root Node */ 123 124 op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); 125 if (!op) { 126 status = AE_NO_MEMORY; 127 goto cleanup; 128 } 129 130 /* Create and initialize a new walk state */ 131 132 info->pass_number = ACPI_IMODE_EXECUTE; 133 walk_state = 134 acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, 135 NULL, NULL); 136 if (!walk_state) { 137 status = AE_NO_MEMORY; 138 goto cleanup; 139 } 140 141 status = acpi_ds_init_aml_walk(walk_state, op, info->node, 142 info->obj_desc->method.aml_start, 143 info->obj_desc->method.aml_length, info, 144 info->pass_number); 145 if (ACPI_FAILURE(status)) { 146 acpi_ds_delete_walk_state(walk_state); 147 goto cleanup; 148 } 149 150 walk_state->method_pathname = info->full_pathname; 151 walk_state->method_is_nested = FALSE; 152 153 if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 154 walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 155 } 156 157 /* Invoke an internal method if necessary */ 158 159 if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { 160 status = 161 info->obj_desc->method.dispatch.implementation(walk_state); 162 info->return_object = walk_state->return_desc; 163 164 /* Cleanup states */ 165 166 acpi_ds_scope_stack_clear(walk_state); 167 acpi_ps_cleanup_scope(&walk_state->parser_state); 168 acpi_ds_terminate_control_method(walk_state->method_desc, 169 walk_state); 170 acpi_ds_delete_walk_state(walk_state); 171 goto cleanup; 172 } 173 174 /* 175 * Start method evaluation with an implicit return of zero. 176 * This is done for Windows compatibility. 177 */ 178 if (acpi_gbl_enable_interpreter_slack) { 179 walk_state->implicit_return_obj = 180 acpi_ut_create_integer_object((u64) 0); 181 if (!walk_state->implicit_return_obj) { 182 status = AE_NO_MEMORY; 183 acpi_ds_delete_walk_state(walk_state); 184 goto cleanup; 185 } 186 } 187 188 /* Parse the AML */ 189 190 status = acpi_ps_parse_aml(walk_state); 191 192 /* walk_state was deleted by parse_aml */ 193 194 cleanup: 195 acpi_ps_delete_parse_tree(op); 196 197 /* Take away the extra reference that we gave the parameters above */ 198 199 acpi_ps_update_parameter_list(info, REF_DECREMENT); 200 201 /* Exit now if error above */ 202 203 if (ACPI_FAILURE(status)) { 204 return_ACPI_STATUS(status); 205 } 206 207 /* 208 * If the method has returned an object, signal this to the caller with 209 * a control exception code 210 */ 211 if (info->return_object) { 212 ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", 213 info->return_object)); 214 ACPI_DUMP_STACK_ENTRY(info->return_object); 215 216 status = AE_CTRL_RETURN_VALUE; 217 } 218 219 return_ACPI_STATUS(status); 220 } 221 222 /******************************************************************************* 223 * 224 * FUNCTION: acpi_ps_execute_table 225 * 226 * PARAMETERS: info - Method info block, contains: 227 * node - Node to where the is entered into the 228 * namespace 229 * obj_desc - Pseudo method object describing the AML 230 * code of the entire table 231 * pass_number - Parse or execute pass 232 * 233 * RETURN: Status 234 * 235 * DESCRIPTION: Execute a table 236 * 237 ******************************************************************************/ 238 239 acpi_status acpi_ps_execute_table(struct acpi_evaluate_info *info) 240 { 241 acpi_status status; 242 union acpi_parse_object *op = NULL; 243 struct acpi_walk_state *walk_state = NULL; 244 245 ACPI_FUNCTION_TRACE(ps_execute_table); 246 247 /* Create and init a Root Node */ 248 249 op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); 250 if (!op) { 251 status = AE_NO_MEMORY; 252 goto cleanup; 253 } 254 255 /* Create and initialize a new walk state */ 256 257 walk_state = 258 acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, 259 NULL, NULL); 260 if (!walk_state) { 261 status = AE_NO_MEMORY; 262 goto cleanup; 263 } 264 265 status = acpi_ds_init_aml_walk(walk_state, op, info->node, 266 info->obj_desc->method.aml_start, 267 info->obj_desc->method.aml_length, info, 268 info->pass_number); 269 if (ACPI_FAILURE(status)) { 270 goto cleanup; 271 } 272 273 walk_state->method_pathname = info->full_pathname; 274 walk_state->method_is_nested = FALSE; 275 276 if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 277 walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 278 } 279 280 /* Info->Node is the default location to load the table */ 281 282 if (info->node && info->node != acpi_gbl_root_node) { 283 status = 284 acpi_ds_scope_stack_push(info->node, ACPI_TYPE_METHOD, 285 walk_state); 286 if (ACPI_FAILURE(status)) { 287 goto cleanup; 288 } 289 } 290 291 /* 292 * Parse the AML, walk_state will be deleted by parse_aml 293 */ 294 acpi_ex_enter_interpreter(); 295 status = acpi_ps_parse_aml(walk_state); 296 acpi_ex_exit_interpreter(); 297 walk_state = NULL; 298 299 cleanup: 300 if (walk_state) { 301 acpi_ds_delete_walk_state(walk_state); 302 } 303 if (op) { 304 acpi_ps_delete_parse_tree(op); 305 } 306 return_ACPI_STATUS(status); 307 } 308 309 /******************************************************************************* 310 * 311 * FUNCTION: acpi_ps_update_parameter_list 312 * 313 * PARAMETERS: info - See struct acpi_evaluate_info 314 * (Used: parameter_type and Parameters) 315 * action - Add or Remove reference 316 * 317 * RETURN: Status 318 * 319 * DESCRIPTION: Update reference count on all method parameter objects 320 * 321 ******************************************************************************/ 322 323 static void 324 acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) 325 { 326 u32 i; 327 328 if (info->parameters) { 329 330 /* Update reference count for each parameter */ 331 332 for (i = 0; info->parameters[i]; i++) { 333 334 /* Ignore errors, just do them all */ 335 336 (void)acpi_ut_update_object_reference(info-> 337 parameters[i], 338 action); 339 } 340 } 341 } 342