1 /****************************************************************************** 2 * 3 * Module Name: psparse - Parser top level AML parse routines 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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, 46 * like Perl, do. Parsing is done by hand rather than with a YACC 47 * generated parser to tightly constrain stack and dynamic memory 48 * usage. At the same time, parsing is kept flexible and the code 49 * fairly compact by parsing based on a list of AML opcode 50 * 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 #include "acinterp.h" 59 #include "acnamesp.h" 60 61 #define _COMPONENT ACPI_PARSER 62 ACPI_MODULE_NAME ("psparse") 63 64 65 /******************************************************************************* 66 * 67 * FUNCTION: AcpiPsGetOpcodeSize 68 * 69 * PARAMETERS: Opcode - An AML opcode 70 * 71 * RETURN: Size of the opcode, in bytes (1 or 2) 72 * 73 * DESCRIPTION: Get the size of the current opcode. 74 * 75 ******************************************************************************/ 76 77 UINT32 78 AcpiPsGetOpcodeSize ( 79 UINT32 Opcode) 80 { 81 82 /* Extended (2-byte) opcode if > 255 */ 83 84 if (Opcode > 0x00FF) 85 { 86 return (2); 87 } 88 89 /* Otherwise, just a single byte opcode */ 90 91 return (1); 92 } 93 94 95 /******************************************************************************* 96 * 97 * FUNCTION: AcpiPsPeekOpcode 98 * 99 * PARAMETERS: ParserState - A parser state object 100 * 101 * RETURN: Next AML opcode 102 * 103 * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) 104 * 105 ******************************************************************************/ 106 107 UINT16 108 AcpiPsPeekOpcode ( 109 ACPI_PARSE_STATE *ParserState) 110 { 111 UINT8 *Aml; 112 UINT16 Opcode; 113 114 115 Aml = ParserState->Aml; 116 Opcode = (UINT16) ACPI_GET8 (Aml); 117 118 if (Opcode == AML_EXTENDED_PREFIX) 119 { 120 /* Extended opcode, get the second opcode byte */ 121 122 Aml++; 123 Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml)); 124 } 125 126 return (Opcode); 127 } 128 129 130 /******************************************************************************* 131 * 132 * FUNCTION: AcpiPsCompleteThisOp 133 * 134 * PARAMETERS: WalkState - Current State 135 * Op - Op to complete 136 * 137 * RETURN: Status 138 * 139 * DESCRIPTION: Perform any cleanup at the completion of an Op. 140 * 141 ******************************************************************************/ 142 143 ACPI_STATUS 144 AcpiPsCompleteThisOp ( 145 ACPI_WALK_STATE *WalkState, 146 ACPI_PARSE_OBJECT *Op) 147 { 148 ACPI_PARSE_OBJECT *Prev; 149 ACPI_PARSE_OBJECT *Next; 150 const ACPI_OPCODE_INFO *ParentInfo; 151 ACPI_PARSE_OBJECT *ReplacementOp = NULL; 152 ACPI_STATUS Status = AE_OK; 153 154 155 ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op); 156 157 158 /* Check for null Op, can happen if AML code is corrupt */ 159 160 if (!Op) 161 { 162 return_ACPI_STATUS (AE_OK); /* OK for now */ 163 } 164 165 AcpiExStopTraceOpcode (Op, WalkState); 166 167 /* Delete this op and the subtree below it if asked to */ 168 169 if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || 170 (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT)) 171 { 172 return_ACPI_STATUS (AE_OK); 173 } 174 175 /* Make sure that we only delete this subtree */ 176 177 if (Op->Common.Parent) 178 { 179 Prev = Op->Common.Parent->Common.Value.Arg; 180 if (!Prev) 181 { 182 /* Nothing more to do */ 183 184 goto Cleanup; 185 } 186 187 /* 188 * Check if we need to replace the operator and its subtree 189 * with a return value op (placeholder op) 190 */ 191 ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); 192 193 switch (ParentInfo->Class) 194 { 195 case AML_CLASS_CONTROL: 196 197 break; 198 199 case AML_CLASS_CREATE: 200 /* 201 * These opcodes contain TermArg operands. The current 202 * op must be replaced by a placeholder return op 203 */ 204 ReplacementOp = AcpiPsAllocOp ( 205 AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 206 if (!ReplacementOp) 207 { 208 Status = AE_NO_MEMORY; 209 } 210 break; 211 212 case AML_CLASS_NAMED_OBJECT: 213 /* 214 * These opcodes contain TermArg operands. The current 215 * op must be replaced by a placeholder return op 216 */ 217 if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || 218 (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || 219 (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || 220 (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || 221 (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || 222 (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)) 223 { 224 ReplacementOp = AcpiPsAllocOp ( 225 AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 226 if (!ReplacementOp) 227 { 228 Status = AE_NO_MEMORY; 229 } 230 } 231 else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 232 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 233 { 234 if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || 235 (Op->Common.AmlOpcode == AML_PACKAGE_OP) || 236 (Op->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)) 237 { 238 ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode, 239 Op->Common.Aml); 240 if (!ReplacementOp) 241 { 242 Status = AE_NO_MEMORY; 243 } 244 else 245 { 246 ReplacementOp->Named.Data = Op->Named.Data; 247 ReplacementOp->Named.Length = Op->Named.Length; 248 } 249 } 250 } 251 break; 252 253 default: 254 255 ReplacementOp = AcpiPsAllocOp ( 256 AML_INT_RETURN_VALUE_OP, Op->Common.Aml); 257 if (!ReplacementOp) 258 { 259 Status = AE_NO_MEMORY; 260 } 261 } 262 263 /* We must unlink this op from the parent tree */ 264 265 if (Prev == Op) 266 { 267 /* This op is the first in the list */ 268 269 if (ReplacementOp) 270 { 271 ReplacementOp->Common.Parent = Op->Common.Parent; 272 ReplacementOp->Common.Value.Arg = NULL; 273 ReplacementOp->Common.Node = Op->Common.Node; 274 Op->Common.Parent->Common.Value.Arg = ReplacementOp; 275 ReplacementOp->Common.Next = Op->Common.Next; 276 } 277 else 278 { 279 Op->Common.Parent->Common.Value.Arg = Op->Common.Next; 280 } 281 } 282 283 /* Search the parent list */ 284 285 else while (Prev) 286 { 287 /* Traverse all siblings in the parent's argument list */ 288 289 Next = Prev->Common.Next; 290 if (Next == Op) 291 { 292 if (ReplacementOp) 293 { 294 ReplacementOp->Common.Parent = Op->Common.Parent; 295 ReplacementOp->Common.Value.Arg = NULL; 296 ReplacementOp->Common.Node = Op->Common.Node; 297 Prev->Common.Next = ReplacementOp; 298 ReplacementOp->Common.Next = Op->Common.Next; 299 Next = NULL; 300 } 301 else 302 { 303 Prev->Common.Next = Op->Common.Next; 304 Next = NULL; 305 } 306 } 307 Prev = Next; 308 } 309 } 310 311 312 Cleanup: 313 314 /* Now we can actually delete the subtree rooted at Op */ 315 316 AcpiPsDeleteParseTree (Op); 317 return_ACPI_STATUS (Status); 318 } 319 320 321 /******************************************************************************* 322 * 323 * FUNCTION: AcpiPsNextParseState 324 * 325 * PARAMETERS: WalkState - Current state 326 * Op - Current parse op 327 * CallbackStatus - Status from previous operation 328 * 329 * RETURN: Status 330 * 331 * DESCRIPTION: Update the parser state based upon the return exception from 332 * the parser callback. 333 * 334 ******************************************************************************/ 335 336 ACPI_STATUS 337 AcpiPsNextParseState ( 338 ACPI_WALK_STATE *WalkState, 339 ACPI_PARSE_OBJECT *Op, 340 ACPI_STATUS CallbackStatus) 341 { 342 ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; 343 ACPI_STATUS Status = AE_CTRL_PENDING; 344 345 346 ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); 347 348 349 switch (CallbackStatus) 350 { 351 case AE_CTRL_TERMINATE: 352 /* 353 * A control method was terminated via a RETURN statement. 354 * The walk of this method is complete. 355 */ 356 ParserState->Aml = ParserState->AmlEnd; 357 Status = AE_CTRL_TERMINATE; 358 break; 359 360 case AE_CTRL_BREAK: 361 362 ParserState->Aml = WalkState->AmlLastWhile; 363 WalkState->ControlState->Common.Value = FALSE; 364 Status = AE_CTRL_BREAK; 365 break; 366 367 case AE_CTRL_CONTINUE: 368 369 ParserState->Aml = WalkState->AmlLastWhile; 370 Status = AE_CTRL_CONTINUE; 371 break; 372 373 case AE_CTRL_PENDING: 374 375 ParserState->Aml = WalkState->AmlLastWhile; 376 break; 377 378 #if 0 379 case AE_CTRL_SKIP: 380 381 ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 382 Status = AE_OK; 383 break; 384 #endif 385 386 case AE_CTRL_TRUE: 387 /* 388 * Predicate of an IF was true, and we are at the matching ELSE. 389 * Just close out this package 390 */ 391 ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); 392 Status = AE_CTRL_PENDING; 393 break; 394 395 case AE_CTRL_FALSE: 396 /* 397 * Either an IF/WHILE Predicate was false or we encountered a BREAK 398 * opcode. In both cases, we do not execute the rest of the 399 * package; We simply close out the parent (finishing the walk of 400 * this branch of the tree) and continue execution at the parent 401 * level. 402 */ 403 ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 404 405 /* In the case of a BREAK, just force a predicate (if any) to FALSE */ 406 407 WalkState->ControlState->Common.Value = FALSE; 408 Status = AE_CTRL_END; 409 break; 410 411 case AE_CTRL_TRANSFER: 412 413 /* A method call (invocation) -- transfer control */ 414 415 Status = AE_CTRL_TRANSFER; 416 WalkState->PrevOp = Op; 417 WalkState->MethodCallOp = Op; 418 WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node; 419 420 /* Will return value (if any) be used by the caller? */ 421 422 WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState); 423 break; 424 425 default: 426 427 Status = CallbackStatus; 428 if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) 429 { 430 Status = AE_OK; 431 } 432 break; 433 } 434 435 return_ACPI_STATUS (Status); 436 } 437 438 439 /******************************************************************************* 440 * 441 * FUNCTION: AcpiPsParseAml 442 * 443 * PARAMETERS: WalkState - Current state 444 * 445 * 446 * RETURN: Status 447 * 448 * DESCRIPTION: Parse raw AML and return a tree of ops 449 * 450 ******************************************************************************/ 451 452 ACPI_STATUS 453 AcpiPsParseAml ( 454 ACPI_WALK_STATE *WalkState) 455 { 456 ACPI_STATUS Status; 457 ACPI_THREAD_STATE *Thread; 458 ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; 459 ACPI_WALK_STATE *PreviousWalkState; 460 461 462 ACPI_FUNCTION_TRACE (PsParseAml); 463 464 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 465 "Entered with WalkState=%p Aml=%p size=%X\n", 466 WalkState, WalkState->ParserState.Aml, 467 WalkState->ParserState.AmlSize)); 468 469 if (!WalkState->ParserState.Aml) 470 { 471 return_ACPI_STATUS (AE_BAD_ADDRESS); 472 } 473 474 /* Create and initialize a new thread state */ 475 476 Thread = AcpiUtCreateThreadState (); 477 if (!Thread) 478 { 479 if (WalkState->MethodDesc) 480 { 481 /* Executing a control method - additional cleanup */ 482 483 AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 484 } 485 486 AcpiDsDeleteWalkState (WalkState); 487 return_ACPI_STATUS (AE_NO_MEMORY); 488 } 489 490 WalkState->Thread = Thread; 491 492 /* 493 * If executing a method, the starting SyncLevel is this method's 494 * SyncLevel 495 */ 496 if (WalkState->MethodDesc) 497 { 498 WalkState->Thread->CurrentSyncLevel = 499 WalkState->MethodDesc->Method.SyncLevel; 500 } 501 502 AcpiDsPushWalkState (WalkState, Thread); 503 504 /* 505 * This global allows the AML debugger to get a handle to the currently 506 * executing control method. 507 */ 508 AcpiGbl_CurrentWalkList = Thread; 509 510 /* 511 * Execute the walk loop as long as there is a valid Walk State. This 512 * handles nested control method invocations without recursion. 513 */ 514 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState)); 515 516 Status = AE_OK; 517 while (WalkState) 518 { 519 if (ACPI_SUCCESS (Status)) 520 { 521 /* 522 * The ParseLoop executes AML until the method terminates 523 * or calls another method. 524 */ 525 Status = AcpiPsParseLoop (WalkState); 526 } 527 528 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 529 "Completed one call to walk loop, %s State=%p\n", 530 AcpiFormatException (Status), WalkState)); 531 532 if (WalkState->MethodPathname && WalkState->MethodIsNested) 533 { 534 /* Optional object evaluation log */ 535 536 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION, "%-26s: %*s%s\n", 537 " Exit nested method", 538 (WalkState->MethodNestingDepth + 1) * 3, " ", 539 &WalkState->MethodPathname[1])); 540 541 ACPI_FREE (WalkState->MethodPathname); 542 WalkState->MethodIsNested = FALSE; 543 } 544 if (Status == AE_CTRL_TRANSFER) 545 { 546 /* 547 * A method call was detected. 548 * Transfer control to the called control method 549 */ 550 Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); 551 if (ACPI_FAILURE (Status)) 552 { 553 Status = AcpiDsMethodError (Status, WalkState); 554 } 555 556 /* 557 * If the transfer to the new method method call worked 558 *, a new walk state was created -- get it 559 */ 560 WalkState = AcpiDsGetCurrentWalkState (Thread); 561 continue; 562 } 563 else if (Status == AE_CTRL_TERMINATE) 564 { 565 Status = AE_OK; 566 } 567 else if ((Status != AE_OK) && (WalkState->MethodDesc)) 568 { 569 /* Either the method parse or actual execution failed */ 570 571 AcpiExExitInterpreter (); 572 if (Status == AE_ABORT_METHOD) 573 { 574 AcpiNsPrintNodePathname ( 575 WalkState->MethodNode, "Aborting method"); 576 AcpiOsPrintf ("\n"); 577 } 578 else 579 { 580 ACPI_ERROR_METHOD ("Aborting method", 581 WalkState->MethodNode, NULL, Status); 582 } 583 AcpiExEnterInterpreter (); 584 585 /* Check for possible multi-thread reentrancy problem */ 586 587 if ((Status == AE_ALREADY_EXISTS) && 588 (!(WalkState->MethodDesc->Method.InfoFlags & 589 ACPI_METHOD_SERIALIZED))) 590 { 591 /* 592 * Method is not serialized and tried to create an object 593 * twice. The probable cause is that the method cannot 594 * handle reentrancy. Mark as "pending serialized" now, and 595 * then mark "serialized" when the last thread exits. 596 */ 597 WalkState->MethodDesc->Method.InfoFlags |= 598 ACPI_METHOD_SERIALIZED_PENDING; 599 } 600 } 601 602 /* We are done with this walk, move on to the parent if any */ 603 604 WalkState = AcpiDsPopWalkState (Thread); 605 606 /* Reset the current scope to the beginning of scope stack */ 607 608 AcpiDsScopeStackClear (WalkState); 609 610 /* 611 * If we just returned from the execution of a control method or if we 612 * encountered an error during the method parse phase, there's lots of 613 * cleanup to do 614 */ 615 if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == 616 ACPI_PARSE_EXECUTE && 617 !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) || 618 (ACPI_FAILURE (Status))) 619 { 620 AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 621 } 622 623 /* Delete this walk state and all linked control states */ 624 625 AcpiPsCleanupScope (&WalkState->ParserState); 626 PreviousWalkState = WalkState; 627 628 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 629 "ReturnValue=%p, ImplicitValue=%p State=%p\n", 630 WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); 631 632 /* Check if we have restarted a preempted walk */ 633 634 WalkState = AcpiDsGetCurrentWalkState (Thread); 635 if (WalkState) 636 { 637 if (ACPI_SUCCESS (Status)) 638 { 639 /* 640 * There is another walk state, restart it. 641 * If the method return value is not used by the parent, 642 * The object is deleted 643 */ 644 if (!PreviousWalkState->ReturnDesc) 645 { 646 /* 647 * In slack mode execution, if there is no return value 648 * we should implicitly return zero (0) as a default value. 649 */ 650 if (AcpiGbl_EnableInterpreterSlack && 651 !PreviousWalkState->ImplicitReturnObj) 652 { 653 PreviousWalkState->ImplicitReturnObj = 654 AcpiUtCreateIntegerObject ((UINT64) 0); 655 if (!PreviousWalkState->ImplicitReturnObj) 656 { 657 return_ACPI_STATUS (AE_NO_MEMORY); 658 } 659 } 660 661 /* Restart the calling control method */ 662 663 Status = AcpiDsRestartControlMethod (WalkState, 664 PreviousWalkState->ImplicitReturnObj); 665 } 666 else 667 { 668 /* 669 * We have a valid return value, delete any implicit 670 * return value. 671 */ 672 AcpiDsClearImplicitReturn (PreviousWalkState); 673 674 Status = AcpiDsRestartControlMethod (WalkState, 675 PreviousWalkState->ReturnDesc); 676 } 677 if (ACPI_SUCCESS (Status)) 678 { 679 WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; 680 } 681 } 682 else 683 { 684 /* On error, delete any return object or implicit return */ 685 686 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 687 AcpiDsClearImplicitReturn (PreviousWalkState); 688 } 689 } 690 691 /* 692 * Just completed a 1st-level method, save the final internal return 693 * value (if any) 694 */ 695 else if (PreviousWalkState->CallerReturnDesc) 696 { 697 if (PreviousWalkState->ImplicitReturnObj) 698 { 699 *(PreviousWalkState->CallerReturnDesc) = 700 PreviousWalkState->ImplicitReturnObj; 701 } 702 else 703 { 704 /* NULL if no return value */ 705 706 *(PreviousWalkState->CallerReturnDesc) = 707 PreviousWalkState->ReturnDesc; 708 } 709 } 710 else 711 { 712 if (PreviousWalkState->ReturnDesc) 713 { 714 /* Caller doesn't want it, must delete it */ 715 716 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 717 } 718 if (PreviousWalkState->ImplicitReturnObj) 719 { 720 /* Caller doesn't want it, must delete it */ 721 722 AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); 723 } 724 } 725 726 AcpiDsDeleteWalkState (PreviousWalkState); 727 } 728 729 /* Normal exit */ 730 731 AcpiExReleaseAllMutexes (Thread); 732 AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); 733 AcpiGbl_CurrentWalkList = PrevWalkList; 734 return_ACPI_STATUS (Status); 735 } 736