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 - 2018, 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 if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 151 walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 152 } 153 154 /* Invoke an internal method if necessary */ 155 156 if (info->obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) { 157 status = 158 info->obj_desc->method.dispatch.implementation(walk_state); 159 info->return_object = walk_state->return_desc; 160 161 /* Cleanup states */ 162 163 acpi_ds_scope_stack_clear(walk_state); 164 acpi_ps_cleanup_scope(&walk_state->parser_state); 165 acpi_ds_terminate_control_method(walk_state->method_desc, 166 walk_state); 167 acpi_ds_delete_walk_state(walk_state); 168 goto cleanup; 169 } 170 171 /* 172 * Start method evaluation with an implicit return of zero. 173 * This is done for Windows compatibility. 174 */ 175 if (acpi_gbl_enable_interpreter_slack) { 176 walk_state->implicit_return_obj = 177 acpi_ut_create_integer_object((u64) 0); 178 if (!walk_state->implicit_return_obj) { 179 status = AE_NO_MEMORY; 180 acpi_ds_delete_walk_state(walk_state); 181 goto cleanup; 182 } 183 } 184 185 /* Parse the AML */ 186 187 status = acpi_ps_parse_aml(walk_state); 188 189 /* walk_state was deleted by parse_aml */ 190 191 cleanup: 192 acpi_ps_delete_parse_tree(op); 193 194 /* Take away the extra reference that we gave the parameters above */ 195 196 acpi_ps_update_parameter_list(info, REF_DECREMENT); 197 198 /* Exit now if error above */ 199 200 if (ACPI_FAILURE(status)) { 201 return_ACPI_STATUS(status); 202 } 203 204 /* 205 * If the method has returned an object, signal this to the caller with 206 * a control exception code 207 */ 208 if (info->return_object) { 209 ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Method returned ObjDesc=%p\n", 210 info->return_object)); 211 ACPI_DUMP_STACK_ENTRY(info->return_object); 212 213 status = AE_CTRL_RETURN_VALUE; 214 } 215 216 return_ACPI_STATUS(status); 217 } 218 219 /******************************************************************************* 220 * 221 * FUNCTION: acpi_ps_execute_table 222 * 223 * PARAMETERS: info - Method info block, contains: 224 * node - Node to where the is entered into the 225 * namespace 226 * obj_desc - Pseudo method object describing the AML 227 * code of the entire table 228 * pass_number - Parse or execute pass 229 * 230 * RETURN: Status 231 * 232 * DESCRIPTION: Execute a table 233 * 234 ******************************************************************************/ 235 236 acpi_status acpi_ps_execute_table(struct acpi_evaluate_info *info) 237 { 238 acpi_status status; 239 union acpi_parse_object *op = NULL; 240 struct acpi_walk_state *walk_state = NULL; 241 242 ACPI_FUNCTION_TRACE(ps_execute_table); 243 244 /* Create and init a Root Node */ 245 246 op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); 247 if (!op) { 248 status = AE_NO_MEMORY; 249 goto cleanup; 250 } 251 252 /* Create and initialize a new walk state */ 253 254 walk_state = 255 acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL, 256 NULL, NULL); 257 if (!walk_state) { 258 status = AE_NO_MEMORY; 259 goto cleanup; 260 } 261 262 status = acpi_ds_init_aml_walk(walk_state, op, info->node, 263 info->obj_desc->method.aml_start, 264 info->obj_desc->method.aml_length, info, 265 info->pass_number); 266 if (ACPI_FAILURE(status)) { 267 goto cleanup; 268 } 269 270 if (info->obj_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL) { 271 walk_state->parse_flags |= ACPI_PARSE_MODULE_LEVEL; 272 } 273 274 /* Info->Node is the default location to load the table */ 275 276 if (info->node && info->node != acpi_gbl_root_node) { 277 status = 278 acpi_ds_scope_stack_push(info->node, ACPI_TYPE_METHOD, 279 walk_state); 280 if (ACPI_FAILURE(status)) { 281 goto cleanup; 282 } 283 } 284 285 /* 286 * Parse the AML, walk_state will be deleted by parse_aml 287 */ 288 acpi_ex_enter_interpreter(); 289 status = acpi_ps_parse_aml(walk_state); 290 acpi_ex_exit_interpreter(); 291 walk_state = NULL; 292 293 cleanup: 294 if (walk_state) { 295 acpi_ds_delete_walk_state(walk_state); 296 } 297 if (op) { 298 acpi_ps_delete_parse_tree(op); 299 } 300 return_ACPI_STATUS(status); 301 } 302 303 /******************************************************************************* 304 * 305 * FUNCTION: acpi_ps_update_parameter_list 306 * 307 * PARAMETERS: info - See struct acpi_evaluate_info 308 * (Used: parameter_type and Parameters) 309 * action - Add or Remove reference 310 * 311 * RETURN: Status 312 * 313 * DESCRIPTION: Update reference count on all method parameter objects 314 * 315 ******************************************************************************/ 316 317 static void 318 acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action) 319 { 320 u32 i; 321 322 if (info->parameters) { 323 324 /* Update reference count for each parameter */ 325 326 for (i = 0; info->parameters[i]; i++) { 327 328 /* Ignore errors, just do them all */ 329 330 (void)acpi_ut_update_object_reference(info-> 331 parameters[i], 332 action); 333 } 334 } 335 } 336