LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - dscontrol.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 72 99 72.7 %
Date: 2022-04-01 13:59:58 Functions: 2 2 100.0 %
Branches: 24 49 49.0 %

           Branch data     Line data    Source code
       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 - 2020, 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
      19                 :            : ACPI_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                 :            :  ******************************************************************************/
      34                 :            : acpi_status
      35                 :      98382 : acpi_ds_exec_begin_control_op(struct acpi_walk_state *walk_state,
      36                 :            :                               union acpi_parse_object *op)
      37                 :            : {
      38                 :      98382 :         acpi_status status = AE_OK;
      39                 :      98382 :         union acpi_generic_state *control_state;
      40                 :            : 
      41                 :      98382 :         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                 :      98382 :                           op, op->common.aml_opcode, walk_state));
      45                 :            : 
      46   [ +  +  +  + ]:      98382 :         switch (op->common.aml_opcode) {
      47                 :      15867 :         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         [ +  + ]:      15867 :                 if (walk_state->control_state) {
      53                 :      15744 :                         if (walk_state->control_state->control.
      54                 :            :                             aml_predicate_start ==
      55         [ +  - ]:      15744 :                             (walk_state->parser_state.aml - 1)) {
      56                 :            : 
      57                 :            :                                 /* Reset the state to start-of-loop */
      58                 :            : 
      59                 :      15744 :                                 walk_state->control_state->common.state =
      60                 :            :                                     ACPI_CONTROL_CONDITIONAL_EXECUTING;
      61                 :      15744 :                                 break;
      62                 :            :                         }
      63                 :            :                 }
      64                 :            : 
      65                 :            :                 /*lint -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                 :      70779 :                 control_state = acpi_ut_create_control_state();
      74         [ +  - ]:      70779 :                 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                 :      70779 :                 control_state->control.aml_predicate_start =
      83                 :      70779 :                     walk_state->parser_state.aml - 1;
      84                 :      70779 :                 control_state->control.package_end =
      85                 :      70779 :                     walk_state->parser_state.pkg_end;
      86                 :      70779 :                 control_state->control.opcode = op->common.aml_opcode;
      87                 :      70779 :                 control_state->control.loop_timeout = acpi_os_get_timer() +
      88                 :      70779 :                     ((u64)acpi_gbl_max_loop_iterations * ACPI_100NSEC_PER_SEC);
      89                 :            : 
      90                 :            :                 /* Push the control state on this walk's control stack */
      91                 :            : 
      92                 :      70779 :                 acpi_ut_push_generic_state(&walk_state->control_state,
      93                 :            :                                            control_state);
      94                 :      70779 :                 break;
      95                 :            : 
      96                 :       4560 :         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         [ +  + ]:       4560 :                 if (walk_state->last_predicate) {
     102                 :        123 :                         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                 :      98382 :         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                 :            : 
     133                 :            : acpi_status
     134                 :      96699 : acpi_ds_exec_end_control_op(struct acpi_walk_state *walk_state,
     135                 :            :                             union acpi_parse_object *op)
     136                 :            : {
     137                 :      96699 :         acpi_status status = AE_OK;
     138                 :      96699 :         union acpi_generic_state *control_state;
     139                 :            : 
     140                 :      96699 :         ACPI_FUNCTION_NAME(ds_exec_end_control_op);
     141                 :            : 
     142   [ +  +  +  -  :      96699 :         switch (op->common.aml_opcode) {
                -  -  + ]
     143                 :      69720 :         case AML_IF_OP:
     144                 :            : 
     145                 :      69720 :                 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                 :      69720 :                 walk_state->last_predicate =
     152                 :      69720 :                     (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                 :      69720 :                 control_state =
     159                 :      69720 :                     acpi_ut_pop_generic_state(&walk_state->control_state);
     160                 :      69720 :                 acpi_ut_delete_generic_state(control_state);
     161                 :      69720 :                 break;
     162                 :            : 
     163                 :            :         case AML_ELSE_OP:
     164                 :            : 
     165                 :            :                 break;
     166                 :            : 
     167                 :      15867 :         case AML_WHILE_OP:
     168                 :            : 
     169                 :      15867 :                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
     170                 :            : 
     171                 :      15867 :                 control_state = walk_state->control_state;
     172         [ +  + ]:      15867 :                 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         [ +  - ]:      15744 :                         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                 :      15744 :                         status = AE_CTRL_PENDING;
     194                 :      15744 :                         walk_state->aml_last_while =
     195                 :      15744 :                             control_state->control.aml_predicate_start;
     196                 :      15744 :                         break;
     197                 :            :                 }
     198                 :            : 
     199                 :            :                 /* Predicate was false, terminate this while loop */
     200                 :            : 
     201                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     202                 :        123 :                                   "[WHILE_OP] termination! Op=%p\n", op));
     203                 :            : 
     204                 :            :                 /* Pop this control state and free it */
     205                 :            : 
     206                 :        123 :                 control_state =
     207                 :        123 :                     acpi_ut_pop_generic_state(&walk_state->control_state);
     208                 :        123 :                 acpi_ut_delete_generic_state(control_state);
     209                 :        123 :                 break;
     210                 :            : 
     211                 :       7299 :         case AML_RETURN_OP:
     212                 :            : 
     213                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     214                 :            :                                   "[RETURN_OP] Op=%p Arg=%p\n", op,
     215                 :       7299 :                                   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         [ +  + ]:       7299 :                 if (op->common.value.arg) {
     223                 :            : 
     224                 :            :                         /* Since we have a real Return(), delete any implicit return */
     225                 :            : 
     226                 :       5115 :                         acpi_ds_clear_implicit_return(walk_state);
     227                 :            : 
     228                 :            :                         /* Return statement has an immediate operand */
     229                 :            : 
     230                 :       5115 :                         status =
     231                 :       5115 :                             acpi_ds_create_operands(walk_state,
     232                 :            :                                                     op->common.value.arg);
     233         [ +  - ]:       5115 :                         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                 :       5115 :                         status =
     243                 :       5115 :                             acpi_ex_resolve_to_value(&walk_state->operands[0],
     244                 :            :                                                      walk_state);
     245         [ +  - ]:       5115 :                         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                 :       5115 :                         walk_state->return_desc = walk_state->operands[0];
     255         [ +  - ]:       2184 :                 } else if (walk_state->result_count) {
     256                 :            : 
     257                 :            :                         /* Since we have a real Return(), delete any implicit return */
     258                 :            : 
     259                 :       2184 :                         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         [ +  - ]:       2184 :                         if ((ACPI_GET_DESCRIPTOR_TYPE
     272                 :            :                              (walk_state->results->results.obj_desc[0]) ==
     273                 :            :                              ACPI_DESC_TYPE_OPERAND)
     274                 :       2184 :                             && ((walk_state->results->results.obj_desc[0])->
     275         [ -  + ]:       2184 :                                 common.type == ACPI_TYPE_LOCAL_REFERENCE)
     276                 :          0 :                             && ((walk_state->results->results.obj_desc[0])->
     277         [ #  # ]:          0 :                                 reference.class != ACPI_REFCLASS_INDEX)) {
     278                 :          0 :                                 status =
     279                 :          0 :                                     acpi_ex_resolve_to_value(&walk_state->
     280                 :            :                                                              results->results.
     281                 :            :                                                              obj_desc[0],
     282                 :            :                                                              walk_state);
     283         [ #  # ]:          0 :                                 if (ACPI_FAILURE(status)) {
     284                 :            :                                         return (status);
     285                 :            :                                 }
     286                 :            :                         }
     287                 :            : 
     288                 :       2184 :                         walk_state->return_desc =
     289                 :       2184 :                             walk_state->results->results.obj_desc[0];
     290                 :            :                 } else {
     291                 :            :                         /* No return operand */
     292                 :            : 
     293         [ #  # ]:          0 :                         if (walk_state->num_operands) {
     294                 :          0 :                                 acpi_ut_remove_reference(walk_state->
     295                 :            :                                                          operands[0]);
     296                 :            :                         }
     297                 :            : 
     298                 :          0 :                         walk_state->operands[0] = NULL;
     299                 :          0 :                         walk_state->num_operands = 0;
     300                 :          0 :                         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                 :          0 :                 acpi_db_signal_break_point(walk_state);
     321                 :            : 
     322                 :            :                 /* Call to the OSL in case OS wants a piece of the action */
     323                 :            : 
     324                 :          0 :                 status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT,
     325                 :            :                                         "Executed AML Breakpoint opcode");
     326                 :          0 :                 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         [ #  # ]:          0 :                 while (walk_state->control_state &&
     334         [ #  # ]:          0 :                        (walk_state->control_state->control.opcode !=
     335                 :            :                         AML_WHILE_OP)) {
     336                 :          0 :                         control_state =
     337                 :          0 :                             acpi_ut_pop_generic_state(&walk_state->
     338                 :            :                                                       control_state);
     339                 :          0 :                         acpi_ut_delete_generic_state(control_state);
     340                 :            :                 }
     341                 :            : 
     342                 :            :                 /* No while found? */
     343                 :            : 
     344         [ #  # ]:          0 :                 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                 :          0 :                 walk_state->aml_last_while =
     351                 :          0 :                     walk_state->control_state->control.package_end;
     352                 :            : 
     353                 :            :                 /* Return status depending on opcode */
     354                 :            : 
     355         [ #  # ]:          0 :                 if (op->common.aml_opcode == AML_BREAK_OP) {
     356                 :            :                         status = AE_CTRL_BREAK;
     357                 :            :                 } else {
     358                 :          0 :                         status = AE_CTRL_CONTINUE;
     359                 :            :                 }
     360                 :            :                 break;
     361                 :            : 
     362                 :          0 :         default:
     363                 :            : 
     364                 :          0 :                 ACPI_ERROR((AE_INFO, "Unknown control opcode=0x%X Op=%p",
     365                 :            :                             op->common.aml_opcode, op));
     366                 :            : 
     367                 :          0 :                 status = AE_AML_BAD_OPCODE;
     368                 :          0 :                 break;
     369                 :            :         }
     370                 :            : 
     371                 :            :         return (status);
     372                 :            : }

Generated by: LCOV version 1.14