Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /******************************************************************************
  2.  *
  3.  * Module Name: dscontrol - Support for execution control opcodes -
  4.  *                          if/else/while/return
  5.  *
  6.  *****************************************************************************/
  7.  
  8. /*
  9.  * Copyright (C) 2000 - 2015, Intel Corp.
  10.  * All rights reserved.
  11.  *
  12.  * Redistribution and use in source and binary forms, with or without
  13.  * modification, are permitted provided that the following conditions
  14.  * are met:
  15.  * 1. Redistributions of source code must retain the above copyright
  16.  *    notice, this list of conditions, and the following disclaimer,
  17.  *    without modification.
  18.  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19.  *    substantially similar to the "NO WARRANTY" disclaimer below
  20.  *    ("Disclaimer") and any redistribution must be conditioned upon
  21.  *    including a substantially similar Disclaimer requirement for further
  22.  *    binary redistribution.
  23.  * 3. Neither the names of the above-listed copyright holders nor the names
  24.  *    of any contributors may be used to endorse or promote products derived
  25.  *    from this software without specific prior written permission.
  26.  *
  27.  * Alternatively, this software may be distributed under the terms of the
  28.  * GNU General Public License ("GPL") version 2 as published by the Free
  29.  * Software Foundation.
  30.  *
  31.  * NO WARRANTY
  32.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33.  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34.  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35.  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36.  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41.  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42.  * POSSIBILITY OF SUCH DAMAGES.
  43.  */
  44.  
  45. #include <acpi/acpi.h>
  46. #include "accommon.h"
  47. #include "amlcode.h"
  48. #include "acdispat.h"
  49. #include "acinterp.h"
  50.  
  51. #define _COMPONENT          ACPI_DISPATCHER
  52. ACPI_MODULE_NAME("dscontrol")
  53.  
  54. /*******************************************************************************
  55.  *
  56.  * FUNCTION:    acpi_ds_exec_begin_control_op
  57.  *
  58.  * PARAMETERS:  walk_list       - The list that owns the walk stack
  59.  *              op              - The control Op
  60.  *
  61.  * RETURN:      Status
  62.  *
  63.  * DESCRIPTION: Handles all control ops encountered during control method
  64.  *              execution.
  65.  *
  66.  ******************************************************************************/
  67. acpi_status
  68. acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
  69.                               union acpi_parse_object *op)
  70. {
  71.         acpi_status status = AE_OK;
  72.         union acpi_generic_state *control_state;
  73.  
  74.         ACPI_FUNCTION_NAME(ds_exec_begin_control_op);
  75.  
  76.         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n",
  77.                           op, op->common.aml_opcode, walk_state));
  78.  
  79.         switch (op->common.aml_opcode) {
  80.         case AML_WHILE_OP:
  81.                 /*
  82.                  * If this is an additional iteration of a while loop, continue.
  83.                  * There is no need to allocate a new control state.
  84.                  */
  85.                 if (walk_state->control_state) {
  86.                         if (walk_state->control_state->control.
  87.                             aml_predicate_start ==
  88.                             (walk_state->parser_state.aml - 1)) {
  89.  
  90.                                 /* Reset the state to start-of-loop */
  91.  
  92.                                 walk_state->control_state->common.state =
  93.                                     ACPI_CONTROL_CONDITIONAL_EXECUTING;
  94.                                 break;
  95.                         }
  96.                 }
  97.  
  98.                 /*lint -fallthrough */
  99.  
  100.         case AML_IF_OP:
  101.                 /*
  102.                  * IF/WHILE: Create a new control state to manage these
  103.                  * constructs. We need to manage these as a stack, in order
  104.                  * to handle nesting.
  105.                  */
  106.                 control_state = acpi_ut_create_control_state();
  107.                 if (!control_state) {
  108.                         status = AE_NO_MEMORY;
  109.                         break;
  110.                 }
  111.                 /*
  112.                  * Save a pointer to the predicate for multiple executions
  113.                  * of a loop
  114.                  */
  115.                 control_state->control.aml_predicate_start =
  116.                     walk_state->parser_state.aml - 1;
  117.                 control_state->control.package_end =
  118.                     walk_state->parser_state.pkg_end;
  119.                 control_state->control.opcode = op->common.aml_opcode;
  120.  
  121.                 /* Push the control state on this walk's control stack */
  122.  
  123.                 acpi_ut_push_generic_state(&walk_state->control_state,
  124.                                            control_state);
  125.                 break;
  126.  
  127.         case AML_ELSE_OP:
  128.  
  129.                 /* Predicate is in the state object */
  130.                 /* If predicate is true, the IF was executed, ignore ELSE part */
  131.  
  132.                 if (walk_state->last_predicate) {
  133.                         status = AE_CTRL_TRUE;
  134.                 }
  135.  
  136.                 break;
  137.  
  138.         case AML_RETURN_OP:
  139.  
  140.                 break;
  141.  
  142.         default:
  143.  
  144.                 break;
  145.         }
  146.  
  147.         return (status);
  148. }
  149.  
  150. /*******************************************************************************
  151.  *
  152.  * FUNCTION:    acpi_ds_exec_end_control_op
  153.  *
  154.  * PARAMETERS:  walk_list       - The list that owns the walk stack
  155.  *              op              - The control Op
  156.  *
  157.  * RETURN:      Status
  158.  *
  159.  * DESCRIPTION: Handles all control ops encountered during control method
  160.  *              execution.
  161.  *
  162.  ******************************************************************************/
  163.  
  164. acpi_status
  165. acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state,
  166.                             union acpi_parse_object * op)
  167. {
  168.         acpi_status status = AE_OK;
  169.         union acpi_generic_state *control_state;
  170.  
  171.         ACPI_FUNCTION_NAME(ds_exec_end_control_op);
  172.  
  173.         switch (op->common.aml_opcode) {
  174.         case AML_IF_OP:
  175.  
  176.                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
  177.  
  178.                 /*
  179.                  * Save the result of the predicate in case there is an
  180.                  * ELSE to come
  181.                  */
  182.                 walk_state->last_predicate =
  183.                     (u8)walk_state->control_state->common.value;
  184.  
  185.                 /*
  186.                  * Pop the control state that was created at the start
  187.                  * of the IF and free it
  188.                  */
  189.                 control_state =
  190.                     acpi_ut_pop_generic_state(&walk_state->control_state);
  191.                 acpi_ut_delete_generic_state(control_state);
  192.                 break;
  193.  
  194.         case AML_ELSE_OP:
  195.  
  196.                 break;
  197.  
  198.         case AML_WHILE_OP:
  199.  
  200.                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
  201.  
  202.                 control_state = walk_state->control_state;
  203.                 if (control_state->common.value) {
  204.  
  205.                         /* Predicate was true, the body of the loop was just executed */
  206.  
  207.                         /*
  208.                          * This loop counter mechanism allows the interpreter to escape
  209.                          * possibly infinite loops. This can occur in poorly written AML
  210.                          * when the hardware does not respond within a while loop and the
  211.                          * loop does not implement a timeout.
  212.                          */
  213.                         control_state->control.loop_count++;
  214.                         if (control_state->control.loop_count >
  215.                             acpi_gbl_max_loop_iterations) {
  216.                                 status = AE_AML_INFINITE_LOOP;
  217.                                 break;
  218.                         }
  219.  
  220.                         /*
  221.                          * Go back and evaluate the predicate and maybe execute the loop
  222.                          * another time
  223.                          */
  224.                         status = AE_CTRL_PENDING;
  225.                         walk_state->aml_last_while =
  226.                             control_state->control.aml_predicate_start;
  227.                         break;
  228.                 }
  229.  
  230.                 /* Predicate was false, terminate this while loop */
  231.  
  232.                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  233.                                   "[WHILE_OP] termination! Op=%p\n", op));
  234.  
  235.                 /* Pop this control state and free it */
  236.  
  237.                 control_state =
  238.                     acpi_ut_pop_generic_state(&walk_state->control_state);
  239.                 acpi_ut_delete_generic_state(control_state);
  240.                 break;
  241.  
  242.         case AML_RETURN_OP:
  243.  
  244.                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  245.                                   "[RETURN_OP] Op=%p Arg=%p\n", op,
  246.                                   op->common.value.arg));
  247.  
  248.                 /*
  249.                  * One optional operand -- the return value
  250.                  * It can be either an immediate operand or a result that
  251.                  * has been bubbled up the tree
  252.                  */
  253.                 if (op->common.value.arg) {
  254.  
  255.                         /* Since we have a real Return(), delete any implicit return */
  256.  
  257.                         acpi_ds_clear_implicit_return(walk_state);
  258.  
  259.                         /* Return statement has an immediate operand */
  260.  
  261.                         status =
  262.                             acpi_ds_create_operands(walk_state,
  263.                                                     op->common.value.arg);
  264.                         if (ACPI_FAILURE(status)) {
  265.                                 return (status);
  266.                         }
  267.  
  268.                         /*
  269.                          * If value being returned is a Reference (such as
  270.                          * an arg or local), resolve it now because it may
  271.                          * cease to exist at the end of the method.
  272.                          */
  273.                         status =
  274.                             acpi_ex_resolve_to_value(&walk_state->operands[0],
  275.                                                      walk_state);
  276.                         if (ACPI_FAILURE(status)) {
  277.                                 return (status);
  278.                         }
  279.  
  280.                         /*
  281.                          * Get the return value and save as the last result
  282.                          * value. This is the only place where walk_state->return_desc
  283.                          * is set to anything other than zero!
  284.                          */
  285.                         walk_state->return_desc = walk_state->operands[0];
  286.                 } else if (walk_state->result_count) {
  287.  
  288.                         /* Since we have a real Return(), delete any implicit return */
  289.  
  290.                         acpi_ds_clear_implicit_return(walk_state);
  291.  
  292.                         /*
  293.                          * The return value has come from a previous calculation.
  294.                          *
  295.                          * If value being returned is a Reference (such as
  296.                          * an arg or local), resolve it now because it may
  297.                          * cease to exist at the end of the method.
  298.                          *
  299.                          * Allow references created by the Index operator to return
  300.                          * unchanged.
  301.                          */
  302.                         if ((ACPI_GET_DESCRIPTOR_TYPE
  303.                              (walk_state->results->results.obj_desc[0]) ==
  304.                              ACPI_DESC_TYPE_OPERAND)
  305.                             && ((walk_state->results->results.obj_desc[0])->
  306.                                 common.type == ACPI_TYPE_LOCAL_REFERENCE)
  307.                             && ((walk_state->results->results.obj_desc[0])->
  308.                                 reference.class != ACPI_REFCLASS_INDEX)) {
  309.                                 status =
  310.                                     acpi_ex_resolve_to_value(&walk_state->
  311.                                                              results->results.
  312.                                                              obj_desc[0],
  313.                                                              walk_state);
  314.                                 if (ACPI_FAILURE(status)) {
  315.                                         return (status);
  316.                                 }
  317.                         }
  318.  
  319.                         walk_state->return_desc =
  320.                             walk_state->results->results.obj_desc[0];
  321.                 } else {
  322.                         /* No return operand */
  323.  
  324.                         if (walk_state->num_operands) {
  325.                                 acpi_ut_remove_reference(walk_state->
  326.                                                          operands[0]);
  327.                         }
  328.  
  329.                         walk_state->operands[0] = NULL;
  330.                         walk_state->num_operands = 0;
  331.                         walk_state->return_desc = NULL;
  332.                 }
  333.  
  334.                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
  335.                                   "Completed RETURN_OP State=%p, RetVal=%p\n",
  336.                                   walk_state, walk_state->return_desc));
  337.  
  338.                 /* End the control method execution right now */
  339.  
  340.                 status = AE_CTRL_TERMINATE;
  341.                 break;
  342.  
  343.         case AML_NOOP_OP:
  344.  
  345.                 /* Just do nothing! */
  346.  
  347.                 break;
  348.  
  349.         case AML_BREAK_POINT_OP:
  350.  
  351.                 /*
  352.                  * Set the single-step flag. This will cause the debugger (if present)
  353.                  * to break to the console within the AML debugger at the start of the
  354.                  * next AML instruction.
  355.                  */
  356.                 ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE);
  357.                 ACPI_DEBUGGER_EXEC(acpi_os_printf
  358.                                    ("**break** Executed AML BreakPoint opcode\n"));
  359.  
  360.                 /* Call to the OSL in case OS wants a piece of the action */
  361.  
  362.                 status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
  363.                                         "Executed AML Breakpoint opcode");
  364.                 break;
  365.  
  366.         case AML_BREAK_OP:
  367.         case AML_CONTINUE_OP:   /* ACPI 2.0 */
  368.  
  369.                 /* Pop and delete control states until we find a while */
  370.  
  371.                 while (walk_state->control_state &&
  372.                        (walk_state->control_state->control.opcode !=
  373.                         AML_WHILE_OP)) {
  374.                         control_state =
  375.                             acpi_ut_pop_generic_state(&walk_state->
  376.                                                       control_state);
  377.                         acpi_ut_delete_generic_state(control_state);
  378.                 }
  379.  
  380.                 /* No while found? */
  381.  
  382.                 if (!walk_state->control_state) {
  383.                         return (AE_AML_NO_WHILE);
  384.                 }
  385.  
  386.                 /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
  387.  
  388.                 walk_state->aml_last_while =
  389.                     walk_state->control_state->control.package_end;
  390.  
  391.                 /* Return status depending on opcode */
  392.  
  393.                 if (op->common.aml_opcode == AML_BREAK_OP) {
  394.                         status = AE_CTRL_BREAK;
  395.                 } else {
  396.                         status = AE_CTRL_CONTINUE;
  397.                 }
  398.                 break;
  399.  
  400.         default:
  401.  
  402.                 ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
  403.                             op->common.aml_opcode, op));
  404.  
  405.                 status = AE_AML_BAD_OPCODE;
  406.                 break;
  407.         }
  408.  
  409.         return (status);
  410. }
  411.