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