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