cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dscontrol.c (9572B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: dscontrol - Support for execution control opcodes -
      5 *                          if/else/while/return
      6 *
      7 * Copyright (C) 2000 - 2022, 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_DISPATCHER
     19ACPI_MODULE_NAME("dscontrol")
     20
     21/*******************************************************************************
     22 *
     23 * FUNCTION:    acpi_ds_exec_begin_control_op
     24 *
     25 * PARAMETERS:  walk_list       - The list that owns the walk stack
     26 *              op              - The control Op
     27 *
     28 * RETURN:      Status
     29 *
     30 * DESCRIPTION: Handles all control ops encountered during control method
     31 *              execution.
     32 *
     33 ******************************************************************************/
     34acpi_status
     35acpi_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 these
     70		 * constructs. We need to manage these as a stack, in order
     71		 * 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 executions
     80		 * of a loop
     81		 */
     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_op
    122 *
    123 * PARAMETERS:  walk_list       - The list that owns the walk stack
    124 *              op              - The control Op
    125 *
    126 * RETURN:      Status
    127 *
    128 * DESCRIPTION: Handles all control ops encountered during control method
    129 *              execution.
    130 *
    131 ******************************************************************************/
    132
    133acpi_status
    134acpi_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 an
    149		 * ELSE to come
    150		 */
    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 start
    156		 * of the IF and free it
    157		 */
    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 interpreter
    178			 * to escape possibly infinite loops. This can occur in poorly
    179			 * written AML when the hardware does not respond within a while
    180			 * 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 loop
    191			 * another time
    192			 */
    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 value
    219		 * It can be either an immediate operand or a result that
    220		 * has been bubbled up the tree
    221		 */
    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 as
    239			 * an arg or local), resolve it now because it may
    240			 * 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 result
    251			 * value. This is the only place where walk_state->return_desc
    252			 * 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 as
    265			 * an arg or local), resolve it now because it may
    266			 * cease to exist at the end of the method.
    267			 *
    268			 * Allow references created by the Index operator to return
    269			 * unchanged.
    270			 */
    271			if ((ACPI_GET_DESCRIPTOR_TYPE
    272			     (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}