/******************************************************************************1*2* Module Name: dscontrol - Support for execution control opcodes -3* if/else/while/return4*5*****************************************************************************/67/*8* Copyright (C) 2000 - 2011, Intel Corp.9* All rights reserved.10*11* Redistribution and use in source and binary forms, with or without12* modification, are permitted provided that the following conditions13* are met:14* 1. Redistributions of source code must retain the above copyright15* notice, this list of conditions, and the following disclaimer,16* without modification.17* 2. Redistributions in binary form must reproduce at minimum a disclaimer18* substantially similar to the "NO WARRANTY" disclaimer below19* ("Disclaimer") and any redistribution must be conditioned upon20* including a substantially similar Disclaimer requirement for further21* binary redistribution.22* 3. Neither the names of the above-listed copyright holders nor the names23* of any contributors may be used to endorse or promote products derived24* from this software without specific prior written permission.25*26* Alternatively, this software may be distributed under the terms of the27* GNU General Public License ("GPL") version 2 as published by the Free28* Software Foundation.29*30* NO WARRANTY31* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS32* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT33* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR34* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT35* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL36* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS37* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)38* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,39* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING40* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE41* POSSIBILITY OF SUCH DAMAGES.42*/4344#include <acpi/acpi.h>45#include "accommon.h"46#include "amlcode.h"47#include "acdispat.h"48#include "acinterp.h"4950#define _COMPONENT ACPI_DISPATCHER51ACPI_MODULE_NAME("dscontrol")5253/*******************************************************************************54*55* FUNCTION: acpi_ds_exec_begin_control_op56*57* PARAMETERS: walk_list - The list that owns the walk stack58* Op - The control Op59*60* RETURN: Status61*62* DESCRIPTION: Handles all control ops encountered during control method63* execution.64*65******************************************************************************/66acpi_status67acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,68union acpi_parse_object *op)69{70acpi_status status = AE_OK;71union acpi_generic_state *control_state;7273ACPI_FUNCTION_NAME(ds_exec_begin_control_op);7475ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",76op, op->common.aml_opcode, walk_state));7778switch (op->common.aml_opcode) {79case AML_WHILE_OP:8081/*82* If this is an additional iteration of a while loop, continue.83* There is no need to allocate a new control state.84*/85if (walk_state->control_state) {86if (walk_state->control_state->control.87aml_predicate_start ==88(walk_state->parser_state.aml - 1)) {8990/* Reset the state to start-of-loop */9192walk_state->control_state->common.state =93ACPI_CONTROL_CONDITIONAL_EXECUTING;94break;95}96}9798/*lint -fallthrough */99100case AML_IF_OP:101102/*103* IF/WHILE: Create a new control state to manage these104* constructs. We need to manage these as a stack, in order105* to handle nesting.106*/107control_state = acpi_ut_create_control_state();108if (!control_state) {109status = AE_NO_MEMORY;110break;111}112/*113* Save a pointer to the predicate for multiple executions114* of a loop115*/116control_state->control.aml_predicate_start =117walk_state->parser_state.aml - 1;118control_state->control.package_end =119walk_state->parser_state.pkg_end;120control_state->control.opcode = op->common.aml_opcode;121122/* Push the control state on this walk's control stack */123124acpi_ut_push_generic_state(&walk_state->control_state,125control_state);126break;127128case AML_ELSE_OP:129130/* Predicate is in the state object */131/* If predicate is true, the IF was executed, ignore ELSE part */132133if (walk_state->last_predicate) {134status = AE_CTRL_TRUE;135}136137break;138139case AML_RETURN_OP:140141break;142143default:144break;145}146147return (status);148}149150/*******************************************************************************151*152* FUNCTION: acpi_ds_exec_end_control_op153*154* PARAMETERS: walk_list - The list that owns the walk stack155* Op - The control Op156*157* RETURN: Status158*159* DESCRIPTION: Handles all control ops encountered during control method160* execution.161*162******************************************************************************/163164acpi_status165acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,166union acpi_parse_object * op)167{168acpi_status status = AE_OK;169union acpi_generic_state *control_state;170171ACPI_FUNCTION_NAME(ds_exec_end_control_op);172173switch (op->common.aml_opcode) {174case AML_IF_OP:175176ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));177178/*179* Save the result of the predicate in case there is an180* ELSE to come181*/182walk_state->last_predicate =183(u8)walk_state->control_state->common.value;184185/*186* Pop the control state that was created at the start187* of the IF and free it188*/189control_state =190acpi_ut_pop_generic_state(&walk_state->control_state);191acpi_ut_delete_generic_state(control_state);192break;193194case AML_ELSE_OP:195196break;197198case AML_WHILE_OP:199200ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));201202control_state = walk_state->control_state;203if (control_state->common.value) {204205/* Predicate was true, the body of the loop was just executed */206207/*208* This loop counter mechanism allows the interpreter to escape209* possibly infinite loops. This can occur in poorly written AML210* when the hardware does not respond within a while loop and the211* loop does not implement a timeout.212*/213control_state->control.loop_count++;214if (control_state->control.loop_count >215ACPI_MAX_LOOP_ITERATIONS) {216status = AE_AML_INFINITE_LOOP;217break;218}219220/*221* Go back and evaluate the predicate and maybe execute the loop222* another time223*/224status = AE_CTRL_PENDING;225walk_state->aml_last_while =226control_state->control.aml_predicate_start;227break;228}229230/* Predicate was false, terminate this while loop */231232ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,233"[WHILE_OP] termination! Op=%p\n", op));234235/* Pop this control state and free it */236237control_state =238acpi_ut_pop_generic_state(&walk_state->control_state);239acpi_ut_delete_generic_state(control_state);240break;241242case AML_RETURN_OP:243244ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,245"[RETURN_OP] Op=%p Arg=%p\n", op,246op->common.value.arg));247248/*249* One optional operand -- the return value250* It can be either an immediate operand or a result that251* has been bubbled up the tree252*/253if (op->common.value.arg) {254255/* Since we have a real Return(), delete any implicit return */256257acpi_ds_clear_implicit_return(walk_state);258259/* Return statement has an immediate operand */260261status =262acpi_ds_create_operands(walk_state,263op->common.value.arg);264if (ACPI_FAILURE(status)) {265return (status);266}267268/*269* If value being returned is a Reference (such as270* an arg or local), resolve it now because it may271* cease to exist at the end of the method.272*/273status =274acpi_ex_resolve_to_value(&walk_state->operands[0],275walk_state);276if (ACPI_FAILURE(status)) {277return (status);278}279280/*281* Get the return value and save as the last result282* value. This is the only place where walk_state->return_desc283* is set to anything other than zero!284*/285walk_state->return_desc = walk_state->operands[0];286} else if (walk_state->result_count) {287288/* Since we have a real Return(), delete any implicit return */289290acpi_ds_clear_implicit_return(walk_state);291292/*293* The return value has come from a previous calculation.294*295* If value being returned is a Reference (such as296* an arg or local), resolve it now because it may297* cease to exist at the end of the method.298*299* Allow references created by the Index operator to return300* unchanged.301*/302if ((ACPI_GET_DESCRIPTOR_TYPE303(walk_state->results->results.obj_desc[0]) ==304ACPI_DESC_TYPE_OPERAND)305&& ((walk_state->results->results.obj_desc[0])->306common.type == ACPI_TYPE_LOCAL_REFERENCE)307&& ((walk_state->results->results.obj_desc[0])->308reference.class != ACPI_REFCLASS_INDEX)) {309status =310acpi_ex_resolve_to_value(&walk_state->311results->results.312obj_desc[0],313walk_state);314if (ACPI_FAILURE(status)) {315return (status);316}317}318319walk_state->return_desc =320walk_state->results->results.obj_desc[0];321} else {322/* No return operand */323324if (walk_state->num_operands) {325acpi_ut_remove_reference(walk_state->326operands[0]);327}328329walk_state->operands[0] = NULL;330walk_state->num_operands = 0;331walk_state->return_desc = NULL;332}333334ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,335"Completed RETURN_OP State=%p, RetVal=%p\n",336walk_state, walk_state->return_desc));337338/* End the control method execution right now */339340status = AE_CTRL_TERMINATE;341break;342343case AML_NOOP_OP:344345/* Just do nothing! */346break;347348case AML_BREAK_POINT_OP:349350/*351* Set the single-step flag. This will cause the debugger (if present)352* to break to the console within the AML debugger at the start of the353* next AML instruction.354*/355ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);356ACPI_DEBUGGER_EXEC(acpi_os_printf357("**break** Executed AML BreakPoint opcode\n"));358359/* Call to the OSL in case OS wants a piece of the action */360361status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,362"Executed AML Breakpoint opcode");363break;364365case AML_BREAK_OP:366case AML_CONTINUE_OP: /* ACPI 2.0 */367368/* Pop and delete control states until we find a while */369370while (walk_state->control_state &&371(walk_state->control_state->control.opcode !=372AML_WHILE_OP)) {373control_state =374acpi_ut_pop_generic_state(&walk_state->375control_state);376acpi_ut_delete_generic_state(control_state);377}378379/* No while found? */380381if (!walk_state->control_state) {382return (AE_AML_NO_WHILE);383}384385/* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */386387walk_state->aml_last_while =388walk_state->control_state->control.package_end;389390/* Return status depending on opcode */391392if (op->common.aml_opcode == AML_BREAK_OP) {393status = AE_CTRL_BREAK;394} else {395status = AE_CTRL_CONTINUE;396}397break;398399default:400401ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",402op->common.aml_opcode, op));403404status = AE_AML_BAD_OPCODE;405break;406}407408return (status);409}410411412