Home | History | Annotate | Line # | Download | only in parser
psloop.c revision 1.1.1.4
      1 /******************************************************************************
      2  *
      3  * Module Name: psloop - Main AML parse loop
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2014, Intel Corp.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions, and the following disclaimer,
     16  *    without modification.
     17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  *    including a substantially similar Disclaimer requirement for further
     21  *    binary redistribution.
     22  * 3. Neither the names of the above-listed copyright holders nor the names
     23  *    of any contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * Alternatively, this software may be distributed under the terms of the
     27  * GNU General Public License ("GPL") version 2 as published by the Free
     28  * Software Foundation.
     29  *
     30  * NO WARRANTY
     31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGES.
     42  */
     43 
     44 /*
     45  * Parse the AML and build an operation tree as most interpreters, (such as
     46  * Perl) do. Parsing is done by hand rather than with a YACC generated parser
     47  * to tightly constrain stack and dynamic memory usage. Parsing is kept
     48  * flexible and the code fairly compact by parsing based on a list of AML
     49  * opcode templates in AmlOpInfo[].
     50  */
     51 
     52 #include "acpi.h"
     53 #include "accommon.h"
     54 #include "acparser.h"
     55 #include "acdispat.h"
     56 #include "amlcode.h"
     57 
     58 #define _COMPONENT          ACPI_PARSER
     59         ACPI_MODULE_NAME    ("psloop")
     60 
     61 
     62 /* Local prototypes */
     63 
     64 static ACPI_STATUS
     65 AcpiPsGetArguments (
     66     ACPI_WALK_STATE         *WalkState,
     67     UINT8                   *AmlOpStart,
     68     ACPI_PARSE_OBJECT       *Op);
     69 
     70 static void
     71 AcpiPsLinkModuleCode (
     72     ACPI_PARSE_OBJECT       *ParentOp,
     73     UINT8                   *AmlStart,
     74     UINT32                  AmlLength,
     75     ACPI_OWNER_ID           OwnerId);
     76 
     77 
     78 /*******************************************************************************
     79  *
     80  * FUNCTION:    AcpiPsGetArguments
     81  *
     82  * PARAMETERS:  WalkState           - Current state
     83  *              AmlOpStart          - Op start in AML
     84  *              Op                  - Current Op
     85  *
     86  * RETURN:      Status
     87  *
     88  * DESCRIPTION: Get arguments for passed Op.
     89  *
     90  ******************************************************************************/
     91 
     92 static ACPI_STATUS
     93 AcpiPsGetArguments (
     94     ACPI_WALK_STATE         *WalkState,
     95     UINT8                   *AmlOpStart,
     96     ACPI_PARSE_OBJECT       *Op)
     97 {
     98     ACPI_STATUS             Status = AE_OK;
     99     ACPI_PARSE_OBJECT       *Arg = NULL;
    100     const ACPI_OPCODE_INFO  *OpInfo;
    101 
    102 
    103     ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);
    104 
    105 
    106     switch (Op->Common.AmlOpcode)
    107     {
    108     case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
    109     case AML_WORD_OP:       /* AML_WORDDATA_ARG */
    110     case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
    111     case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
    112     case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
    113 
    114         /* Fill in constant or string argument directly */
    115 
    116         AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
    117             GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
    118         break;
    119 
    120     case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */
    121 
    122         Status = AcpiPsGetNextNamepath (WalkState, &(WalkState->ParserState), Op, 1);
    123         if (ACPI_FAILURE (Status))
    124         {
    125             return_ACPI_STATUS (Status);
    126         }
    127 
    128         WalkState->ArgTypes = 0;
    129         break;
    130 
    131     default:
    132         /*
    133          * Op is not a constant or string, append each argument to the Op
    134          */
    135         while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && !WalkState->ArgCount)
    136         {
    137             WalkState->AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->ParserState.Aml,
    138                 WalkState->ParserState.AmlStart);
    139 
    140             Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
    141                         GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
    142             if (ACPI_FAILURE (Status))
    143             {
    144                 return_ACPI_STATUS (Status);
    145             }
    146 
    147             if (Arg)
    148             {
    149                 Arg->Common.AmlOffset = WalkState->AmlOffset;
    150                 AcpiPsAppendArg (Op, Arg);
    151             }
    152 
    153             INCREMENT_ARG_LIST (WalkState->ArgTypes);
    154         }
    155 
    156 
    157         /*
    158          * Handle executable code at "module-level". This refers to
    159          * executable opcodes that appear outside of any control method.
    160          */
    161         if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
    162             ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
    163         {
    164             /*
    165              * We want to skip If/Else/While constructs during Pass1 because we
    166              * want to actually conditionally execute the code during Pass2.
    167              *
    168              * Except for disassembly, where we always want to walk the
    169              * If/Else/While packages
    170              */
    171             switch (Op->Common.AmlOpcode)
    172             {
    173             case AML_IF_OP:
    174             case AML_ELSE_OP:
    175             case AML_WHILE_OP:
    176                 /*
    177                  * Currently supported module-level opcodes are:
    178                  * IF/ELSE/WHILE. These appear to be the most common,
    179                  * and easiest to support since they open an AML
    180                  * package.
    181                  */
    182                 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
    183                 {
    184                     AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
    185                         (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
    186                         WalkState->OwnerId);
    187                 }
    188 
    189                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
    190                     "Pass1: Skipping an If/Else/While body\n"));
    191 
    192                 /* Skip body of if/else/while in pass 1 */
    193 
    194                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
    195                 WalkState->ArgCount = 0;
    196                 break;
    197 
    198             default:
    199                 /*
    200                  * Check for an unsupported executable opcode at module
    201                  * level. We must be in PASS1, the parent must be a SCOPE,
    202                  * The opcode class must be EXECUTE, and the opcode must
    203                  * not be an argument to another opcode.
    204                  */
    205                 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
    206                     (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
    207                 {
    208                     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
    209                     if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
    210                         (!Arg))
    211                     {
    212                         ACPI_WARNING ((AE_INFO,
    213                             "Unsupported module-level executable opcode "
    214                             "0x%.2X at table offset 0x%.4X",
    215                             Op->Common.AmlOpcode,
    216                             (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
    217                                 WalkState->ParserState.AmlStart) +
    218                                 sizeof (ACPI_TABLE_HEADER))));
    219                     }
    220                 }
    221                 break;
    222             }
    223         }
    224 
    225         /* Special processing for certain opcodes */
    226 
    227         switch (Op->Common.AmlOpcode)
    228         {
    229         case AML_METHOD_OP:
    230             /*
    231              * Skip parsing of control method because we don't have enough
    232              * info in the first pass to parse it correctly.
    233              *
    234              * Save the length and address of the body
    235              */
    236             Op->Named.Data = WalkState->ParserState.Aml;
    237             Op->Named.Length = (UINT32)
    238                 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);
    239 
    240             /* Skip body of method */
    241 
    242             WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
    243             WalkState->ArgCount = 0;
    244             break;
    245 
    246         case AML_BUFFER_OP:
    247         case AML_PACKAGE_OP:
    248         case AML_VAR_PACKAGE_OP:
    249 
    250             if ((Op->Common.Parent) &&
    251                 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
    252                 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
    253             {
    254                 /*
    255                  * Skip parsing of Buffers and Packages because we don't have
    256                  * enough info in the first pass to parse them correctly.
    257                  */
    258                 Op->Named.Data = AmlOpStart;
    259                 Op->Named.Length = (UINT32)
    260                     (WalkState->ParserState.PkgEnd - AmlOpStart);
    261 
    262                 /* Skip body */
    263 
    264                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
    265                 WalkState->ArgCount = 0;
    266             }
    267             break;
    268 
    269         case AML_WHILE_OP:
    270 
    271             if (WalkState->ControlState)
    272             {
    273                 WalkState->ControlState->Control.PackageEnd =
    274                     WalkState->ParserState.PkgEnd;
    275             }
    276             break;
    277 
    278         default:
    279 
    280             /* No action for all other opcodes */
    281 
    282             break;
    283         }
    284 
    285         break;
    286     }
    287 
    288     return_ACPI_STATUS (AE_OK);
    289 }
    290 
    291 
    292 /*******************************************************************************
    293  *
    294  * FUNCTION:    AcpiPsLinkModuleCode
    295  *
    296  * PARAMETERS:  ParentOp            - Parent parser op
    297  *              AmlStart            - Pointer to the AML
    298  *              AmlLength           - Length of executable AML
    299  *              OwnerId             - OwnerId of module level code
    300  *
    301  * RETURN:      None.
    302  *
    303  * DESCRIPTION: Wrap the module-level code with a method object and link the
    304  *              object to the global list. Note, the mutex field of the method
    305  *              object is used to link multiple module-level code objects.
    306  *
    307  ******************************************************************************/
    308 
    309 static void
    310 AcpiPsLinkModuleCode (
    311     ACPI_PARSE_OBJECT       *ParentOp,
    312     UINT8                   *AmlStart,
    313     UINT32                  AmlLength,
    314     ACPI_OWNER_ID           OwnerId)
    315 {
    316     ACPI_OPERAND_OBJECT     *Prev;
    317     ACPI_OPERAND_OBJECT     *Next;
    318     ACPI_OPERAND_OBJECT     *MethodObj;
    319     ACPI_NAMESPACE_NODE     *ParentNode;
    320 
    321 
    322     /* Get the tail of the list */
    323 
    324     Prev = Next = AcpiGbl_ModuleCodeList;
    325     while (Next)
    326     {
    327         Prev = Next;
    328         Next = Next->Method.Mutex;
    329     }
    330 
    331     /*
    332      * Insert the module level code into the list. Merge it if it is
    333      * adjacent to the previous element.
    334      */
    335     if (!Prev ||
    336        ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
    337     {
    338         /* Create, initialize, and link a new temporary method object */
    339 
    340         MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
    341         if (!MethodObj)
    342         {
    343             return;
    344         }
    345 
    346         if (ParentOp->Common.Node)
    347         {
    348             ParentNode = ParentOp->Common.Node;
    349         }
    350         else
    351         {
    352             ParentNode = AcpiGbl_RootNode;
    353         }
    354 
    355         MethodObj->Method.AmlStart = AmlStart;
    356         MethodObj->Method.AmlLength = AmlLength;
    357         MethodObj->Method.OwnerId = OwnerId;
    358         MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL;
    359 
    360         /*
    361          * Save the parent node in NextObject. This is cheating, but we
    362          * don't want to expand the method object.
    363          */
    364         MethodObj->Method.NextObject =
    365             ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode);
    366 
    367         if (!Prev)
    368         {
    369             AcpiGbl_ModuleCodeList = MethodObj;
    370         }
    371         else
    372         {
    373             Prev->Method.Mutex = MethodObj;
    374         }
    375     }
    376     else
    377     {
    378         Prev->Method.AmlLength += AmlLength;
    379     }
    380 }
    381 
    382 /*******************************************************************************
    383  *
    384  * FUNCTION:    AcpiPsParseLoop
    385  *
    386  * PARAMETERS:  WalkState           - Current state
    387  *
    388  * RETURN:      Status
    389  *
    390  * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
    391  *              a tree of ops.
    392  *
    393  ******************************************************************************/
    394 
    395 ACPI_STATUS
    396 AcpiPsParseLoop (
    397     ACPI_WALK_STATE         *WalkState)
    398 {
    399     ACPI_STATUS             Status = AE_OK;
    400     ACPI_PARSE_OBJECT       *Op = NULL;     /* current op */
    401     ACPI_PARSE_STATE        *ParserState;
    402     UINT8                   *AmlOpStart = NULL;
    403 
    404 
    405     ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);
    406 
    407 
    408     if (WalkState->DescendingCallback == NULL)
    409     {
    410         return_ACPI_STATUS (AE_BAD_PARAMETER);
    411     }
    412 
    413     ParserState = &WalkState->ParserState;
    414     WalkState->ArgTypes = 0;
    415 
    416 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
    417 
    418     if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)
    419     {
    420         /* We are restarting a preempted control method */
    421 
    422         if (AcpiPsHasCompletedScope (ParserState))
    423         {
    424             /*
    425              * We must check if a predicate to an IF or WHILE statement
    426              * was just completed
    427              */
    428             if ((ParserState->Scope->ParseScope.Op) &&
    429                ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||
    430                 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&
    431                 (WalkState->ControlState) &&
    432                 (WalkState->ControlState->Common.State ==
    433                     ACPI_CONTROL_PREDICATE_EXECUTING))
    434             {
    435                 /*
    436                  * A predicate was just completed, get the value of the
    437                  * predicate and branch based on that value
    438                  */
    439                 WalkState->Op = NULL;
    440                 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));
    441                 if (ACPI_FAILURE (Status) &&
    442                     ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
    443                 {
    444                     if (Status == AE_AML_NO_RETURN_VALUE)
    445                     {
    446                         ACPI_EXCEPTION ((AE_INFO, Status,
    447                             "Invoked method did not return a value"));
    448                     }
    449 
    450                     ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));
    451                     return_ACPI_STATUS (Status);
    452                 }
    453 
    454                 Status = AcpiPsNextParseState (WalkState, Op, Status);
    455             }
    456 
    457             AcpiPsPopScope (ParserState, &Op,
    458                 &WalkState->ArgTypes, &WalkState->ArgCount);
    459             ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
    460         }
    461         else if (WalkState->PrevOp)
    462         {
    463             /* We were in the middle of an op */
    464 
    465             Op = WalkState->PrevOp;
    466             WalkState->ArgTypes = WalkState->PrevArgTypes;
    467         }
    468     }
    469 #endif
    470 
    471     /* Iterative parsing loop, while there is more AML to process: */
    472 
    473     while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
    474     {
    475         AmlOpStart = ParserState->Aml;
    476         if (!Op)
    477         {
    478             Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
    479             if (ACPI_FAILURE (Status))
    480             {
    481                 if (Status == AE_CTRL_PARSE_CONTINUE)
    482                 {
    483                     continue;
    484                 }
    485 
    486                 if (Status == AE_CTRL_PARSE_PENDING)
    487                 {
    488                     Status = AE_OK;
    489                 }
    490 
    491                 if (Status == AE_CTRL_TERMINATE)
    492                 {
    493                     return_ACPI_STATUS (Status);
    494                 }
    495 
    496                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
    497                 if (ACPI_FAILURE (Status))
    498                 {
    499                     return_ACPI_STATUS (Status);
    500                 }
    501 
    502                 continue;
    503             }
    504 
    505             Op->Common.AmlOffset = WalkState->AmlOffset;
    506 
    507             if (WalkState->OpInfo)
    508             {
    509                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
    510                     "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n",
    511                      (UINT32) Op->Common.AmlOpcode, WalkState->OpInfo->Name,
    512                      Op, ParserState->Aml, Op->Common.AmlOffset));
    513             }
    514         }
    515 
    516 
    517         /*
    518          * Start ArgCount at zero because we don't know if there are
    519          * any args yet
    520          */
    521         WalkState->ArgCount  = 0;
    522 
    523         /* Are there any arguments that must be processed? */
    524 
    525         if (WalkState->ArgTypes)
    526         {
    527             /* Get arguments */
    528 
    529             Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);
    530             if (ACPI_FAILURE (Status))
    531             {
    532                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
    533                 if (ACPI_FAILURE (Status))
    534                 {
    535                     return_ACPI_STATUS (Status);
    536                 }
    537 
    538                 continue;
    539             }
    540         }
    541 
    542         /* Check for arguments that need to be processed */
    543 
    544         if (WalkState->ArgCount)
    545         {
    546             /*
    547              * There are arguments (complex ones), push Op and
    548              * prepare for argument
    549              */
    550             Status = AcpiPsPushScope (ParserState, Op,
    551                         WalkState->ArgTypes, WalkState->ArgCount);
    552             if (ACPI_FAILURE (Status))
    553             {
    554                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
    555                 if (ACPI_FAILURE (Status))
    556                 {
    557                     return_ACPI_STATUS (Status);
    558                 }
    559 
    560                 continue;
    561             }
    562 
    563             Op = NULL;
    564             continue;
    565         }
    566 
    567         /*
    568          * All arguments have been processed -- Op is complete,
    569          * prepare for next
    570          */
    571         WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
    572         if (WalkState->OpInfo->Flags & AML_NAMED)
    573         {
    574             if (Op->Common.AmlOpcode == AML_REGION_OP ||
    575                 Op->Common.AmlOpcode == AML_DATA_REGION_OP)
    576             {
    577                 /*
    578                  * Skip parsing of control method or opregion body,
    579                  * because we don't have enough info in the first pass
    580                  * to parse them correctly.
    581                  *
    582                  * Completed parsing an OpRegion declaration, we now
    583                  * know the length.
    584                  */
    585                 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
    586             }
    587         }
    588 
    589         if (WalkState->OpInfo->Flags & AML_CREATE)
    590         {
    591             /*
    592              * Backup to beginning of CreateXXXfield declaration (1 for
    593              * Opcode)
    594              *
    595              * BodyLength is unknown until we parse the body
    596              */
    597             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
    598         }
    599 
    600         if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)
    601         {
    602             /*
    603              * Backup to beginning of BankField declaration
    604              *
    605              * BodyLength is unknown until we parse the body
    606              */
    607             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
    608         }
    609 
    610         /* This op complete, notify the dispatcher */
    611 
    612         if (WalkState->AscendingCallback != NULL)
    613         {
    614             WalkState->Op = Op;
    615             WalkState->Opcode = Op->Common.AmlOpcode;
    616 
    617             Status = WalkState->AscendingCallback (WalkState);
    618             Status = AcpiPsNextParseState (WalkState, Op, Status);
    619             if (Status == AE_CTRL_PENDING)
    620             {
    621                 Status = AE_OK;
    622             }
    623         }
    624 
    625         Status = AcpiPsCompleteOp (WalkState, &Op, Status);
    626         if (ACPI_FAILURE (Status))
    627         {
    628             return_ACPI_STATUS (Status);
    629         }
    630 
    631     } /* while ParserState->Aml */
    632 
    633     Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);
    634     return_ACPI_STATUS (Status);
    635 }
    636