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