LCOV - code coverage report
Current view: top level - drivers/acpi/acpica - dsmethod.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 161 218 73.9 %
Date: 2022-03-28 15:32:58 Functions: 8 8 100.0 %
Branches: 54 110 49.1 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
       2                 :            : /******************************************************************************
       3                 :            :  *
       4                 :            :  * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
       5                 :            :  *
       6                 :            :  * Copyright (C) 2000 - 2020, Intel Corp.
       7                 :            :  *
       8                 :            :  *****************************************************************************/
       9                 :            : 
      10                 :            : #include <acpi/acpi.h>
      11                 :            : #include "accommon.h"
      12                 :            : #include "acdispat.h"
      13                 :            : #include "acinterp.h"
      14                 :            : #include "acnamesp.h"
      15                 :            : #include "acparser.h"
      16                 :            : #include "amlcode.h"
      17                 :            : #include "acdebug.h"
      18                 :            : 
      19                 :            : #define _COMPONENT          ACPI_DISPATCHER
      20                 :            : ACPI_MODULE_NAME("dsmethod")
      21                 :            : 
      22                 :            : /* Local prototypes */
      23                 :            : static acpi_status
      24                 :            : acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
      25                 :            :                              union acpi_parse_object **out_op);
      26                 :            : 
      27                 :            : static acpi_status
      28                 :            : acpi_ds_create_method_mutex(union acpi_operand_object *method_desc);
      29                 :            : 
      30                 :            : /*******************************************************************************
      31                 :            :  *
      32                 :            :  * FUNCTION:    acpi_ds_auto_serialize_method
      33                 :            :  *
      34                 :            :  * PARAMETERS:  node                        - Namespace Node of the method
      35                 :            :  *              obj_desc                    - Method object attached to node
      36                 :            :  *
      37                 :            :  * RETURN:      Status
      38                 :            :  *
      39                 :            :  * DESCRIPTION: Parse a control method AML to scan for control methods that
      40                 :            :  *              need serialization due to the creation of named objects.
      41                 :            :  *
      42                 :            :  * NOTE: It is a bit of overkill to mark all such methods serialized, since
      43                 :            :  * there is only a problem if the method actually blocks during execution.
      44                 :            :  * A blocking operation is, for example, a Sleep() operation, or any access
      45                 :            :  * to an operation region. However, it is probably not possible to easily
      46                 :            :  * detect whether a method will block or not, so we simply mark all suspicious
      47                 :            :  * methods as serialized.
      48                 :            :  *
      49                 :            :  * NOTE2: This code is essentially a generic routine for parsing a single
      50                 :            :  * control method.
      51                 :            :  *
      52                 :            :  ******************************************************************************/
      53                 :            : 
      54                 :            : acpi_status
      55                 :       1904 : acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
      56                 :            :                               union acpi_operand_object *obj_desc)
      57                 :            : {
      58                 :       1904 :         acpi_status status;
      59                 :       1904 :         union acpi_parse_object *op = NULL;
      60                 :       1904 :         struct acpi_walk_state *walk_state;
      61                 :            : 
      62                 :       1904 :         ACPI_FUNCTION_TRACE_PTR(ds_auto_serialize_method, node);
      63                 :            : 
      64                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
      65                 :            :                           "Method auto-serialization parse [%4.4s] %p\n",
      66                 :       1904 :                           acpi_ut_get_node_name(node), node));
      67                 :            : 
      68                 :            :         /* Create/Init a root op for the method parse tree */
      69                 :            : 
      70                 :       1904 :         op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start);
      71         [ +  - ]:       1904 :         if (!op) {
      72                 :            :                 return_ACPI_STATUS(AE_NO_MEMORY);
      73                 :            :         }
      74                 :            : 
      75                 :       1904 :         acpi_ps_set_name(op, node->name.integer);
      76                 :       1904 :         op->common.node = node;
      77                 :            : 
      78                 :            :         /* Create and initialize a new walk state */
      79                 :            : 
      80                 :       1904 :         walk_state =
      81                 :       1904 :             acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
      82         [ -  + ]:       1904 :         if (!walk_state) {
      83                 :          0 :                 acpi_ps_free_op(op);
      84                 :          0 :                 return_ACPI_STATUS(AE_NO_MEMORY);
      85                 :            :         }
      86                 :            : 
      87                 :       1904 :         status = acpi_ds_init_aml_walk(walk_state, op, node,
      88                 :            :                                        obj_desc->method.aml_start,
      89                 :            :                                        obj_desc->method.aml_length, NULL, 0);
      90         [ -  + ]:       1904 :         if (ACPI_FAILURE(status)) {
      91                 :          0 :                 acpi_ds_delete_walk_state(walk_state);
      92                 :          0 :                 acpi_ps_free_op(op);
      93                 :          0 :                 return_ACPI_STATUS(status);
      94                 :            :         }
      95                 :            : 
      96                 :       1904 :         walk_state->descending_callback = acpi_ds_detect_named_opcodes;
      97                 :            : 
      98                 :            :         /* Parse the method, scan for creation of named objects */
      99                 :            : 
     100                 :       1904 :         status = acpi_ps_parse_aml(walk_state);
     101                 :            : 
     102                 :       1904 :         acpi_ps_delete_parse_tree(op);
     103                 :       1904 :         return_ACPI_STATUS(status);
     104                 :            : }
     105                 :            : 
     106                 :            : /*******************************************************************************
     107                 :            :  *
     108                 :            :  * FUNCTION:    acpi_ds_detect_named_opcodes
     109                 :            :  *
     110                 :            :  * PARAMETERS:  walk_state      - Current state of the parse tree walk
     111                 :            :  *              out_op          - Unused, required for parser interface
     112                 :            :  *
     113                 :            :  * RETURN:      Status
     114                 :            :  *
     115                 :            :  * DESCRIPTION: Descending callback used during the loading of ACPI tables.
     116                 :            :  *              Currently used to detect methods that must be marked serialized
     117                 :            :  *              in order to avoid problems with the creation of named objects.
     118                 :            :  *
     119                 :            :  ******************************************************************************/
     120                 :            : 
     121                 :            : static acpi_status
     122                 :      15428 : acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state,
     123                 :            :                              union acpi_parse_object **out_op)
     124                 :            : {
     125                 :            : 
     126                 :      15428 :         ACPI_FUNCTION_NAME(acpi_ds_detect_named_opcodes);
     127                 :            : 
     128                 :            :         /* We are only interested in opcodes that create a new name */
     129                 :            : 
     130                 :      15428 :         if (!
     131         [ +  + ]:      15428 :             (walk_state->op_info->
     132                 :            :              flags & (AML_NAMED | AML_CREATE | AML_FIELD))) {
     133                 :            :                 return (AE_OK);
     134                 :            :         }
     135                 :            : 
     136                 :            :         /*
     137                 :            :          * At this point, we know we have a Named object opcode.
     138                 :            :          * Mark the method as serialized. Later code will create a mutex for
     139                 :            :          * this method to enforce serialization.
     140                 :            :          *
     141                 :            :          * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the
     142                 :            :          * Sync Level mechanism for this method, even though it is now serialized.
     143                 :            :          * Otherwise, there can be conflicts with existing ASL code that actually
     144                 :            :          * uses sync levels.
     145                 :            :          */
     146                 :        112 :         walk_state->method_desc->method.sync_level = 0;
     147                 :        112 :         walk_state->method_desc->method.info_flags |=
     148                 :            :             (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL);
     149                 :            : 
     150                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_INFO,
     151                 :            :                           "Method serialized [%4.4s] %p - [%s] (%4.4X)\n",
     152                 :            :                           walk_state->method_node->name.ascii,
     153                 :            :                           walk_state->method_node, walk_state->op_info->name,
     154                 :        112 :                           walk_state->opcode));
     155                 :            : 
     156                 :            :         /* Abort the parse, no need to examine this method any further */
     157                 :            : 
     158                 :        112 :         return (AE_CTRL_TERMINATE);
     159                 :            : }
     160                 :            : 
     161                 :            : /*******************************************************************************
     162                 :            :  *
     163                 :            :  * FUNCTION:    acpi_ds_method_error
     164                 :            :  *
     165                 :            :  * PARAMETERS:  status          - Execution status
     166                 :            :  *              walk_state      - Current state
     167                 :            :  *
     168                 :            :  * RETURN:      Status
     169                 :            :  *
     170                 :            :  * DESCRIPTION: Called on method error. Invoke the global exception handler if
     171                 :            :  *              present, dump the method data if the debugger is configured
     172                 :            :  *
     173                 :            :  *              Note: Allows the exception handler to change the status code
     174                 :            :  *
     175                 :            :  ******************************************************************************/
     176                 :            : 
     177                 :            : acpi_status
     178                 :      20171 : acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state)
     179                 :            : {
     180                 :      20171 :         u32 aml_offset;
     181                 :      20171 :         acpi_name name = 0;
     182                 :            : 
     183                 :      20171 :         ACPI_FUNCTION_ENTRY();
     184                 :            : 
     185                 :            :         /* Ignore AE_OK and control exception codes */
     186                 :            : 
     187   [ +  -  -  + ]:      20171 :         if (ACPI_SUCCESS(status) || (status & AE_CODE_CONTROL)) {
     188                 :            :                 return (status);
     189                 :            :         }
     190                 :            : 
     191                 :            :         /* Invoke the global exception handler */
     192                 :            : 
     193         [ #  # ]:          0 :         if (acpi_gbl_exception_handler) {
     194                 :            : 
     195                 :            :                 /* Exit the interpreter, allow handler to execute methods */
     196                 :            : 
     197                 :          0 :                 acpi_ex_exit_interpreter();
     198                 :            : 
     199                 :            :                 /*
     200                 :            :                  * Handler can map the exception code to anything it wants, including
     201                 :            :                  * AE_OK, in which case the executing method will not be aborted.
     202                 :            :                  */
     203                 :          0 :                 aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml,
     204                 :            :                                                 walk_state->parser_state.
     205                 :            :                                                 aml_start);
     206                 :            : 
     207         [ #  # ]:          0 :                 if (walk_state->method_node) {
     208                 :          0 :                         name = walk_state->method_node->name.integer;
     209         [ #  # ]:          0 :                 } else if (walk_state->deferred_node) {
     210                 :          0 :                         name = walk_state->deferred_node->name.integer;
     211                 :            :                 }
     212                 :            : 
     213                 :          0 :                 status = acpi_gbl_exception_handler(status, name,
     214                 :          0 :                                                     walk_state->opcode,
     215                 :            :                                                     aml_offset, NULL);
     216                 :          0 :                 acpi_ex_enter_interpreter();
     217                 :            :         }
     218                 :            : 
     219                 :          0 :         acpi_ds_clear_implicit_return(walk_state);
     220                 :            : 
     221         [ #  # ]:          0 :         if (ACPI_FAILURE(status)) {
     222                 :          0 :                 acpi_ds_dump_method_stack(status, walk_state, walk_state->op);
     223                 :            : 
     224                 :            :                 /* Display method locals/args if debugger is present */
     225                 :            : 
     226                 :            : #ifdef ACPI_DEBUGGER
     227                 :            :                 acpi_db_dump_method_info(status, walk_state);
     228                 :            : #endif
     229                 :            :         }
     230                 :            : 
     231                 :            :         return (status);
     232                 :            : }
     233                 :            : 
     234                 :            : /*******************************************************************************
     235                 :            :  *
     236                 :            :  * FUNCTION:    acpi_ds_create_method_mutex
     237                 :            :  *
     238                 :            :  * PARAMETERS:  obj_desc            - The method object
     239                 :            :  *
     240                 :            :  * RETURN:      Status
     241                 :            :  *
     242                 :            :  * DESCRIPTION: Create a mutex object for a serialized control method
     243                 :            :  *
     244                 :            :  ******************************************************************************/
     245                 :            : 
     246                 :            : static acpi_status
     247                 :        140 : acpi_ds_create_method_mutex(union acpi_operand_object *method_desc)
     248                 :            : {
     249                 :        140 :         union acpi_operand_object *mutex_desc;
     250                 :        140 :         acpi_status status;
     251                 :            : 
     252                 :        140 :         ACPI_FUNCTION_TRACE(ds_create_method_mutex);
     253                 :            : 
     254                 :            :         /* Create the new mutex object */
     255                 :            : 
     256                 :        140 :         mutex_desc = acpi_ut_create_internal_object(ACPI_TYPE_MUTEX);
     257         [ +  - ]:        140 :         if (!mutex_desc) {
     258                 :            :                 return_ACPI_STATUS(AE_NO_MEMORY);
     259                 :            :         }
     260                 :            : 
     261                 :            :         /* Create the actual OS Mutex */
     262                 :            : 
     263                 :        140 :         status = acpi_os_create_mutex(&mutex_desc->mutex.os_mutex);
     264         [ -  + ]:        140 :         if (ACPI_FAILURE(status)) {
     265                 :          0 :                 acpi_ut_delete_object_desc(mutex_desc);
     266                 :          0 :                 return_ACPI_STATUS(status);
     267                 :            :         }
     268                 :            : 
     269                 :        140 :         mutex_desc->mutex.sync_level = method_desc->method.sync_level;
     270                 :        140 :         method_desc->method.mutex = mutex_desc;
     271                 :        140 :         return_ACPI_STATUS(AE_OK);
     272                 :            : }
     273                 :            : 
     274                 :            : /*******************************************************************************
     275                 :            :  *
     276                 :            :  * FUNCTION:    acpi_ds_begin_method_execution
     277                 :            :  *
     278                 :            :  * PARAMETERS:  method_node         - Node of the method
     279                 :            :  *              obj_desc            - The method object
     280                 :            :  *              walk_state          - current state, NULL if not yet executing
     281                 :            :  *                                    a method.
     282                 :            :  *
     283                 :            :  * RETURN:      Status
     284                 :            :  *
     285                 :            :  * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
     286                 :            :  *              increments the thread count, and waits at the method semaphore
     287                 :            :  *              for clearance to execute.
     288                 :            :  *
     289                 :            :  ******************************************************************************/
     290                 :            : 
     291                 :            : acpi_status
     292                 :       2803 : acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node,
     293                 :            :                                union acpi_operand_object *obj_desc,
     294                 :            :                                struct acpi_walk_state *walk_state)
     295                 :            : {
     296                 :       2803 :         acpi_status status = AE_OK;
     297                 :            : 
     298                 :       2803 :         ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node);
     299                 :            : 
     300         [ +  - ]:       2803 :         if (!method_node) {
     301                 :            :                 return_ACPI_STATUS(AE_NULL_ENTRY);
     302                 :            :         }
     303                 :            : 
     304                 :       2803 :         acpi_ex_start_trace_method(method_node, obj_desc, walk_state);
     305                 :            : 
     306                 :            :         /* Prevent wraparound of thread count */
     307                 :            : 
     308         [ -  + ]:       2803 :         if (obj_desc->method.thread_count == ACPI_UINT8_MAX) {
     309                 :          0 :                 ACPI_ERROR((AE_INFO,
     310                 :            :                             "Method reached maximum reentrancy limit (255)"));
     311                 :          0 :                 return_ACPI_STATUS(AE_AML_METHOD_LIMIT);
     312                 :            :         }
     313                 :            : 
     314                 :            :         /*
     315                 :            :          * If this method is serialized, we need to acquire the method mutex.
     316                 :            :          */
     317         [ +  + ]:       2803 :         if (obj_desc->method.info_flags & ACPI_METHOD_SERIALIZED) {
     318                 :            :                 /*
     319                 :            :                  * Create a mutex for the method if it is defined to be Serialized
     320                 :            :                  * and a mutex has not already been created. We defer the mutex creation
     321                 :            :                  * until a method is actually executed, to minimize the object count
     322                 :            :                  */
     323         [ +  + ]:        420 :                 if (!obj_desc->method.mutex) {
     324                 :        140 :                         status = acpi_ds_create_method_mutex(obj_desc);
     325         [ +  - ]:        140 :                         if (ACPI_FAILURE(status)) {
     326                 :            :                                 return_ACPI_STATUS(status);
     327                 :            :                         }
     328                 :            :                 }
     329                 :            : 
     330                 :            :                 /*
     331                 :            :                  * The current_sync_level (per-thread) must be less than or equal to
     332                 :            :                  * the sync level of the method. This mechanism provides some
     333                 :            :                  * deadlock prevention.
     334                 :            :                  *
     335                 :            :                  * If the method was auto-serialized, we just ignore the sync level
     336                 :            :                  * mechanism, because auto-serialization of methods can interfere
     337                 :            :                  * with ASL code that actually uses sync levels.
     338                 :            :                  *
     339                 :            :                  * Top-level method invocation has no walk state at this point
     340                 :            :                  */
     341         [ +  + ]:        420 :                 if (walk_state &&
     342         [ +  - ]:        308 :                     (!(obj_desc->method.
     343                 :            :                        info_flags & ACPI_METHOD_IGNORE_SYNC_LEVEL))
     344                 :        308 :                     && (walk_state->thread->current_sync_level >
     345         [ -  + ]:        308 :                         obj_desc->method.mutex->mutex.sync_level)) {
     346                 :          0 :                         ACPI_ERROR((AE_INFO,
     347                 :            :                                     "Cannot acquire Mutex for method [%4.4s]"
     348                 :            :                                     ", current SyncLevel is too large (%u)",
     349                 :            :                                     acpi_ut_get_node_name(method_node),
     350                 :            :                                     walk_state->thread->current_sync_level));
     351                 :            : 
     352                 :          0 :                         return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
     353                 :            :                 }
     354                 :            : 
     355                 :            :                 /*
     356                 :            :                  * Obtain the method mutex if necessary. Do not acquire mutex for a
     357                 :            :                  * recursive call.
     358                 :            :                  */
     359         [ +  + ]:        420 :                 if (!walk_state ||
     360         [ -  + ]:        308 :                     !obj_desc->method.mutex->mutex.thread_id ||
     361         [ #  # ]:          0 :                     (walk_state->thread->thread_id !=
     362                 :            :                      obj_desc->method.mutex->mutex.thread_id)) {
     363                 :            :                         /*
     364                 :            :                          * Acquire the method mutex. This releases the interpreter if we
     365                 :            :                          * block (and reacquires it before it returns)
     366                 :            :                          */
     367                 :        420 :                         status =
     368                 :        420 :                             acpi_ex_system_wait_mutex(obj_desc->method.mutex->
     369                 :            :                                                       mutex.os_mutex,
     370                 :            :                                                       ACPI_WAIT_FOREVER);
     371         [ +  - ]:        420 :                         if (ACPI_FAILURE(status)) {
     372                 :            :                                 return_ACPI_STATUS(status);
     373                 :            :                         }
     374                 :            : 
     375                 :            :                         /* Update the mutex and walk info and save the original sync_level */
     376                 :            : 
     377         [ +  + ]:        420 :                         if (walk_state) {
     378                 :        308 :                                 obj_desc->method.mutex->mutex.
     379                 :        308 :                                     original_sync_level =
     380                 :        308 :                                     walk_state->thread->current_sync_level;
     381                 :            : 
     382                 :        308 :                                 obj_desc->method.mutex->mutex.thread_id =
     383                 :        308 :                                     walk_state->thread->thread_id;
     384                 :            : 
     385                 :            :                                 /*
     386                 :            :                                  * Update the current sync_level only if this is not an auto-
     387                 :            :                                  * serialized method. In the auto case, we have to ignore
     388                 :            :                                  * the sync level for the method mutex (created for the
     389                 :            :                                  * auto-serialization) because we have no idea of what the
     390                 :            :                                  * sync level should be. Therefore, just ignore it.
     391                 :            :                                  */
     392         [ +  - ]:        308 :                                 if (!(obj_desc->method.info_flags &
     393                 :            :                                       ACPI_METHOD_IGNORE_SYNC_LEVEL)) {
     394                 :        308 :                                         walk_state->thread->current_sync_level =
     395                 :        308 :                                             obj_desc->method.sync_level;
     396                 :            :                                 }
     397                 :            :                         } else {
     398                 :        112 :                                 obj_desc->method.mutex->mutex.
     399                 :        112 :                                     original_sync_level =
     400                 :        112 :                                     obj_desc->method.mutex->mutex.sync_level;
     401                 :            : 
     402                 :        112 :                                 obj_desc->method.mutex->mutex.thread_id =
     403                 :            :                                     acpi_os_get_thread_id();
     404                 :            :                         }
     405                 :            :                 }
     406                 :            : 
     407                 :            :                 /* Always increase acquisition depth */
     408                 :            : 
     409                 :        420 :                 obj_desc->method.mutex->mutex.acquisition_depth++;
     410                 :            :         }
     411                 :            : 
     412                 :            :         /*
     413                 :            :          * Allocate an Owner ID for this method, only if this is the first thread
     414                 :            :          * to begin concurrent execution. We only need one owner_id, even if the
     415                 :            :          * method is invoked recursively.
     416                 :            :          */
     417         [ +  - ]:       2803 :         if (!obj_desc->method.owner_id) {
     418                 :       2803 :                 status = acpi_ut_allocate_owner_id(&obj_desc->method.owner_id);
     419         [ -  + ]:       2803 :                 if (ACPI_FAILURE(status)) {
     420                 :          0 :                         goto cleanup;
     421                 :            :                 }
     422                 :            :         }
     423                 :            : 
     424                 :            :         /*
     425                 :            :          * Increment the method parse tree thread count since it has been
     426                 :            :          * reentered one more time (even if it is the same thread)
     427                 :            :          */
     428                 :       2803 :         obj_desc->method.thread_count++;
     429                 :       2803 :         acpi_method_count++;
     430                 :       2803 :         return_ACPI_STATUS(status);
     431                 :            : 
     432                 :            : cleanup:
     433                 :            :         /* On error, must release the method mutex (if present) */
     434                 :            : 
     435         [ #  # ]:          0 :         if (obj_desc->method.mutex) {
     436                 :          0 :                 acpi_os_release_mutex(obj_desc->method.mutex->mutex.os_mutex);
     437                 :            :         }
     438                 :            :         return_ACPI_STATUS(status);
     439                 :            : }
     440                 :            : 
     441                 :            : /*******************************************************************************
     442                 :            :  *
     443                 :            :  * FUNCTION:    acpi_ds_call_control_method
     444                 :            :  *
     445                 :            :  * PARAMETERS:  thread              - Info for this thread
     446                 :            :  *              this_walk_state     - Current walk state
     447                 :            :  *              op                  - Current Op to be walked
     448                 :            :  *
     449                 :            :  * RETURN:      Status
     450                 :            :  *
     451                 :            :  * DESCRIPTION: Transfer execution to a called control method
     452                 :            :  *
     453                 :            :  ******************************************************************************/
     454                 :            : 
     455                 :            : acpi_status
     456                 :        784 : acpi_ds_call_control_method(struct acpi_thread_state *thread,
     457                 :            :                             struct acpi_walk_state *this_walk_state,
     458                 :            :                             union acpi_parse_object *op)
     459                 :            : {
     460                 :        784 :         acpi_status status;
     461                 :        784 :         struct acpi_namespace_node *method_node;
     462                 :        784 :         struct acpi_walk_state *next_walk_state = NULL;
     463                 :        784 :         union acpi_operand_object *obj_desc;
     464                 :        784 :         struct acpi_evaluate_info *info;
     465                 :        784 :         u32 i;
     466                 :            : 
     467                 :        784 :         ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
     468                 :            : 
     469                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     470                 :            :                           "Calling method %p, currentstate=%p\n",
     471                 :        784 :                           this_walk_state->prev_op, this_walk_state));
     472                 :            : 
     473                 :            :         /*
     474                 :            :          * Get the namespace entry for the control method we are about to call
     475                 :            :          */
     476                 :        784 :         method_node = this_walk_state->method_call_node;
     477         [ +  - ]:        784 :         if (!method_node) {
     478                 :            :                 return_ACPI_STATUS(AE_NULL_ENTRY);
     479                 :            :         }
     480                 :            : 
     481                 :        784 :         obj_desc = acpi_ns_get_attached_object(method_node);
     482         [ +  - ]:        784 :         if (!obj_desc) {
     483                 :            :                 return_ACPI_STATUS(AE_NULL_OBJECT);
     484                 :            :         }
     485                 :            : 
     486                 :            :         /* Init for new method, possibly wait on method mutex */
     487                 :            : 
     488                 :        784 :         status =
     489                 :        784 :             acpi_ds_begin_method_execution(method_node, obj_desc,
     490                 :            :                                            this_walk_state);
     491         [ +  - ]:        784 :         if (ACPI_FAILURE(status)) {
     492                 :            :                 return_ACPI_STATUS(status);
     493                 :            :         }
     494                 :            : 
     495                 :            :         /* Begin method parse/execution. Create a new walk state */
     496                 :            : 
     497                 :        784 :         next_walk_state =
     498                 :        784 :             acpi_ds_create_walk_state(obj_desc->method.owner_id, NULL, obj_desc,
     499                 :            :                                       thread);
     500         [ -  + ]:        784 :         if (!next_walk_state) {
     501                 :          0 :                 status = AE_NO_MEMORY;
     502                 :          0 :                 goto cleanup;
     503                 :            :         }
     504                 :            : 
     505                 :            :         /*
     506                 :            :          * The resolved arguments were put on the previous walk state's operand
     507                 :            :          * stack. Operands on the previous walk state stack always
     508                 :            :          * start at index 0. Also, null terminate the list of arguments
     509                 :            :          */
     510                 :        784 :         this_walk_state->operands[this_walk_state->num_operands] = NULL;
     511                 :            : 
     512                 :            :         /*
     513                 :            :          * Allocate and initialize the evaluation information block
     514                 :            :          * TBD: this is somewhat inefficient, should change interface to
     515                 :            :          * ds_init_aml_walk. For now, keeps this struct off the CPU stack
     516                 :            :          */
     517                 :        784 :         info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info));
     518         [ -  + ]:        784 :         if (!info) {
     519                 :          0 :                 status = AE_NO_MEMORY;
     520                 :          0 :                 goto cleanup;
     521                 :            :         }
     522                 :            : 
     523                 :        784 :         info->parameters = &this_walk_state->operands[0];
     524                 :            : 
     525                 :        784 :         status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
     526                 :            :                                        obj_desc->method.aml_start,
     527                 :            :                                        obj_desc->method.aml_length, info,
     528                 :            :                                        ACPI_IMODE_EXECUTE);
     529                 :            : 
     530                 :        784 :         ACPI_FREE(info);
     531         [ -  + ]:        784 :         if (ACPI_FAILURE(status)) {
     532                 :          0 :                 goto cleanup;
     533                 :            :         }
     534                 :            : 
     535                 :        784 :         next_walk_state->method_nesting_depth =
     536                 :        784 :             this_walk_state->method_nesting_depth + 1;
     537                 :            : 
     538                 :            :         /*
     539                 :            :          * Delete the operands on the previous walkstate operand stack
     540                 :            :          * (they were copied to new objects)
     541                 :            :          */
     542         [ +  + ]:       1568 :         for (i = 0; i < obj_desc->method.param_count; i++) {
     543                 :        784 :                 acpi_ut_remove_reference(this_walk_state->operands[i]);
     544                 :        784 :                 this_walk_state->operands[i] = NULL;
     545                 :            :         }
     546                 :            : 
     547                 :            :         /* Clear the operand stack */
     548                 :            : 
     549                 :        784 :         this_walk_state->num_operands = 0;
     550                 :            : 
     551                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     552                 :            :                           "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
     553                 :        784 :                           method_node->name.ascii, next_walk_state));
     554                 :            : 
     555                 :       1568 :         this_walk_state->method_pathname =
     556                 :        784 :             acpi_ns_get_normalized_pathname(method_node, TRUE);
     557                 :        784 :         this_walk_state->method_is_nested = TRUE;
     558                 :            : 
     559                 :            :         /* Optional object evaluation log */
     560                 :            : 
     561                 :            :         ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
     562                 :            :                               "%-26s:  %*s%s\n", "   Nested method call",
     563                 :            :                               next_walk_state->method_nesting_depth * 3, " ",
     564                 :        784 :                               &this_walk_state->method_pathname[1]));
     565                 :            : 
     566                 :            :         /* Invoke an internal method if necessary */
     567                 :            : 
     568         [ -  + ]:        784 :         if (obj_desc->method.info_flags & ACPI_METHOD_INTERNAL_ONLY) {
     569                 :          0 :                 status =
     570                 :          0 :                     obj_desc->method.dispatch.implementation(next_walk_state);
     571         [ #  # ]:          0 :                 if (status == AE_OK) {
     572                 :          0 :                         status = AE_CTRL_TERMINATE;
     573                 :            :                 }
     574                 :            :         }
     575                 :            : 
     576                 :            :         return_ACPI_STATUS(status);
     577                 :            : 
     578                 :          0 : cleanup:
     579                 :            : 
     580                 :            :         /* On error, we must terminate the method properly */
     581                 :            : 
     582                 :          0 :         acpi_ds_terminate_control_method(obj_desc, next_walk_state);
     583                 :          0 :         acpi_ds_delete_walk_state(next_walk_state);
     584                 :            : 
     585                 :          0 :         return_ACPI_STATUS(status);
     586                 :            : }
     587                 :            : 
     588                 :            : /*******************************************************************************
     589                 :            :  *
     590                 :            :  * FUNCTION:    acpi_ds_restart_control_method
     591                 :            :  *
     592                 :            :  * PARAMETERS:  walk_state          - State for preempted method (caller)
     593                 :            :  *              return_desc         - Return value from the called method
     594                 :            :  *
     595                 :            :  * RETURN:      Status
     596                 :            :  *
     597                 :            :  * DESCRIPTION: Restart a method that was preempted by another (nested) method
     598                 :            :  *              invocation. Handle the return value (if any) from the callee.
     599                 :            :  *
     600                 :            :  ******************************************************************************/
     601                 :            : 
     602                 :            : acpi_status
     603                 :        784 : acpi_ds_restart_control_method(struct acpi_walk_state *walk_state,
     604                 :            :                                union acpi_operand_object *return_desc)
     605                 :            : {
     606                 :        784 :         acpi_status status;
     607                 :        784 :         int same_as_implicit_return;
     608                 :            : 
     609                 :        784 :         ACPI_FUNCTION_TRACE_PTR(ds_restart_control_method, walk_state);
     610                 :            : 
     611                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     612                 :            :                           "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n",
     613                 :            :                           acpi_ut_get_node_name(walk_state->method_node),
     614                 :        784 :                           walk_state->method_call_op, return_desc));
     615                 :            : 
     616                 :            :         ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     617                 :            :                           "    ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n",
     618                 :            :                           walk_state->return_used,
     619                 :        784 :                           walk_state->results, walk_state));
     620                 :            : 
     621                 :            :         /* Did the called method return a value? */
     622                 :            : 
     623         [ +  - ]:        784 :         if (return_desc) {
     624                 :            : 
     625                 :            :                 /* Is the implicit return object the same as the return desc? */
     626                 :            : 
     627                 :        784 :                 same_as_implicit_return =
     628                 :        784 :                     (walk_state->implicit_return_obj == return_desc);
     629                 :            : 
     630                 :            :                 /* Are we actually going to use the return value? */
     631                 :            : 
     632         [ +  - ]:        784 :                 if (walk_state->return_used) {
     633                 :            : 
     634                 :            :                         /* Save the return value from the previous method */
     635                 :            : 
     636                 :        784 :                         status = acpi_ds_result_push(return_desc, walk_state);
     637         [ -  + ]:        784 :                         if (ACPI_FAILURE(status)) {
     638                 :          0 :                                 acpi_ut_remove_reference(return_desc);
     639                 :          0 :                                 return_ACPI_STATUS(status);
     640                 :            :                         }
     641                 :            : 
     642                 :            :                         /*
     643                 :            :                          * Save as THIS method's return value in case it is returned
     644                 :            :                          * immediately to yet another method
     645                 :            :                          */
     646                 :        784 :                         walk_state->return_desc = return_desc;
     647                 :            :                 }
     648                 :            : 
     649                 :            :                 /*
     650                 :            :                  * The following code is the optional support for the so-called
     651                 :            :                  * "implicit return". Some AML code assumes that the last value of the
     652                 :            :                  * method is "implicitly" returned to the caller, in the absence of an
     653                 :            :                  * explicit return value.
     654                 :            :                  *
     655                 :            :                  * Just save the last result of the method as the return value.
     656                 :            :                  *
     657                 :            :                  * NOTE: this is optional because the ASL language does not actually
     658                 :            :                  * support this behavior.
     659                 :            :                  */
     660         [ #  # ]:          0 :                 else if (!acpi_ds_do_implicit_return
     661                 :            :                          (return_desc, walk_state, FALSE)
     662         [ #  # ]:          0 :                          || same_as_implicit_return) {
     663                 :            :                         /*
     664                 :            :                          * Delete the return value if it will not be used by the
     665                 :            :                          * calling method or remove one reference if the explicit return
     666                 :            :                          * is the same as the implicit return value.
     667                 :            :                          */
     668                 :          0 :                         acpi_ut_remove_reference(return_desc);
     669                 :            :                 }
     670                 :            :         }
     671                 :            : 
     672                 :            :         return_ACPI_STATUS(AE_OK);
     673                 :            : }
     674                 :            : 
     675                 :            : /*******************************************************************************
     676                 :            :  *
     677                 :            :  * FUNCTION:    acpi_ds_terminate_control_method
     678                 :            :  *
     679                 :            :  * PARAMETERS:  method_desc         - Method object
     680                 :            :  *              walk_state          - State associated with the method
     681                 :            :  *
     682                 :            :  * RETURN:      None
     683                 :            :  *
     684                 :            :  * DESCRIPTION: Terminate a control method. Delete everything that the method
     685                 :            :  *              created, delete all locals and arguments, and delete the parse
     686                 :            :  *              tree if requested.
     687                 :            :  *
     688                 :            :  * MUTEX:       Interpreter is locked
     689                 :            :  *
     690                 :            :  ******************************************************************************/
     691                 :            : 
     692                 :            : void
     693                 :       2915 : acpi_ds_terminate_control_method(union acpi_operand_object *method_desc,
     694                 :            :                                  struct acpi_walk_state *walk_state)
     695                 :            : {
     696                 :            : 
     697                 :       2915 :         ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state);
     698                 :            : 
     699                 :            :         /* method_desc is required, walk_state is optional */
     700                 :            : 
     701         [ +  + ]:       2915 :         if (!method_desc) {
     702                 :            :                 return_VOID;
     703                 :            :         }
     704                 :            : 
     705         [ +  - ]:       2803 :         if (walk_state) {
     706                 :            : 
     707                 :            :                 /* Delete all arguments and locals */
     708                 :            : 
     709                 :       2803 :                 acpi_ds_method_data_delete_all(walk_state);
     710                 :            : 
     711                 :            :                 /*
     712                 :            :                  * Delete any namespace objects created anywhere within the
     713                 :            :                  * namespace by the execution of this method. Unless:
     714                 :            :                  * 1) This method is a module-level executable code method, in which
     715                 :            :                  *    case we want make the objects permanent.
     716                 :            :                  * 2) There are other threads executing the method, in which case we
     717                 :            :                  *    will wait until the last thread has completed.
     718                 :            :                  */
     719         [ +  - ]:       2803 :                 if (!(method_desc->method.info_flags & ACPI_METHOD_MODULE_LEVEL)
     720         [ +  - ]:       2803 :                     && (method_desc->method.thread_count == 1)) {
     721                 :            : 
     722                 :            :                         /* Delete any direct children of (created by) this method */
     723                 :            : 
     724                 :       2803 :                         (void)acpi_ex_exit_interpreter();
     725                 :       2803 :                         acpi_ns_delete_namespace_subtree(walk_state->
     726                 :            :                                                          method_node);
     727                 :       2803 :                         (void)acpi_ex_enter_interpreter();
     728                 :            : 
     729                 :            :                         /*
     730                 :            :                          * Delete any objects that were created by this method
     731                 :            :                          * elsewhere in the namespace (if any were created).
     732                 :            :                          * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the
     733                 :            :                          * deletion such that we don't have to perform an entire
     734                 :            :                          * namespace walk for every control method execution.
     735                 :            :                          */
     736         [ -  + ]:       2803 :                         if (method_desc->method.
     737                 :            :                             info_flags & ACPI_METHOD_MODIFIED_NAMESPACE) {
     738                 :          0 :                                 (void)acpi_ex_exit_interpreter();
     739                 :          0 :                                 acpi_ns_delete_namespace_by_owner(method_desc->
     740                 :          0 :                                                                   method.
     741                 :            :                                                                   owner_id);
     742                 :          0 :                                 (void)acpi_ex_enter_interpreter();
     743                 :          0 :                                 method_desc->method.info_flags &=
     744                 :            :                                     ~ACPI_METHOD_MODIFIED_NAMESPACE;
     745                 :            :                         }
     746                 :            :                 }
     747                 :            : 
     748                 :            :                 /*
     749                 :            :                  * If method is serialized, release the mutex and restore the
     750                 :            :                  * current sync level for this thread
     751                 :            :                  */
     752         [ +  + ]:       2803 :                 if (method_desc->method.mutex) {
     753                 :            : 
     754                 :            :                         /* Acquisition Depth handles recursive calls */
     755                 :            : 
     756                 :        420 :                         method_desc->method.mutex->mutex.acquisition_depth--;
     757         [ +  - ]:        420 :                         if (!method_desc->method.mutex->mutex.acquisition_depth) {
     758                 :        420 :                                 walk_state->thread->current_sync_level =
     759                 :        420 :                                     method_desc->method.mutex->mutex.
     760                 :            :                                     original_sync_level;
     761                 :            : 
     762                 :        420 :                                 acpi_os_release_mutex(method_desc->method.
     763                 :            :                                                       mutex->mutex.os_mutex);
     764                 :        420 :                                 method_desc->method.mutex->mutex.thread_id = 0;
     765                 :            :                         }
     766                 :            :                 }
     767                 :            :         }
     768                 :            : 
     769                 :            :         /* Decrement the thread count on the method */
     770                 :            : 
     771         [ +  - ]:       2803 :         if (method_desc->method.thread_count) {
     772                 :       2803 :                 method_desc->method.thread_count--;
     773                 :            :         } else {
     774                 :          0 :                 ACPI_ERROR((AE_INFO, "Invalid zero thread count in method"));
     775                 :            :         }
     776                 :            : 
     777                 :            :         /* Are there any other threads currently executing this method? */
     778                 :            : 
     779         [ +  - ]:       2803 :         if (method_desc->method.thread_count) {
     780                 :            :                 /*
     781                 :            :                  * Additional threads. Do not release the owner_id in this case,
     782                 :            :                  * we immediately reuse it for the next thread executing this method
     783                 :            :                  */
     784                 :            :                 ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
     785                 :            :                                   "*** Completed execution of one thread, %u threads remaining\n",
     786                 :            :                                   method_desc->method.thread_count));
     787                 :            :         } else {
     788                 :            :                 /* This is the only executing thread for this method */
     789                 :            : 
     790                 :            :                 /*
     791                 :            :                  * Support to dynamically change a method from not_serialized to
     792                 :            :                  * Serialized if it appears that the method is incorrectly written and
     793                 :            :                  * does not support multiple thread execution. The best example of this
     794                 :            :                  * is if such a method creates namespace objects and blocks. A second
     795                 :            :                  * thread will fail with an AE_ALREADY_EXISTS exception.
     796                 :            :                  *
     797                 :            :                  * This code is here because we must wait until the last thread exits
     798                 :            :                  * before marking the method as serialized.
     799                 :            :                  */
     800         [ -  + ]:       2803 :                 if (method_desc->method.
     801                 :            :                     info_flags & ACPI_METHOD_SERIALIZED_PENDING) {
     802         [ #  # ]:          0 :                         if (walk_state) {
     803                 :          0 :                                 ACPI_INFO(("Marking method %4.4s as Serialized "
     804                 :            :                                            "because of AE_ALREADY_EXISTS error",
     805                 :            :                                            walk_state->method_node->name.
     806                 :            :                                            ascii));
     807                 :            :                         }
     808                 :            : 
     809                 :            :                         /*
     810                 :            :                          * Method tried to create an object twice and was marked as
     811                 :            :                          * "pending serialized". The probable cause is that the method
     812                 :            :                          * cannot handle reentrancy.
     813                 :            :                          *
     814                 :            :                          * The method was created as not_serialized, but it tried to create
     815                 :            :                          * a named object and then blocked, causing the second thread
     816                 :            :                          * entrance to begin and then fail. Workaround this problem by
     817                 :            :                          * marking the method permanently as Serialized when the last
     818                 :            :                          * thread exits here.
     819                 :            :                          */
     820                 :          0 :                         method_desc->method.info_flags &=
     821                 :            :                             ~ACPI_METHOD_SERIALIZED_PENDING;
     822                 :            : 
     823                 :          0 :                         method_desc->method.info_flags |=
     824                 :            :                             (ACPI_METHOD_SERIALIZED |
     825                 :            :                              ACPI_METHOD_IGNORE_SYNC_LEVEL);
     826                 :          0 :                         method_desc->method.sync_level = 0;
     827                 :            :                 }
     828                 :            : 
     829                 :            :                 /* No more threads, we can free the owner_id */
     830                 :            : 
     831                 :       2803 :                 if (!
     832         [ +  - ]:       2803 :                     (method_desc->method.
     833                 :            :                      info_flags & ACPI_METHOD_MODULE_LEVEL)) {
     834                 :       2803 :                         acpi_ut_release_owner_id(&method_desc->method.owner_id);
     835                 :            :                 }
     836                 :            :         }
     837                 :            : 
     838                 :       2803 :         acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc->
     839                 :       2803 :                                   method.node, method_desc, walk_state);
     840                 :            : 
     841                 :       2803 :         return_VOID;
     842                 :            : }

Generated by: LCOV version 1.14