1 /****************************************************************************** 2 * 3 * Module Name: psloop - Main AML parse loop 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2018, 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 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 178 "Final argument count: %8.8X pass %u\n", 179 WalkState->ArgCount, WalkState->PassNumber)); 180 181 /* 182 * This case handles the legacy option that groups all module-level 183 * code blocks together and defers execution until all of the tables 184 * are loaded. Execute all of these blocks at this time. 185 * Execute any module-level code that was detected during the table 186 * load phase. 187 * 188 * Note: this option is deprecated and will be eliminated in the 189 * future. Use of this option can cause problems with AML code that 190 * depends upon in-order immediate execution of module-level code. 191 */ 192 if (AcpiGbl_GroupModuleLevelCode && 193 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) && 194 ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0)) 195 { 196 /* 197 * We want to skip If/Else/While constructs during Pass1 because we 198 * want to actually conditionally execute the code during Pass2. 199 * 200 * Except for disassembly, where we always want to walk the 201 * If/Else/While packages 202 */ 203 switch (Op->Common.AmlOpcode) 204 { 205 case AML_IF_OP: 206 case AML_ELSE_OP: 207 case AML_WHILE_OP: 208 /* 209 * Currently supported module-level opcodes are: 210 * IF/ELSE/WHILE. These appear to be the most common, 211 * and easiest to support since they open an AML 212 * package. 213 */ 214 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) 215 { 216 AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart, 217 (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart), 218 WalkState->OwnerId); 219 } 220 221 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 222 "Pass1: Skipping an If/Else/While body\n")); 223 224 /* Skip body of if/else/while in pass 1 */ 225 226 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 227 WalkState->ArgCount = 0; 228 break; 229 230 default: 231 /* 232 * Check for an unsupported executable opcode at module 233 * level. We must be in PASS1, the parent must be a SCOPE, 234 * The opcode class must be EXECUTE, and the opcode must 235 * not be an argument to another opcode. 236 */ 237 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) && 238 (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) 239 { 240 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 241 if ((OpInfo->Class == AML_CLASS_EXECUTE) && 242 (!Arg)) 243 { 244 ACPI_WARNING ((AE_INFO, 245 "Unsupported module-level executable opcode " 246 "0x%.2X at table offset 0x%.4X", 247 Op->Common.AmlOpcode, 248 (UINT32) (ACPI_PTR_DIFF (AmlOpStart, 249 WalkState->ParserState.AmlStart) + 250 sizeof (ACPI_TABLE_HEADER)))); 251 } 252 } 253 break; 254 } 255 } 256 257 /* Special processing for certain opcodes */ 258 259 switch (Op->Common.AmlOpcode) 260 { 261 case AML_METHOD_OP: 262 /* 263 * Skip parsing of control method because we don't have enough 264 * info in the first pass to parse it correctly. 265 * 266 * Save the length and address of the body 267 */ 268 Op->Named.Data = WalkState->ParserState.Aml; 269 Op->Named.Length = (UINT32) 270 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml); 271 272 /* Skip body of method */ 273 274 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 275 WalkState->ArgCount = 0; 276 break; 277 278 case AML_BUFFER_OP: 279 case AML_PACKAGE_OP: 280 case AML_VARIABLE_PACKAGE_OP: 281 282 if ((Op->Common.Parent) && 283 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 284 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 285 { 286 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 287 "Setup Package/Buffer: Pass %u, AML Ptr: %p\n", 288 WalkState->PassNumber, AmlOpStart)); 289 290 /* 291 * Skip parsing of Buffers and Packages because we don't have 292 * enough info in the first pass to parse them correctly. 293 */ 294 Op->Named.Data = AmlOpStart; 295 Op->Named.Length = (UINT32) 296 (WalkState->ParserState.PkgEnd - AmlOpStart); 297 298 /* Skip body */ 299 300 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; 301 WalkState->ArgCount = 0; 302 } 303 break; 304 305 case AML_WHILE_OP: 306 307 if (WalkState->ControlState) 308 { 309 WalkState->ControlState->Control.PackageEnd = 310 WalkState->ParserState.PkgEnd; 311 } 312 break; 313 314 default: 315 316 /* No action for all other opcodes */ 317 318 break; 319 } 320 321 break; 322 } 323 324 return_ACPI_STATUS (AE_OK); 325 } 326 327 328 /******************************************************************************* 329 * 330 * FUNCTION: AcpiPsLinkModuleCode 331 * 332 * PARAMETERS: ParentOp - Parent parser op 333 * AmlStart - Pointer to the AML 334 * AmlLength - Length of executable AML 335 * OwnerId - OwnerId of module level code 336 * 337 * RETURN: None. 338 * 339 * DESCRIPTION: Wrap the module-level code with a method object and link the 340 * object to the global list. Note, the mutex field of the method 341 * object is used to link multiple module-level code objects. 342 * 343 * NOTE: In this legacy option, each block of detected executable AML 344 * code that is outside of any control method is wrapped with a temporary 345 * control method object and placed on a global list below. 346 * 347 * This function executes the module-level code for all tables only after 348 * all of the tables have been loaded. It is a legacy option and is 349 * not compatible with other ACPI implementations. See AcpiNsLoadTable. 350 * 351 * This function will be removed when the legacy option is removed. 352 * 353 ******************************************************************************/ 354 355 static void 356 AcpiPsLinkModuleCode ( 357 ACPI_PARSE_OBJECT *ParentOp, 358 UINT8 *AmlStart, 359 UINT32 AmlLength, 360 ACPI_OWNER_ID OwnerId) 361 { 362 ACPI_OPERAND_OBJECT *Prev; 363 ACPI_OPERAND_OBJECT *Next; 364 ACPI_OPERAND_OBJECT *MethodObj; 365 ACPI_NAMESPACE_NODE *ParentNode; 366 367 368 ACPI_FUNCTION_TRACE (PsLinkModuleCode); 369 370 371 /* Get the tail of the list */ 372 373 Prev = Next = AcpiGbl_ModuleCodeList; 374 while (Next) 375 { 376 Prev = Next; 377 Next = Next->Method.Mutex; 378 } 379 380 /* 381 * Insert the module level code into the list. Merge it if it is 382 * adjacent to the previous element. 383 */ 384 if (!Prev || 385 ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart)) 386 { 387 /* Create, initialize, and link a new temporary method object */ 388 389 MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); 390 if (!MethodObj) 391 { 392 return_VOID; 393 } 394 395 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 396 "Create/Link new code block: %p\n", MethodObj)); 397 398 if (ParentOp->Common.Node) 399 { 400 ParentNode = ParentOp->Common.Node; 401 } 402 else 403 { 404 ParentNode = AcpiGbl_RootNode; 405 } 406 407 MethodObj->Method.AmlStart = AmlStart; 408 MethodObj->Method.AmlLength = AmlLength; 409 MethodObj->Method.OwnerId = OwnerId; 410 MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL; 411 412 /* 413 * Save the parent node in NextObject. This is cheating, but we 414 * don't want to expand the method object. 415 */ 416 MethodObj->Method.NextObject = 417 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode); 418 419 if (!Prev) 420 { 421 AcpiGbl_ModuleCodeList = MethodObj; 422 } 423 else 424 { 425 Prev->Method.Mutex = MethodObj; 426 } 427 } 428 else 429 { 430 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 431 "Appending to existing code block: %p\n", Prev)); 432 433 Prev->Method.AmlLength += AmlLength; 434 } 435 436 return_VOID; 437 } 438 439 /******************************************************************************* 440 * 441 * FUNCTION: AcpiPsParseLoop 442 * 443 * PARAMETERS: WalkState - Current state 444 * 445 * RETURN: Status 446 * 447 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return 448 * a tree of ops. 449 * 450 ******************************************************************************/ 451 452 ACPI_STATUS 453 AcpiPsParseLoop ( 454 ACPI_WALK_STATE *WalkState) 455 { 456 ACPI_STATUS Status = AE_OK; 457 ACPI_PARSE_OBJECT *Op = NULL; /* current op */ 458 ACPI_PARSE_STATE *ParserState; 459 UINT8 *AmlOpStart = NULL; 460 461 462 ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState); 463 464 465 if (WalkState->DescendingCallback == NULL) 466 { 467 return_ACPI_STATUS (AE_BAD_PARAMETER); 468 } 469 470 ParserState = &WalkState->ParserState; 471 WalkState->ArgTypes = 0; 472 473 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) 474 475 if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART) 476 { 477 /* We are restarting a preempted control method */ 478 479 if (AcpiPsHasCompletedScope (ParserState)) 480 { 481 /* 482 * We must check if a predicate to an IF or WHILE statement 483 * was just completed 484 */ 485 if ((ParserState->Scope->ParseScope.Op) && 486 ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) || 487 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) && 488 (WalkState->ControlState) && 489 (WalkState->ControlState->Common.State == 490 ACPI_CONTROL_PREDICATE_EXECUTING)) 491 { 492 /* 493 * A predicate was just completed, get the value of the 494 * predicate and branch based on that value 495 */ 496 WalkState->Op = NULL; 497 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE)); 498 if (ACPI_FAILURE (Status) && 499 ((Status & AE_CODE_MASK) != AE_CODE_CONTROL)) 500 { 501 if (Status == AE_AML_NO_RETURN_VALUE) 502 { 503 ACPI_EXCEPTION ((AE_INFO, Status, 504 "Invoked method did not return a value")); 505 } 506 507 ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed")); 508 return_ACPI_STATUS (Status); 509 } 510 511 Status = AcpiPsNextParseState (WalkState, Op, Status); 512 } 513 514 AcpiPsPopScope (ParserState, &Op, 515 &WalkState->ArgTypes, &WalkState->ArgCount); 516 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op)); 517 } 518 else if (WalkState->PrevOp) 519 { 520 /* We were in the middle of an op */ 521 522 Op = WalkState->PrevOp; 523 WalkState->ArgTypes = WalkState->PrevArgTypes; 524 } 525 } 526 #endif 527 528 /* Iterative parsing loop, while there is more AML to process: */ 529 530 while ((ParserState->Aml < ParserState->AmlEnd) || (Op)) 531 { 532 ASL_CV_CAPTURE_COMMENTS (WalkState); 533 534 AmlOpStart = ParserState->Aml; 535 if (!Op) 536 { 537 Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op); 538 if (ACPI_FAILURE (Status)) 539 { 540 if (Status == AE_CTRL_PARSE_CONTINUE) 541 { 542 continue; 543 } 544 545 if (Status == AE_CTRL_PARSE_PENDING) 546 { 547 Status = AE_OK; 548 } 549 550 if (Status == AE_CTRL_TERMINATE) 551 { 552 return_ACPI_STATUS (Status); 553 } 554 555 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 556 if (ACPI_FAILURE (Status)) 557 { 558 return_ACPI_STATUS (Status); 559 } 560 561 continue; 562 } 563 564 AcpiExStartTraceOpcode (Op, WalkState); 565 } 566 567 /* 568 * Start ArgCount at zero because we don't know if there are 569 * any args yet 570 */ 571 WalkState->ArgCount = 0; 572 573 switch (Op->Common.AmlOpcode) 574 { 575 case AML_BYTE_OP: 576 case AML_WORD_OP: 577 case AML_DWORD_OP: 578 case AML_QWORD_OP: 579 580 break; 581 582 default: 583 584 ASL_CV_CAPTURE_COMMENTS (WalkState); 585 break; 586 } 587 588 /* Are there any arguments that must be processed? */ 589 590 if (WalkState->ArgTypes) 591 { 592 /* Get arguments */ 593 594 Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op); 595 if (ACPI_FAILURE (Status)) 596 { 597 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 598 if (ACPI_FAILURE (Status)) 599 { 600 return_ACPI_STATUS (Status); 601 } 602 603 continue; 604 } 605 } 606 607 /* Check for arguments that need to be processed */ 608 609 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 610 "Parseloop: argument count: %8.8X\n", WalkState->ArgCount)); 611 612 if (WalkState->ArgCount) 613 { 614 /* 615 * There are arguments (complex ones), push Op and 616 * prepare for argument 617 */ 618 Status = AcpiPsPushScope (ParserState, Op, 619 WalkState->ArgTypes, WalkState->ArgCount); 620 if (ACPI_FAILURE (Status)) 621 { 622 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 623 if (ACPI_FAILURE (Status)) 624 { 625 return_ACPI_STATUS (Status); 626 } 627 628 continue; 629 } 630 631 Op = NULL; 632 continue; 633 } 634 635 /* 636 * All arguments have been processed -- Op is complete, 637 * prepare for next 638 */ 639 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 640 if (WalkState->OpInfo->Flags & AML_NAMED) 641 { 642 if (Op->Common.AmlOpcode == AML_REGION_OP || 643 Op->Common.AmlOpcode == AML_DATA_REGION_OP) 644 { 645 /* 646 * Skip parsing of control method or opregion body, 647 * because we don't have enough info in the first pass 648 * to parse them correctly. 649 * 650 * Completed parsing an OpRegion declaration, we now 651 * know the length. 652 */ 653 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 654 } 655 } 656 657 if (WalkState->OpInfo->Flags & AML_CREATE) 658 { 659 /* 660 * Backup to beginning of CreateXXXfield declaration (1 for 661 * Opcode) 662 * 663 * BodyLength is unknown until we parse the body 664 */ 665 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 666 } 667 668 if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP) 669 { 670 /* 671 * Backup to beginning of BankField declaration 672 * 673 * BodyLength is unknown until we parse the body 674 */ 675 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); 676 } 677 678 /* This op complete, notify the dispatcher */ 679 680 if (WalkState->AscendingCallback != NULL) 681 { 682 WalkState->Op = Op; 683 WalkState->Opcode = Op->Common.AmlOpcode; 684 685 Status = WalkState->AscendingCallback (WalkState); 686 Status = AcpiPsNextParseState (WalkState, Op, Status); 687 if (Status == AE_CTRL_PENDING) 688 { 689 Status = AE_OK; 690 } 691 } 692 693 Status = AcpiPsCompleteOp (WalkState, &Op, Status); 694 if (ACPI_FAILURE (Status)) 695 { 696 return_ACPI_STATUS (Status); 697 } 698 699 } /* while ParserState->Aml */ 700 701 Status = AcpiPsCompleteFinalOp (WalkState, Op, Status); 702 return_ACPI_STATUS (Status); 703 } 704