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