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