1 /****************************************************************************** 2 * 3 * Module Name: psparse - Parser top level AML parse routines 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, 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 break; 195 196 case AML_CLASS_CREATE: 197 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 /* 212 * These opcodes contain TermArg operands. The current 213 * op must be replaced by a placeholder return op 214 */ 215 if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || 216 (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || 217 (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || 218 (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || 219 (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || 220 (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 221 { 222 ReplacementOp = AcpiPsAllocOp (AML_INT_RETURN_VALUE_OP); 223 if (!ReplacementOp) 224 { 225 Status = AE_NO_MEMORY; 226 } 227 } 228 else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && 229 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) 230 { 231 if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || 232 (Op->Common.AmlOpcode == AML_PACKAGE_OP) || 233 (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) 234 { 235 ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode); 236 if (!ReplacementOp) 237 { 238 Status = AE_NO_MEMORY; 239 } 240 else 241 { 242 ReplacementOp->Named.Data = Op->Named.Data; 243 ReplacementOp->Named.Length = Op->Named.Length; 244 } 245 } 246 } 247 break; 248 249 default: 250 251 ReplacementOp = AcpiPsAllocOp (AML_INT_RETURN_VALUE_OP); 252 if (!ReplacementOp) 253 { 254 Status = AE_NO_MEMORY; 255 } 256 } 257 258 /* We must unlink this op from the parent tree */ 259 260 if (Prev == Op) 261 { 262 /* This op is the first in the list */ 263 264 if (ReplacementOp) 265 { 266 ReplacementOp->Common.Parent = Op->Common.Parent; 267 ReplacementOp->Common.Value.Arg = NULL; 268 ReplacementOp->Common.Node = Op->Common.Node; 269 Op->Common.Parent->Common.Value.Arg = ReplacementOp; 270 ReplacementOp->Common.Next = Op->Common.Next; 271 } 272 else 273 { 274 Op->Common.Parent->Common.Value.Arg = Op->Common.Next; 275 } 276 } 277 278 /* Search the parent list */ 279 280 else while (Prev) 281 { 282 /* Traverse all siblings in the parent's argument list */ 283 284 Next = Prev->Common.Next; 285 if (Next == Op) 286 { 287 if (ReplacementOp) 288 { 289 ReplacementOp->Common.Parent = Op->Common.Parent; 290 ReplacementOp->Common.Value.Arg = NULL; 291 ReplacementOp->Common.Node = Op->Common.Node; 292 Prev->Common.Next = ReplacementOp; 293 ReplacementOp->Common.Next = Op->Common.Next; 294 Next = NULL; 295 } 296 else 297 { 298 Prev->Common.Next = Op->Common.Next; 299 Next = NULL; 300 } 301 } 302 Prev = Next; 303 } 304 } 305 306 307 Cleanup: 308 309 /* Now we can actually delete the subtree rooted at Op */ 310 311 AcpiPsDeleteParseTree (Op); 312 return_ACPI_STATUS (Status); 313 } 314 315 316 /******************************************************************************* 317 * 318 * FUNCTION: AcpiPsNextParseState 319 * 320 * PARAMETERS: WalkState - Current state 321 * Op - Current parse op 322 * CallbackStatus - Status from previous operation 323 * 324 * RETURN: Status 325 * 326 * DESCRIPTION: Update the parser state based upon the return exception from 327 * the parser callback. 328 * 329 ******************************************************************************/ 330 331 ACPI_STATUS 332 AcpiPsNextParseState ( 333 ACPI_WALK_STATE *WalkState, 334 ACPI_PARSE_OBJECT *Op, 335 ACPI_STATUS CallbackStatus) 336 { 337 ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; 338 ACPI_STATUS Status = AE_CTRL_PENDING; 339 340 341 ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); 342 343 344 switch (CallbackStatus) 345 { 346 case AE_CTRL_TERMINATE: 347 /* 348 * A control method was terminated via a RETURN statement. 349 * The walk of this method is complete. 350 */ 351 ParserState->Aml = ParserState->AmlEnd; 352 Status = AE_CTRL_TERMINATE; 353 break; 354 355 356 case AE_CTRL_BREAK: 357 358 ParserState->Aml = WalkState->AmlLastWhile; 359 WalkState->ControlState->Common.Value = FALSE; 360 Status = AE_CTRL_BREAK; 361 break; 362 363 364 case AE_CTRL_CONTINUE: 365 366 ParserState->Aml = WalkState->AmlLastWhile; 367 Status = AE_CTRL_CONTINUE; 368 break; 369 370 371 case AE_CTRL_PENDING: 372 373 ParserState->Aml = WalkState->AmlLastWhile; 374 break; 375 376 #if 0 377 case AE_CTRL_SKIP: 378 379 ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 380 Status = AE_OK; 381 break; 382 #endif 383 384 case AE_CTRL_TRUE: 385 /* 386 * Predicate of an IF was true, and we are at the matching ELSE. 387 * Just close out this package 388 */ 389 ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); 390 Status = AE_CTRL_PENDING; 391 break; 392 393 394 case AE_CTRL_FALSE: 395 /* 396 * Either an IF/WHILE Predicate was false or we encountered a BREAK 397 * opcode. In both cases, we do not execute the rest of the 398 * package; We simply close out the parent (finishing the walk of 399 * this branch of the tree) and continue execution at the parent 400 * level. 401 */ 402 ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; 403 404 /* In the case of a BREAK, just force a predicate (if any) to FALSE */ 405 406 WalkState->ControlState->Common.Value = FALSE; 407 Status = AE_CTRL_END; 408 break; 409 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 426 default: 427 428 Status = CallbackStatus; 429 if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) 430 { 431 Status = AE_OK; 432 } 433 break; 434 } 435 436 return_ACPI_STATUS (Status); 437 } 438 439 440 /******************************************************************************* 441 * 442 * FUNCTION: AcpiPsParseAml 443 * 444 * PARAMETERS: WalkState - Current state 445 * 446 * 447 * RETURN: Status 448 * 449 * DESCRIPTION: Parse raw AML and return a tree of ops 450 * 451 ******************************************************************************/ 452 453 ACPI_STATUS 454 AcpiPsParseAml ( 455 ACPI_WALK_STATE *WalkState) 456 { 457 ACPI_STATUS Status; 458 ACPI_THREAD_STATE *Thread; 459 ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; 460 ACPI_WALK_STATE *PreviousWalkState; 461 462 463 ACPI_FUNCTION_TRACE (PsParseAml); 464 465 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 466 "Entered with WalkState=%p Aml=%p size=%X\n", 467 WalkState, WalkState->ParserState.Aml, 468 WalkState->ParserState.AmlSize)); 469 470 if (!WalkState->ParserState.Aml) 471 { 472 return_ACPI_STATUS (AE_NULL_OBJECT); 473 } 474 475 /* Create and initialize a new thread state */ 476 477 Thread = AcpiUtCreateThreadState (); 478 if (!Thread) 479 { 480 if (WalkState->MethodDesc) 481 { 482 /* Executing a control method - additional cleanup */ 483 484 AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 485 } 486 487 AcpiDsDeleteWalkState (WalkState); 488 return_ACPI_STATUS (AE_NO_MEMORY); 489 } 490 491 WalkState->Thread = Thread; 492 493 /* 494 * If executing a method, the starting SyncLevel is this method's 495 * SyncLevel 496 */ 497 if (WalkState->MethodDesc) 498 { 499 WalkState->Thread->CurrentSyncLevel = 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 (Status == AE_CTRL_TRANSFER) 533 { 534 /* 535 * A method call was detected. 536 * Transfer control to the called control method 537 */ 538 Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); 539 if (ACPI_FAILURE (Status)) 540 { 541 Status = AcpiDsMethodError (Status, WalkState); 542 } 543 544 /* 545 * If the transfer to the new method method call worked, a new walk 546 * state was created -- get it 547 */ 548 WalkState = AcpiDsGetCurrentWalkState (Thread); 549 continue; 550 } 551 else if (Status == AE_CTRL_TERMINATE) 552 { 553 Status = AE_OK; 554 } 555 else if ((Status != AE_OK) && (WalkState->MethodDesc)) 556 { 557 /* Either the method parse or actual execution failed */ 558 559 ACPI_ERROR_METHOD ("Method parse/execution failed", 560 WalkState->MethodNode, NULL, Status); 561 562 /* Check for possible multi-thread reentrancy problem */ 563 564 if ((Status == AE_ALREADY_EXISTS) && 565 (!(WalkState->MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED))) 566 { 567 /* 568 * Method is not serialized and tried to create an object 569 * twice. The probable cause is that the method cannot 570 * handle reentrancy. Mark as "pending serialized" now, and 571 * then mark "serialized" when the last thread exits. 572 */ 573 WalkState->MethodDesc->Method.InfoFlags |= 574 ACPI_METHOD_SERIALIZED_PENDING; 575 } 576 } 577 578 /* We are done with this walk, move on to the parent if any */ 579 580 WalkState = AcpiDsPopWalkState (Thread); 581 582 /* Reset the current scope to the beginning of scope stack */ 583 584 AcpiDsScopeStackClear (WalkState); 585 586 /* 587 * If we just returned from the execution of a control method or if we 588 * encountered an error during the method parse phase, there's lots of 589 * cleanup to do 590 */ 591 if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) || 592 (ACPI_FAILURE (Status))) 593 { 594 AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); 595 } 596 597 /* Delete this walk state and all linked control states */ 598 599 AcpiPsCleanupScope (&WalkState->ParserState); 600 PreviousWalkState = WalkState; 601 602 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 603 "ReturnValue=%p, ImplicitValue=%p State=%p\n", 604 WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); 605 606 /* Check if we have restarted a preempted walk */ 607 608 WalkState = AcpiDsGetCurrentWalkState (Thread); 609 if (WalkState) 610 { 611 if (ACPI_SUCCESS (Status)) 612 { 613 /* 614 * There is another walk state, restart it. 615 * If the method return value is not used by the parent, 616 * The object is deleted 617 */ 618 if (!PreviousWalkState->ReturnDesc) 619 { 620 /* 621 * In slack mode execution, if there is no return value 622 * we should implicitly return zero (0) as a default value. 623 */ 624 if (AcpiGbl_EnableInterpreterSlack && 625 !PreviousWalkState->ImplicitReturnObj) 626 { 627 PreviousWalkState->ImplicitReturnObj = 628 AcpiUtCreateIntegerObject ((UINT64) 0); 629 if (!PreviousWalkState->ImplicitReturnObj) 630 { 631 return_ACPI_STATUS (AE_NO_MEMORY); 632 } 633 } 634 635 /* Restart the calling control method */ 636 637 Status = AcpiDsRestartControlMethod (WalkState, 638 PreviousWalkState->ImplicitReturnObj); 639 } 640 else 641 { 642 /* 643 * We have a valid return value, delete any implicit 644 * return value. 645 */ 646 AcpiDsClearImplicitReturn (PreviousWalkState); 647 648 Status = AcpiDsRestartControlMethod (WalkState, 649 PreviousWalkState->ReturnDesc); 650 } 651 if (ACPI_SUCCESS (Status)) 652 { 653 WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; 654 } 655 } 656 else 657 { 658 /* On error, delete any return object or implicit return */ 659 660 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 661 AcpiDsClearImplicitReturn (PreviousWalkState); 662 } 663 } 664 665 /* 666 * Just completed a 1st-level method, save the final internal return 667 * value (if any) 668 */ 669 else if (PreviousWalkState->CallerReturnDesc) 670 { 671 if (PreviousWalkState->ImplicitReturnObj) 672 { 673 *(PreviousWalkState->CallerReturnDesc) = 674 PreviousWalkState->ImplicitReturnObj; 675 } 676 else 677 { 678 /* NULL if no return value */ 679 680 *(PreviousWalkState->CallerReturnDesc) = 681 PreviousWalkState->ReturnDesc; 682 } 683 } 684 else 685 { 686 if (PreviousWalkState->ReturnDesc) 687 { 688 /* Caller doesn't want it, must delete it */ 689 690 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); 691 } 692 if (PreviousWalkState->ImplicitReturnObj) 693 { 694 /* Caller doesn't want it, must delete it */ 695 696 AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); 697 } 698 } 699 700 AcpiDsDeleteWalkState (PreviousWalkState); 701 } 702 703 /* Normal exit */ 704 705 AcpiExReleaseAllMutexes (Thread); 706 AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); 707 AcpiGbl_CurrentWalkList = PrevWalkList; 708 return_ACPI_STATUS (Status); 709 } 710 711 712