brintos

brintos / linux-shallow public Read only

0
0
Text · 9.3 KiB · 80c69af Raw
373 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: dscontrol - Support for execution control opcodes -5 *                          if/else/while/return6 *7 * Copyright (C) 2000 - 2023, Intel Corp.8 *9 *****************************************************************************/10 11#include <acpi/acpi.h>12#include "accommon.h"13#include "amlcode.h"14#include "acdispat.h"15#include "acinterp.h"16#include "acdebug.h"17 18#define _COMPONENT          ACPI_DISPATCHER19ACPI_MODULE_NAME("dscontrol")20 21/*******************************************************************************22 *23 * FUNCTION:    acpi_ds_exec_begin_control_op24 *25 * PARAMETERS:  walk_list       - The list that owns the walk stack26 *              op              - The control Op27 *28 * RETURN:      Status29 *30 * DESCRIPTION: Handles all control ops encountered during control method31 *              execution.32 *33 ******************************************************************************/34acpi_status35acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,36			      union acpi_parse_object *op)37{38	acpi_status status = AE_OK;39	union acpi_generic_state *control_state;40 41	ACPI_FUNCTION_NAME(ds_exec_begin_control_op);42 43	ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",44			  op, op->common.aml_opcode, walk_state));45 46	switch (op->common.aml_opcode) {47	case AML_WHILE_OP:48		/*49		 * If this is an additional iteration of a while loop, continue.50		 * There is no need to allocate a new control state.51		 */52		if (walk_state->control_state) {53			if (walk_state->control_state->control.54			    aml_predicate_start ==55			    (walk_state->parser_state.aml - 1)) {56 57				/* Reset the state to start-of-loop */58 59				walk_state->control_state->common.state =60				    ACPI_CONTROL_CONDITIONAL_EXECUTING;61				break;62			}63		}64 65		ACPI_FALLTHROUGH;66 67	case AML_IF_OP:68		/*69		 * IF/WHILE: Create a new control state to manage these70		 * constructs. We need to manage these as a stack, in order71		 * to handle nesting.72		 */73		control_state = acpi_ut_create_control_state();74		if (!control_state) {75			status = AE_NO_MEMORY;76			break;77		}78		/*79		 * Save a pointer to the predicate for multiple executions80		 * of a loop81		 */82		control_state->control.aml_predicate_start =83		    walk_state->parser_state.aml - 1;84		control_state->control.package_end =85		    walk_state->parser_state.pkg_end;86		control_state->control.opcode = op->common.aml_opcode;87		control_state->control.loop_timeout = acpi_os_get_timer() +88		    ((u64)acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);89 90		/* Push the control state on this walk's control stack */91 92		acpi_ut_push_generic_state(&walk_state->control_state,93					   control_state);94		break;95 96	case AML_ELSE_OP:97 98		/* Predicate is in the state object */99		/* If predicate is true, the IF was executed, ignore ELSE part */100 101		if (walk_state->last_predicate) {102			status = AE_CTRL_TRUE;103		}104 105		break;106 107	case AML_RETURN_OP:108 109		break;110 111	default:112 113		break;114	}115 116	return (status);117}118 119/*******************************************************************************120 *121 * FUNCTION:    acpi_ds_exec_end_control_op122 *123 * PARAMETERS:  walk_list       - The list that owns the walk stack124 *              op              - The control Op125 *126 * RETURN:      Status127 *128 * DESCRIPTION: Handles all control ops encountered during control method129 *              execution.130 *131 ******************************************************************************/132 133acpi_status134acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,135			    union acpi_parse_object *op)136{137	acpi_status status = AE_OK;138	union acpi_generic_state *control_state;139 140	ACPI_FUNCTION_NAME(ds_exec_end_control_op);141 142	switch (op->common.aml_opcode) {143	case AML_IF_OP:144 145		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));146 147		/*148		 * Save the result of the predicate in case there is an149		 * ELSE to come150		 */151		walk_state->last_predicate =152		    (u8)walk_state->control_state->common.value;153 154		/*155		 * Pop the control state that was created at the start156		 * of the IF and free it157		 */158		control_state =159		    acpi_ut_pop_generic_state(&walk_state->control_state);160		acpi_ut_delete_generic_state(control_state);161		break;162 163	case AML_ELSE_OP:164 165		break;166 167	case AML_WHILE_OP:168 169		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));170 171		control_state = walk_state->control_state;172		if (control_state->common.value) {173 174			/* Predicate was true, the body of the loop was just executed */175 176			/*177			 * This infinite loop detection mechanism allows the interpreter178			 * to escape possibly infinite loops. This can occur in poorly179			 * written AML when the hardware does not respond within a while180			 * loop and the loop does not implement a timeout.181			 */182			if (ACPI_TIME_AFTER(acpi_os_get_timer(),183					    control_state->control.184					    loop_timeout)) {185				status = AE_AML_LOOP_TIMEOUT;186				break;187			}188 189			/*190			 * Go back and evaluate the predicate and maybe execute the loop191			 * another time192			 */193			status = AE_CTRL_PENDING;194			walk_state->aml_last_while =195			    control_state->control.aml_predicate_start;196			break;197		}198 199		/* Predicate was false, terminate this while loop */200 201		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,202				  "[WHILE_OP] termination! Op=%p\n", op));203 204		/* Pop this control state and free it */205 206		control_state =207		    acpi_ut_pop_generic_state(&walk_state->control_state);208		acpi_ut_delete_generic_state(control_state);209		break;210 211	case AML_RETURN_OP:212 213		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,214				  "[RETURN_OP] Op=%p Arg=%p\n", op,215				  op->common.value.arg));216 217		/*218		 * One optional operand -- the return value219		 * It can be either an immediate operand or a result that220		 * has been bubbled up the tree221		 */222		if (op->common.value.arg) {223 224			/* Since we have a real Return(), delete any implicit return */225 226			acpi_ds_clear_implicit_return(walk_state);227 228			/* Return statement has an immediate operand */229 230			status =231			    acpi_ds_create_operands(walk_state,232						    op->common.value.arg);233			if (ACPI_FAILURE(status)) {234				return (status);235			}236 237			/*238			 * If value being returned is a Reference (such as239			 * an arg or local), resolve it now because it may240			 * cease to exist at the end of the method.241			 */242			status =243			    acpi_ex_resolve_to_value(&walk_state->operands[0],244						     walk_state);245			if (ACPI_FAILURE(status)) {246				return (status);247			}248 249			/*250			 * Get the return value and save as the last result251			 * value. This is the only place where walk_state->return_desc252			 * is set to anything other than zero!253			 */254			walk_state->return_desc = walk_state->operands[0];255		} else if (walk_state->result_count) {256 257			/* Since we have a real Return(), delete any implicit return */258 259			acpi_ds_clear_implicit_return(walk_state);260 261			/*262			 * The return value has come from a previous calculation.263			 *264			 * If value being returned is a Reference (such as265			 * an arg or local), resolve it now because it may266			 * cease to exist at the end of the method.267			 *268			 * Allow references created by the Index operator to return269			 * unchanged.270			 */271			if ((ACPI_GET_DESCRIPTOR_TYPE272			     (walk_state->results->results.obj_desc[0]) ==273			     ACPI_DESC_TYPE_OPERAND)274			    && ((walk_state->results->results.obj_desc[0])->275				common.type == ACPI_TYPE_LOCAL_REFERENCE)276			    && ((walk_state->results->results.obj_desc[0])->277				reference.class != ACPI_REFCLASS_INDEX)) {278				status =279				    acpi_ex_resolve_to_value(&walk_state->280							     results->results.281							     obj_desc[0],282							     walk_state);283				if (ACPI_FAILURE(status)) {284					return (status);285				}286			}287 288			walk_state->return_desc =289			    walk_state->results->results.obj_desc[0];290		} else {291			/* No return operand */292 293			if (walk_state->num_operands) {294				acpi_ut_remove_reference(walk_state->295							 operands[0]);296			}297 298			walk_state->operands[0] = NULL;299			walk_state->num_operands = 0;300			walk_state->return_desc = NULL;301		}302 303		ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,304				  "Completed RETURN_OP State=%p, RetVal=%p\n",305				  walk_state, walk_state->return_desc));306 307		/* End the control method execution right now */308 309		status = AE_CTRL_TERMINATE;310		break;311 312	case AML_NOOP_OP:313 314		/* Just do nothing! */315 316		break;317 318	case AML_BREAKPOINT_OP:319 320		acpi_db_signal_break_point(walk_state);321 322		/* Call to the OSL in case OS wants a piece of the action */323 324		status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,325					"Executed AML Breakpoint opcode");326		break;327 328	case AML_BREAK_OP:329	case AML_CONTINUE_OP:	/* ACPI 2.0 */330 331		/* Pop and delete control states until we find a while */332 333		while (walk_state->control_state &&334		       (walk_state->control_state->control.opcode !=335			AML_WHILE_OP)) {336			control_state =337			    acpi_ut_pop_generic_state(&walk_state->338						      control_state);339			acpi_ut_delete_generic_state(control_state);340		}341 342		/* No while found? */343 344		if (!walk_state->control_state) {345			return (AE_AML_NO_WHILE);346		}347 348		/* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */349 350		walk_state->aml_last_while =351		    walk_state->control_state->control.package_end;352 353		/* Return status depending on opcode */354 355		if (op->common.aml_opcode == AML_BREAK_OP) {356			status = AE_CTRL_BREAK;357		} else {358			status = AE_CTRL_CONTINUE;359		}360		break;361 362	default:363 364		ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",365			    op->common.aml_opcode, op));366 367		status = AE_AML_BAD_OPCODE;368		break;369	}370 371	return (status);372}373