Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: psparse - Parser top level AML parse routines
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 /*
0011  * Parse the AML and build an operation tree as most interpreters,
0012  * like Perl, do. Parsing is done by hand rather than with a YACC
0013  * generated parser to tightly constrain stack and dynamic memory
0014  * usage. At the same time, parsing is kept flexible and the code
0015  * fairly compact by parsing based on a list of AML opcode
0016  * templates in aml_op_info[]
0017  */
0018 
0019 #include <acpi/acpi.h>
0020 #include "accommon.h"
0021 #include "acparser.h"
0022 #include "acdispat.h"
0023 #include "amlcode.h"
0024 #include "acinterp.h"
0025 #include "acnamesp.h"
0026 
0027 #define _COMPONENT          ACPI_PARSER
0028 ACPI_MODULE_NAME("psparse")
0029 
0030 /*******************************************************************************
0031  *
0032  * FUNCTION:    acpi_ps_get_opcode_size
0033  *
0034  * PARAMETERS:  opcode          - An AML opcode
0035  *
0036  * RETURN:      Size of the opcode, in bytes (1 or 2)
0037  *
0038  * DESCRIPTION: Get the size of the current opcode.
0039  *
0040  ******************************************************************************/
0041 u32 acpi_ps_get_opcode_size(u32 opcode)
0042 {
0043 
0044     /* Extended (2-byte) opcode if > 255 */
0045 
0046     if (opcode > 0x00FF) {
0047         return (2);
0048     }
0049 
0050     /* Otherwise, just a single byte opcode */
0051 
0052     return (1);
0053 }
0054 
0055 /*******************************************************************************
0056  *
0057  * FUNCTION:    acpi_ps_peek_opcode
0058  *
0059  * PARAMETERS:  parser_state        - A parser state object
0060  *
0061  * RETURN:      Next AML opcode
0062  *
0063  * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
0064  *
0065  ******************************************************************************/
0066 
0067 u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state)
0068 {
0069     u8 *aml;
0070     u16 opcode;
0071 
0072     aml = parser_state->aml;
0073     opcode = (u16) ACPI_GET8(aml);
0074 
0075     if (opcode == AML_EXTENDED_PREFIX) {
0076 
0077         /* Extended opcode, get the second opcode byte */
0078 
0079         aml++;
0080         opcode = (u16) ((opcode << 8) | ACPI_GET8(aml));
0081     }
0082 
0083     return (opcode);
0084 }
0085 
0086 /*******************************************************************************
0087  *
0088  * FUNCTION:    acpi_ps_complete_this_op
0089  *
0090  * PARAMETERS:  walk_state      - Current State
0091  *              op              - Op to complete
0092  *
0093  * RETURN:      Status
0094  *
0095  * DESCRIPTION: Perform any cleanup at the completion of an Op.
0096  *
0097  ******************************************************************************/
0098 
0099 acpi_status
0100 acpi_ps_complete_this_op(struct acpi_walk_state *walk_state,
0101              union acpi_parse_object *op)
0102 {
0103     union acpi_parse_object *prev;
0104     union acpi_parse_object *next;
0105     const struct acpi_opcode_info *parent_info;
0106     union acpi_parse_object *replacement_op = NULL;
0107     acpi_status status = AE_OK;
0108 
0109     ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op);
0110 
0111     /* Check for null Op, can happen if AML code is corrupt */
0112 
0113     if (!op) {
0114         return_ACPI_STATUS(AE_OK);  /* OK for now */
0115     }
0116 
0117     acpi_ex_stop_trace_opcode(op, walk_state);
0118 
0119     /* Delete this op and the subtree below it if asked to */
0120 
0121     if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) !=
0122          ACPI_PARSE_DELETE_TREE)
0123         || (walk_state->op_info->class == AML_CLASS_ARGUMENT)) {
0124         return_ACPI_STATUS(AE_OK);
0125     }
0126 
0127     /* Make sure that we only delete this subtree */
0128 
0129     if (op->common.parent) {
0130         prev = op->common.parent->common.value.arg;
0131         if (!prev) {
0132 
0133             /* Nothing more to do */
0134 
0135             goto cleanup;
0136         }
0137 
0138         /*
0139          * Check if we need to replace the operator and its subtree
0140          * with a return value op (placeholder op)
0141          */
0142         parent_info =
0143             acpi_ps_get_opcode_info(op->common.parent->common.
0144                         aml_opcode);
0145 
0146         switch (parent_info->class) {
0147         case AML_CLASS_CONTROL:
0148 
0149             break;
0150 
0151         case AML_CLASS_CREATE:
0152             /*
0153              * These opcodes contain term_arg operands. The current
0154              * op must be replaced by a placeholder return op
0155              */
0156             replacement_op =
0157                 acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
0158                          op->common.aml);
0159             if (!replacement_op) {
0160                 status = AE_NO_MEMORY;
0161             }
0162             break;
0163 
0164         case AML_CLASS_NAMED_OBJECT:
0165             /*
0166              * These opcodes contain term_arg operands. The current
0167              * op must be replaced by a placeholder return op
0168              */
0169             if ((op->common.parent->common.aml_opcode ==
0170                  AML_REGION_OP)
0171                 || (op->common.parent->common.aml_opcode ==
0172                 AML_DATA_REGION_OP)
0173                 || (op->common.parent->common.aml_opcode ==
0174                 AML_BUFFER_OP)
0175                 || (op->common.parent->common.aml_opcode ==
0176                 AML_PACKAGE_OP)
0177                 || (op->common.parent->common.aml_opcode ==
0178                 AML_BANK_FIELD_OP)
0179                 || (op->common.parent->common.aml_opcode ==
0180                 AML_VARIABLE_PACKAGE_OP)) {
0181                 replacement_op =
0182                     acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
0183                              op->common.aml);
0184                 if (!replacement_op) {
0185                     status = AE_NO_MEMORY;
0186                 }
0187             } else
0188                 if ((op->common.parent->common.aml_opcode ==
0189                  AML_NAME_OP)
0190                 && (walk_state->pass_number <=
0191                     ACPI_IMODE_LOAD_PASS2)) {
0192                 if ((op->common.aml_opcode == AML_BUFFER_OP)
0193                     || (op->common.aml_opcode == AML_PACKAGE_OP)
0194                     || (op->common.aml_opcode ==
0195                     AML_VARIABLE_PACKAGE_OP)) {
0196                     replacement_op =
0197                         acpi_ps_alloc_op(op->common.
0198                                  aml_opcode,
0199                                  op->common.aml);
0200                     if (!replacement_op) {
0201                         status = AE_NO_MEMORY;
0202                     } else {
0203                         replacement_op->named.data =
0204                             op->named.data;
0205                         replacement_op->named.length =
0206                             op->named.length;
0207                     }
0208                 }
0209             }
0210             break;
0211 
0212         default:
0213 
0214             replacement_op =
0215                 acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP,
0216                          op->common.aml);
0217             if (!replacement_op) {
0218                 status = AE_NO_MEMORY;
0219             }
0220         }
0221 
0222         /* We must unlink this op from the parent tree */
0223 
0224         if (prev == op) {
0225 
0226             /* This op is the first in the list */
0227 
0228             if (replacement_op) {
0229                 replacement_op->common.parent =
0230                     op->common.parent;
0231                 replacement_op->common.value.arg = NULL;
0232                 replacement_op->common.node = op->common.node;
0233                 op->common.parent->common.value.arg =
0234                     replacement_op;
0235                 replacement_op->common.next = op->common.next;
0236             } else {
0237                 op->common.parent->common.value.arg =
0238                     op->common.next;
0239             }
0240         }
0241 
0242         /* Search the parent list */
0243 
0244         else
0245             while (prev) {
0246 
0247                 /* Traverse all siblings in the parent's argument list */
0248 
0249                 next = prev->common.next;
0250                 if (next == op) {
0251                     if (replacement_op) {
0252                         replacement_op->common.parent =
0253                             op->common.parent;
0254                         replacement_op->common.value.
0255                             arg = NULL;
0256                         replacement_op->common.node =
0257                             op->common.node;
0258                         prev->common.next =
0259                             replacement_op;
0260                         replacement_op->common.next =
0261                             op->common.next;
0262                         next = NULL;
0263                     } else {
0264                         prev->common.next =
0265                             op->common.next;
0266                         next = NULL;
0267                     }
0268                 }
0269                 prev = next;
0270             }
0271     }
0272 
0273 cleanup:
0274 
0275     /* Now we can actually delete the subtree rooted at Op */
0276 
0277     acpi_ps_delete_parse_tree(op);
0278     return_ACPI_STATUS(status);
0279 }
0280 
0281 /*******************************************************************************
0282  *
0283  * FUNCTION:    acpi_ps_next_parse_state
0284  *
0285  * PARAMETERS:  walk_state          - Current state
0286  *              op                  - Current parse op
0287  *              callback_status     - Status from previous operation
0288  *
0289  * RETURN:      Status
0290  *
0291  * DESCRIPTION: Update the parser state based upon the return exception from
0292  *              the parser callback.
0293  *
0294  ******************************************************************************/
0295 
0296 acpi_status
0297 acpi_ps_next_parse_state(struct acpi_walk_state *walk_state,
0298              union acpi_parse_object *op,
0299              acpi_status callback_status)
0300 {
0301     struct acpi_parse_state *parser_state = &walk_state->parser_state;
0302     acpi_status status = AE_CTRL_PENDING;
0303 
0304     ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op);
0305 
0306     switch (callback_status) {
0307     case AE_CTRL_TERMINATE:
0308         /*
0309          * A control method was terminated via a RETURN statement.
0310          * The walk of this method is complete.
0311          */
0312         parser_state->aml = parser_state->aml_end;
0313         status = AE_CTRL_TERMINATE;
0314         break;
0315 
0316     case AE_CTRL_BREAK:
0317 
0318         parser_state->aml = walk_state->aml_last_while;
0319         walk_state->control_state->common.value = FALSE;
0320         status = AE_CTRL_BREAK;
0321         break;
0322 
0323     case AE_CTRL_CONTINUE:
0324 
0325         parser_state->aml = walk_state->aml_last_while;
0326         status = AE_CTRL_CONTINUE;
0327         break;
0328 
0329     case AE_CTRL_PENDING:
0330 
0331         parser_state->aml = walk_state->aml_last_while;
0332         break;
0333 
0334 #if 0
0335     case AE_CTRL_SKIP:
0336 
0337         parser_state->aml = parser_state->scope->parse_scope.pkg_end;
0338         status = AE_OK;
0339         break;
0340 #endif
0341 
0342     case AE_CTRL_TRUE:
0343         /*
0344          * Predicate of an IF was true, and we are at the matching ELSE.
0345          * Just close out this package
0346          */
0347         parser_state->aml = acpi_ps_get_next_package_end(parser_state);
0348         status = AE_CTRL_PENDING;
0349         break;
0350 
0351     case AE_CTRL_FALSE:
0352         /*
0353          * Either an IF/WHILE Predicate was false or we encountered a BREAK
0354          * opcode. In both cases, we do not execute the rest of the
0355          * package;  We simply close out the parent (finishing the walk of
0356          * this branch of the tree) and continue execution at the parent
0357          * level.
0358          */
0359         parser_state->aml = parser_state->scope->parse_scope.pkg_end;
0360 
0361         /* In the case of a BREAK, just force a predicate (if any) to FALSE */
0362 
0363         walk_state->control_state->common.value = FALSE;
0364         status = AE_CTRL_END;
0365         break;
0366 
0367     case AE_CTRL_TRANSFER:
0368 
0369         /* A method call (invocation) -- transfer control */
0370 
0371         status = AE_CTRL_TRANSFER;
0372         walk_state->prev_op = op;
0373         walk_state->method_call_op = op;
0374         walk_state->method_call_node =
0375             (op->common.value.arg)->common.node;
0376 
0377         /* Will return value (if any) be used by the caller? */
0378 
0379         walk_state->return_used =
0380             acpi_ds_is_result_used(op, walk_state);
0381         break;
0382 
0383     default:
0384 
0385         status = callback_status;
0386         if (ACPI_CNTL_EXCEPTION(callback_status)) {
0387             status = AE_OK;
0388         }
0389         break;
0390     }
0391 
0392     return_ACPI_STATUS(status);
0393 }
0394 
0395 /*******************************************************************************
0396  *
0397  * FUNCTION:    acpi_ps_parse_aml
0398  *
0399  * PARAMETERS:  walk_state      - Current state
0400  *
0401  *
0402  * RETURN:      Status
0403  *
0404  * DESCRIPTION: Parse raw AML and return a tree of ops
0405  *
0406  ******************************************************************************/
0407 
0408 acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
0409 {
0410     acpi_status status;
0411     struct acpi_thread_state *thread;
0412     struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list;
0413     struct acpi_walk_state *previous_walk_state;
0414 
0415     ACPI_FUNCTION_TRACE(ps_parse_aml);
0416 
0417     ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
0418               "Entered with WalkState=%p Aml=%p size=%X\n",
0419               walk_state, walk_state->parser_state.aml,
0420               walk_state->parser_state.aml_size));
0421 
0422     if (!walk_state->parser_state.aml) {
0423         return_ACPI_STATUS(AE_BAD_ADDRESS);
0424     }
0425 
0426     /* Create and initialize a new thread state */
0427 
0428     thread = acpi_ut_create_thread_state();
0429     if (!thread) {
0430         if (walk_state->method_desc) {
0431 
0432             /* Executing a control method - additional cleanup */
0433 
0434             acpi_ds_terminate_control_method(walk_state->
0435                              method_desc,
0436                              walk_state);
0437         }
0438 
0439         acpi_ds_delete_walk_state(walk_state);
0440         return_ACPI_STATUS(AE_NO_MEMORY);
0441     }
0442 
0443     walk_state->thread = thread;
0444 
0445     /*
0446      * If executing a method, the starting sync_level is this method's
0447      * sync_level
0448      */
0449     if (walk_state->method_desc) {
0450         walk_state->thread->current_sync_level =
0451             walk_state->method_desc->method.sync_level;
0452     }
0453 
0454     acpi_ds_push_walk_state(walk_state, thread);
0455 
0456     /*
0457      * This global allows the AML debugger to get a handle to the currently
0458      * executing control method.
0459      */
0460     acpi_gbl_current_walk_list = thread;
0461 
0462     /*
0463      * Execute the walk loop as long as there is a valid Walk State. This
0464      * handles nested control method invocations without recursion.
0465      */
0466     ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state));
0467 
0468     status = AE_OK;
0469     while (walk_state) {
0470         if (ACPI_SUCCESS(status)) {
0471             /*
0472              * The parse_loop executes AML until the method terminates
0473              * or calls another method.
0474              */
0475             status = acpi_ps_parse_loop(walk_state);
0476         }
0477 
0478         ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
0479                   "Completed one call to walk loop, %s State=%p\n",
0480                   acpi_format_exception(status), walk_state));
0481 
0482         if (walk_state->method_pathname && walk_state->method_is_nested) {
0483 
0484             /* Optional object evaluation log */
0485 
0486             ACPI_DEBUG_PRINT_RAW((ACPI_DB_EVALUATION,
0487                           "%-26s:  %*s%s\n",
0488                           "   Exit nested method",
0489                           (walk_state->
0490                            method_nesting_depth + 1) * 3,
0491                           " ",
0492                           &walk_state->method_pathname[1]));
0493 
0494             ACPI_FREE(walk_state->method_pathname);
0495             walk_state->method_is_nested = FALSE;
0496         }
0497         if (status == AE_CTRL_TRANSFER) {
0498             /*
0499              * A method call was detected.
0500              * Transfer control to the called control method
0501              */
0502             status =
0503                 acpi_ds_call_control_method(thread, walk_state,
0504                             NULL);
0505             if (ACPI_FAILURE(status)) {
0506                 status =
0507                     acpi_ds_method_error(status, walk_state);
0508             }
0509 
0510             /*
0511              * If the transfer to the new method method call worked,
0512              * a new walk state was created -- get it
0513              */
0514             walk_state = acpi_ds_get_current_walk_state(thread);
0515             continue;
0516         } else if (status == AE_CTRL_TERMINATE) {
0517             status = AE_OK;
0518         } else if ((status != AE_OK) && (walk_state->method_desc)) {
0519 
0520             /* Either the method parse or actual execution failed */
0521 
0522             acpi_ex_exit_interpreter();
0523             if (status == AE_ABORT_METHOD) {
0524                 acpi_ns_print_node_pathname(walk_state->
0525                                 method_node,
0526                                 "Aborting method");
0527                 acpi_os_printf("\n");
0528             } else {
0529                 ACPI_ERROR_METHOD("Aborting method",
0530                           walk_state->method_node, NULL,
0531                           status);
0532             }
0533             acpi_ex_enter_interpreter();
0534 
0535             /* Check for possible multi-thread reentrancy problem */
0536 
0537             if ((status == AE_ALREADY_EXISTS) &&
0538                 (!(walk_state->method_desc->method.info_flags &
0539                    ACPI_METHOD_SERIALIZED))) {
0540                 /*
0541                  * Method is not serialized and tried to create an object
0542                  * twice. The probable cause is that the method cannot
0543                  * handle reentrancy. Mark as "pending serialized" now, and
0544                  * then mark "serialized" when the last thread exits.
0545                  */
0546                 walk_state->method_desc->method.info_flags |=
0547                     ACPI_METHOD_SERIALIZED_PENDING;
0548             }
0549         }
0550 
0551         /* We are done with this walk, move on to the parent if any */
0552 
0553         walk_state = acpi_ds_pop_walk_state(thread);
0554 
0555         /* Reset the current scope to the beginning of scope stack */
0556 
0557         acpi_ds_scope_stack_clear(walk_state);
0558 
0559         /*
0560          * If we just returned from the execution of a control method or if we
0561          * encountered an error during the method parse phase, there's lots of
0562          * cleanup to do
0563          */
0564         if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) ==
0565              ACPI_PARSE_EXECUTE &&
0566              !(walk_state->parse_flags & ACPI_PARSE_MODULE_LEVEL)) ||
0567             (ACPI_FAILURE(status))) {
0568             acpi_ds_terminate_control_method(walk_state->
0569                              method_desc,
0570                              walk_state);
0571         }
0572 
0573         /* Delete this walk state and all linked control states */
0574 
0575         acpi_ps_cleanup_scope(&walk_state->parser_state);
0576         previous_walk_state = walk_state;
0577 
0578         ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
0579                   "ReturnValue=%p, ImplicitValue=%p State=%p\n",
0580                   walk_state->return_desc,
0581                   walk_state->implicit_return_obj, walk_state));
0582 
0583         /* Check if we have restarted a preempted walk */
0584 
0585         walk_state = acpi_ds_get_current_walk_state(thread);
0586         if (walk_state) {
0587             if (ACPI_SUCCESS(status)) {
0588                 /*
0589                  * There is another walk state, restart it.
0590                  * If the method return value is not used by the parent,
0591                  * The object is deleted
0592                  */
0593                 if (!previous_walk_state->return_desc) {
0594                     /*
0595                      * In slack mode execution, if there is no return value
0596                      * we should implicitly return zero (0) as a default value.
0597                      */
0598                     if (acpi_gbl_enable_interpreter_slack &&
0599                         !previous_walk_state->
0600                         implicit_return_obj) {
0601                         previous_walk_state->
0602                             implicit_return_obj =
0603                             acpi_ut_create_integer_object
0604                             ((u64) 0);
0605                         if (!previous_walk_state->
0606                             implicit_return_obj) {
0607                             return_ACPI_STATUS
0608                                 (AE_NO_MEMORY);
0609                         }
0610                     }
0611 
0612                     /* Restart the calling control method */
0613 
0614                     status =
0615                         acpi_ds_restart_control_method
0616                         (walk_state,
0617                          previous_walk_state->
0618                          implicit_return_obj);
0619                 } else {
0620                     /*
0621                      * We have a valid return value, delete any implicit
0622                      * return value.
0623                      */
0624                     acpi_ds_clear_implicit_return
0625                         (previous_walk_state);
0626 
0627                     status =
0628                         acpi_ds_restart_control_method
0629                         (walk_state,
0630                          previous_walk_state->return_desc);
0631                 }
0632                 if (ACPI_SUCCESS(status)) {
0633                     walk_state->walk_type |=
0634                         ACPI_WALK_METHOD_RESTART;
0635                 }
0636             } else {
0637                 /* On error, delete any return object or implicit return */
0638 
0639                 acpi_ut_remove_reference(previous_walk_state->
0640                              return_desc);
0641                 acpi_ds_clear_implicit_return
0642                     (previous_walk_state);
0643             }
0644         }
0645 
0646         /*
0647          * Just completed a 1st-level method, save the final internal return
0648          * value (if any)
0649          */
0650         else if (previous_walk_state->caller_return_desc) {
0651             if (previous_walk_state->implicit_return_obj) {
0652                 *(previous_walk_state->caller_return_desc) =
0653                     previous_walk_state->implicit_return_obj;
0654             } else {
0655                 /* NULL if no return value */
0656 
0657                 *(previous_walk_state->caller_return_desc) =
0658                     previous_walk_state->return_desc;
0659             }
0660         } else {
0661             if (previous_walk_state->return_desc) {
0662 
0663                 /* Caller doesn't want it, must delete it */
0664 
0665                 acpi_ut_remove_reference(previous_walk_state->
0666                              return_desc);
0667             }
0668             if (previous_walk_state->implicit_return_obj) {
0669 
0670                 /* Caller doesn't want it, must delete it */
0671 
0672                 acpi_ut_remove_reference(previous_walk_state->
0673                              implicit_return_obj);
0674             }
0675         }
0676 
0677         acpi_ds_delete_walk_state(previous_walk_state);
0678     }
0679 
0680     /* Normal exit */
0681 
0682     acpi_ex_release_all_mutexes(thread);
0683     acpi_ut_delete_generic_state(ACPI_CAST_PTR
0684                      (union acpi_generic_state, thread));
0685     acpi_gbl_current_walk_list = prev_walk_list;
0686     return_ACPI_STATUS(status);
0687 }