1 /****************************************************************************** 2 * 3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 #include "acpi.h" 45 #include "accommon.h" 46 #include "acdispat.h" 47 #include "acinterp.h" 48 #include "acnamesp.h" 49 #include "acparser.h" 50 #include "amlcode.h" 51 #include "acdebug.h" 52 53 54 #define _COMPONENT ACPI_DISPATCHER 55 ACPI_MODULE_NAME ("dsmethod") 56 57 /* Local prototypes */ 58 59 static ACPI_STATUS 60 AcpiDsDetectNamedOpcodes ( 61 ACPI_WALK_STATE *WalkState, 62 ACPI_PARSE_OBJECT **OutOp); 63 64 static ACPI_STATUS 65 AcpiDsCreateMethodMutex ( 66 ACPI_OPERAND_OBJECT *MethodDesc); 67 68 69 /******************************************************************************* 70 * 71 * FUNCTION: AcpiDsAutoSerializeMethod 72 * 73 * PARAMETERS: Node - Namespace Node of the method 74 * ObjDesc - Method object attached to node 75 * 76 * RETURN: Status 77 * 78 * DESCRIPTION: Parse a control method AML to scan for control methods that 79 * need serialization due to the creation of named objects. 80 * 81 * NOTE: It is a bit of overkill to mark all such methods serialized, since 82 * there is only a problem if the method actually blocks during execution. 83 * A blocking operation is, for example, a Sleep() operation, or any access 84 * to an operation region. However, it is probably not possible to easily 85 * detect whether a method will block or not, so we simply mark all suspicious 86 * methods as serialized. 87 * 88 * NOTE2: This code is essentially a generic routine for parsing a single 89 * control method. 90 * 91 ******************************************************************************/ 92 93 ACPI_STATUS 94 AcpiDsAutoSerializeMethod ( 95 ACPI_NAMESPACE_NODE *Node, 96 ACPI_OPERAND_OBJECT *ObjDesc) 97 { 98 ACPI_STATUS Status; 99 ACPI_PARSE_OBJECT *Op = NULL; 100 ACPI_WALK_STATE *WalkState; 101 102 103 ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node); 104 105 106 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 107 "Method auto-serialization parse [%4.4s] %p\n", 108 AcpiUtGetNodeName (Node), Node)); 109 110 /* Create/Init a root op for the method parse tree */ 111 112 Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart); 113 if (!Op) 114 { 115 return_ACPI_STATUS (AE_NO_MEMORY); 116 } 117 118 AcpiPsSetName (Op, Node->Name.Integer); 119 Op->Common.Node = Node; 120 121 /* Create and initialize a new walk state */ 122 123 WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL); 124 if (!WalkState) 125 { 126 AcpiPsFreeOp (Op); 127 return_ACPI_STATUS (AE_NO_MEMORY); 128 } 129 130 Status = AcpiDsInitAmlWalk (WalkState, Op, Node, 131 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0); 132 if (ACPI_FAILURE (Status)) 133 { 134 AcpiDsDeleteWalkState (WalkState); 135 AcpiPsFreeOp (Op); 136 return_ACPI_STATUS (Status); 137 } 138 139 WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes; 140 141 /* Parse the method, scan for creation of named objects */ 142 143 Status = AcpiPsParseAml (WalkState); 144 145 AcpiPsDeleteParseTree (Op); 146 return_ACPI_STATUS (Status); 147 } 148 149 150 /******************************************************************************* 151 * 152 * FUNCTION: AcpiDsDetectNamedOpcodes 153 * 154 * PARAMETERS: WalkState - Current state of the parse tree walk 155 * OutOp - Unused, required for parser interface 156 * 157 * RETURN: Status 158 * 159 * DESCRIPTION: Descending callback used during the loading of ACPI tables. 160 * Currently used to detect methods that must be marked serialized 161 * in order to avoid problems with the creation of named objects. 162 * 163 ******************************************************************************/ 164 165 static ACPI_STATUS 166 AcpiDsDetectNamedOpcodes ( 167 ACPI_WALK_STATE *WalkState, 168 ACPI_PARSE_OBJECT **OutOp) 169 { 170 171 ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes); 172 173 174 /* We are only interested in opcodes that create a new name */ 175 176 if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD))) 177 { 178 return (AE_OK); 179 } 180 181 /* 182 * At this point, we know we have a Named object opcode. 183 * Mark the method as serialized. Later code will create a mutex for 184 * this method to enforce serialization. 185 * 186 * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the 187 * Sync Level mechanism for this method, even though it is now serialized. 188 * Otherwise, there can be conflicts with existing ASL code that actually 189 * uses sync levels. 190 */ 191 WalkState->MethodDesc->Method.SyncLevel = 0; 192 WalkState->MethodDesc->Method.InfoFlags |= 193 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 194 195 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 196 "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", 197 WalkState->MethodNode->Name.Ascii, WalkState->MethodNode, 198 WalkState->OpInfo->Name, WalkState->Opcode)); 199 200 /* Abort the parse, no need to examine this method any further */ 201 202 return (AE_CTRL_TERMINATE); 203 } 204 205 206 /******************************************************************************* 207 * 208 * FUNCTION: AcpiDsMethodError 209 * 210 * PARAMETERS: Status - Execution status 211 * WalkState - Current state 212 * 213 * RETURN: Status 214 * 215 * DESCRIPTION: Called on method error. Invoke the global exception handler if 216 * present, dump the method data if the debugger is configured 217 * 218 * Note: Allows the exception handler to change the status code 219 * 220 ******************************************************************************/ 221 222 ACPI_STATUS 223 AcpiDsMethodError ( 224 ACPI_STATUS Status, 225 ACPI_WALK_STATE *WalkState) 226 { 227 UINT32 AmlOffset; 228 229 230 ACPI_FUNCTION_ENTRY (); 231 232 233 /* Ignore AE_OK and control exception codes */ 234 235 if (ACPI_SUCCESS (Status) || 236 (Status & AE_CODE_CONTROL)) 237 { 238 return (Status); 239 } 240 241 /* Invoke the global exception handler */ 242 243 if (AcpiGbl_ExceptionHandler) 244 { 245 /* Exit the interpreter, allow handler to execute methods */ 246 247 AcpiExExitInterpreter (); 248 249 /* 250 * Handler can map the exception code to anything it wants, including 251 * AE_OK, in which case the executing method will not be aborted. 252 */ 253 AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml, 254 WalkState->ParserState.AmlStart); 255 256 Status = AcpiGbl_ExceptionHandler (Status, 257 WalkState->MethodNode ? 258 WalkState->MethodNode->Name.Integer : 0, 259 WalkState->Opcode, AmlOffset, NULL); 260 AcpiExEnterInterpreter (); 261 } 262 263 AcpiDsClearImplicitReturn (WalkState); 264 265 if (ACPI_FAILURE (Status)) 266 { 267 AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op); 268 269 /* Display method locals/args if debugger is present */ 270 271 #ifdef ACPI_DEBUGGER 272 AcpiDbDumpMethodInfo (Status, WalkState); 273 #endif 274 } 275 276 return (Status); 277 } 278 279 280 /******************************************************************************* 281 * 282 * FUNCTION: AcpiDsCreateMethodMutex 283 * 284 * PARAMETERS: ObjDesc - The method object 285 * 286 * RETURN: Status 287 * 288 * DESCRIPTION: Create a mutex object for a serialized control method 289 * 290 ******************************************************************************/ 291 292 static ACPI_STATUS 293 AcpiDsCreateMethodMutex ( 294 ACPI_OPERAND_OBJECT *MethodDesc) 295 { 296 ACPI_OPERAND_OBJECT *MutexDesc; 297 ACPI_STATUS Status; 298 299 300 ACPI_FUNCTION_TRACE (DsCreateMethodMutex); 301 302 303 /* Create the new mutex object */ 304 305 MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); 306 if (!MutexDesc) 307 { 308 return_ACPI_STATUS (AE_NO_MEMORY); 309 } 310 311 /* Create the actual OS Mutex */ 312 313 Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); 314 if (ACPI_FAILURE (Status)) 315 { 316 AcpiUtDeleteObjectDesc (MutexDesc); 317 return_ACPI_STATUS (Status); 318 } 319 320 MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; 321 MethodDesc->Method.Mutex = MutexDesc; 322 return_ACPI_STATUS (AE_OK); 323 } 324 325 326 /******************************************************************************* 327 * 328 * FUNCTION: AcpiDsBeginMethodExecution 329 * 330 * PARAMETERS: MethodNode - Node of the method 331 * ObjDesc - The method object 332 * WalkState - current state, NULL if not yet executing 333 * a method. 334 * 335 * RETURN: Status 336 * 337 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, 338 * increments the thread count, and waits at the method semaphore 339 * for clearance to execute. 340 * 341 ******************************************************************************/ 342 343 ACPI_STATUS 344 AcpiDsBeginMethodExecution ( 345 ACPI_NAMESPACE_NODE *MethodNode, 346 ACPI_OPERAND_OBJECT *ObjDesc, 347 ACPI_WALK_STATE *WalkState) 348 { 349 ACPI_STATUS Status = AE_OK; 350 351 352 ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); 353 354 355 if (!MethodNode) 356 { 357 return_ACPI_STATUS (AE_NULL_ENTRY); 358 } 359 360 AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState); 361 362 /* Prevent wraparound of thread count */ 363 364 if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) 365 { 366 ACPI_ERROR ((AE_INFO, 367 "Method reached maximum reentrancy limit (255)")); 368 return_ACPI_STATUS (AE_AML_METHOD_LIMIT); 369 } 370 371 /* 372 * If this method is serialized, we need to acquire the method mutex. 373 */ 374 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) 375 { 376 /* 377 * Create a mutex for the method if it is defined to be Serialized 378 * and a mutex has not already been created. We defer the mutex creation 379 * until a method is actually executed, to minimize the object count 380 */ 381 if (!ObjDesc->Method.Mutex) 382 { 383 Status = AcpiDsCreateMethodMutex (ObjDesc); 384 if (ACPI_FAILURE (Status)) 385 { 386 return_ACPI_STATUS (Status); 387 } 388 } 389 390 /* 391 * The CurrentSyncLevel (per-thread) must be less than or equal to 392 * the sync level of the method. This mechanism provides some 393 * deadlock prevention. 394 * 395 * If the method was auto-serialized, we just ignore the sync level 396 * mechanism, because auto-serialization of methods can interfere 397 * with ASL code that actually uses sync levels. 398 * 399 * Top-level method invocation has no walk state at this point 400 */ 401 if (WalkState && 402 (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) && 403 (WalkState->Thread->CurrentSyncLevel > 404 ObjDesc->Method.Mutex->Mutex.SyncLevel)) 405 { 406 ACPI_ERROR ((AE_INFO, 407 "Cannot acquire Mutex for method [%4.4s]" 408 ", current SyncLevel is too large (%u)", 409 AcpiUtGetNodeName (MethodNode), 410 WalkState->Thread->CurrentSyncLevel)); 411 412 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 413 } 414 415 /* 416 * Obtain the method mutex if necessary. Do not acquire mutex for a 417 * recursive call. 418 */ 419 if (!WalkState || 420 !ObjDesc->Method.Mutex->Mutex.ThreadId || 421 (WalkState->Thread->ThreadId != 422 ObjDesc->Method.Mutex->Mutex.ThreadId)) 423 { 424 /* 425 * Acquire the method mutex. This releases the interpreter if we 426 * block (and reacquires it before it returns) 427 */ 428 Status = AcpiExSystemWaitMutex ( 429 ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER); 430 if (ACPI_FAILURE (Status)) 431 { 432 return_ACPI_STATUS (Status); 433 } 434 435 /* Update the mutex and walk info and save the original SyncLevel */ 436 437 if (WalkState) 438 { 439 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 440 WalkState->Thread->CurrentSyncLevel; 441 442 ObjDesc->Method.Mutex->Mutex.ThreadId = 443 WalkState->Thread->ThreadId; 444 445 /* 446 * Update the current SyncLevel only if this is not an auto- 447 * serialized method. In the auto case, we have to ignore 448 * the sync level for the method mutex (created for the 449 * auto-serialization) because we have no idea of what the 450 * sync level should be. Therefore, just ignore it. 451 */ 452 if (!(ObjDesc->Method.InfoFlags & 453 ACPI_METHOD_IGNORE_SYNC_LEVEL)) 454 { 455 WalkState->Thread->CurrentSyncLevel = 456 ObjDesc->Method.SyncLevel; 457 } 458 } 459 else 460 { 461 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 462 ObjDesc->Method.Mutex->Mutex.SyncLevel; 463 464 ObjDesc->Method.Mutex->Mutex.ThreadId = 465 AcpiOsGetThreadId (); 466 } 467 } 468 469 /* Always increase acquisition depth */ 470 471 ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; 472 } 473 474 /* 475 * Allocate an Owner ID for this method, only if this is the first thread 476 * to begin concurrent execution. We only need one OwnerId, even if the 477 * method is invoked recursively. 478 */ 479 if (!ObjDesc->Method.OwnerId) 480 { 481 Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 482 if (ACPI_FAILURE (Status)) 483 { 484 goto Cleanup; 485 } 486 } 487 488 /* 489 * Increment the method parse tree thread count since it has been 490 * reentered one more time (even if it is the same thread) 491 */ 492 ObjDesc->Method.ThreadCount++; 493 AcpiMethodCount++; 494 return_ACPI_STATUS (Status); 495 496 497 Cleanup: 498 /* On error, must release the method mutex (if present) */ 499 500 if (ObjDesc->Method.Mutex) 501 { 502 AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); 503 } 504 return_ACPI_STATUS (Status); 505 } 506 507 508 /******************************************************************************* 509 * 510 * FUNCTION: AcpiDsCallControlMethod 511 * 512 * PARAMETERS: Thread - Info for this thread 513 * ThisWalkState - Current walk state 514 * Op - Current Op to be walked 515 * 516 * RETURN: Status 517 * 518 * DESCRIPTION: Transfer execution to a called control method 519 * 520 ******************************************************************************/ 521 522 ACPI_STATUS 523 AcpiDsCallControlMethod ( 524 ACPI_THREAD_STATE *Thread, 525 ACPI_WALK_STATE *ThisWalkState, 526 ACPI_PARSE_OBJECT *Op) 527 { 528 ACPI_STATUS Status; 529 ACPI_NAMESPACE_NODE *MethodNode; 530 ACPI_WALK_STATE *NextWalkState = NULL; 531 ACPI_OPERAND_OBJECT *ObjDesc; 532 ACPI_EVALUATE_INFO *Info; 533 UINT32 i; 534 535 536 ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); 537 538 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 539 "Calling method %p, currentstate=%p\n", 540 ThisWalkState->PrevOp, ThisWalkState)); 541 542 /* 543 * Get the namespace entry for the control method we are about to call 544 */ 545 MethodNode = ThisWalkState->MethodCallNode; 546 if (!MethodNode) 547 { 548 return_ACPI_STATUS (AE_NULL_ENTRY); 549 } 550 551 ObjDesc = AcpiNsGetAttachedObject (MethodNode); 552 if (!ObjDesc) 553 { 554 return_ACPI_STATUS (AE_NULL_OBJECT); 555 } 556 557 /* Init for new method, possibly wait on method mutex */ 558 559 Status = AcpiDsBeginMethodExecution ( 560 MethodNode, ObjDesc, ThisWalkState); 561 if (ACPI_FAILURE (Status)) 562 { 563 return_ACPI_STATUS (Status); 564 } 565 566 /* Begin method parse/execution. Create a new walk state */ 567 568 NextWalkState = AcpiDsCreateWalkState ( 569 ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread); 570 if (!NextWalkState) 571 { 572 Status = AE_NO_MEMORY; 573 goto Cleanup; 574 } 575 576 /* 577 * The resolved arguments were put on the previous walk state's operand 578 * stack. Operands on the previous walk state stack always 579 * start at index 0. Also, null terminate the list of arguments 580 */ 581 ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; 582 583 /* 584 * Allocate and initialize the evaluation information block 585 * TBD: this is somewhat inefficient, should change interface to 586 * DsInitAmlWalk. For now, keeps this struct off the CPU stack 587 */ 588 Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 589 if (!Info) 590 { 591 Status = AE_NO_MEMORY; 592 goto Cleanup; 593 } 594 595 Info->Parameters = &ThisWalkState->Operands[0]; 596 597 Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, 598 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, 599 Info, ACPI_IMODE_EXECUTE); 600 601 ACPI_FREE (Info); 602 if (ACPI_FAILURE (Status)) 603 { 604 goto Cleanup; 605 } 606 607 /* 608 * Delete the operands on the previous walkstate operand stack 609 * (they were copied to new objects) 610 */ 611 for (i = 0; i < ObjDesc->Method.ParamCount; i++) 612 { 613 AcpiUtRemoveReference (ThisWalkState->Operands [i]); 614 ThisWalkState->Operands [i] = NULL; 615 } 616 617 /* Clear the operand stack */ 618 619 ThisWalkState->NumOperands = 0; 620 621 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 622 "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 623 MethodNode->Name.Ascii, NextWalkState)); 624 625 /* Invoke an internal method if necessary */ 626 627 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) 628 { 629 Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); 630 if (Status == AE_OK) 631 { 632 Status = AE_CTRL_TERMINATE; 633 } 634 } 635 636 return_ACPI_STATUS (Status); 637 638 639 Cleanup: 640 641 /* On error, we must terminate the method properly */ 642 643 AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); 644 AcpiDsDeleteWalkState (NextWalkState); 645 646 return_ACPI_STATUS (Status); 647 } 648 649 650 /******************************************************************************* 651 * 652 * FUNCTION: AcpiDsRestartControlMethod 653 * 654 * PARAMETERS: WalkState - State for preempted method (caller) 655 * ReturnDesc - Return value from the called method 656 * 657 * RETURN: Status 658 * 659 * DESCRIPTION: Restart a method that was preempted by another (nested) method 660 * invocation. Handle the return value (if any) from the callee. 661 * 662 ******************************************************************************/ 663 664 ACPI_STATUS 665 AcpiDsRestartControlMethod ( 666 ACPI_WALK_STATE *WalkState, 667 ACPI_OPERAND_OBJECT *ReturnDesc) 668 { 669 ACPI_STATUS Status; 670 int SameAsImplicitReturn; 671 672 673 ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); 674 675 676 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 677 "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 678 AcpiUtGetNodeName (WalkState->MethodNode), 679 WalkState->MethodCallOp, ReturnDesc)); 680 681 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 682 " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 683 WalkState->ReturnUsed, 684 WalkState->Results, WalkState)); 685 686 /* Did the called method return a value? */ 687 688 if (ReturnDesc) 689 { 690 /* Is the implicit return object the same as the return desc? */ 691 692 SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); 693 694 /* Are we actually going to use the return value? */ 695 696 if (WalkState->ReturnUsed) 697 { 698 /* Save the return value from the previous method */ 699 700 Status = AcpiDsResultPush (ReturnDesc, WalkState); 701 if (ACPI_FAILURE (Status)) 702 { 703 AcpiUtRemoveReference (ReturnDesc); 704 return_ACPI_STATUS (Status); 705 } 706 707 /* 708 * Save as THIS method's return value in case it is returned 709 * immediately to yet another method 710 */ 711 WalkState->ReturnDesc = ReturnDesc; 712 } 713 714 /* 715 * The following code is the optional support for the so-called 716 * "implicit return". Some AML code assumes that the last value of the 717 * method is "implicitly" returned to the caller, in the absence of an 718 * explicit return value. 719 * 720 * Just save the last result of the method as the return value. 721 * 722 * NOTE: this is optional because the ASL language does not actually 723 * support this behavior. 724 */ 725 else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || 726 SameAsImplicitReturn) 727 { 728 /* 729 * Delete the return value if it will not be used by the 730 * calling method or remove one reference if the explicit return 731 * is the same as the implicit return value. 732 */ 733 AcpiUtRemoveReference (ReturnDesc); 734 } 735 } 736 737 return_ACPI_STATUS (AE_OK); 738 } 739 740 741 /******************************************************************************* 742 * 743 * FUNCTION: AcpiDsTerminateControlMethod 744 * 745 * PARAMETERS: MethodDesc - Method object 746 * WalkState - State associated with the method 747 * 748 * RETURN: None 749 * 750 * DESCRIPTION: Terminate a control method. Delete everything that the method 751 * created, delete all locals and arguments, and delete the parse 752 * tree if requested. 753 * 754 * MUTEX: Interpreter is locked 755 * 756 ******************************************************************************/ 757 758 void 759 AcpiDsTerminateControlMethod ( 760 ACPI_OPERAND_OBJECT *MethodDesc, 761 ACPI_WALK_STATE *WalkState) 762 { 763 764 ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); 765 766 767 /* MethodDesc is required, WalkState is optional */ 768 769 if (!MethodDesc) 770 { 771 return_VOID; 772 } 773 774 if (WalkState) 775 { 776 /* Delete all arguments and locals */ 777 778 AcpiDsMethodDataDeleteAll (WalkState); 779 780 /* 781 * If method is serialized, release the mutex and restore the 782 * current sync level for this thread 783 */ 784 if (MethodDesc->Method.Mutex) 785 { 786 /* Acquisition Depth handles recursive calls */ 787 788 MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; 789 if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) 790 { 791 WalkState->Thread->CurrentSyncLevel = 792 MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; 793 794 AcpiOsReleaseMutex ( 795 MethodDesc->Method.Mutex->Mutex.OsMutex); 796 MethodDesc->Method.Mutex->Mutex.ThreadId = 0; 797 } 798 } 799 800 /* 801 * Delete any namespace objects created anywhere within the 802 * namespace by the execution of this method. Unless: 803 * 1) This method is a module-level executable code method, in which 804 * case we want make the objects permanent. 805 * 2) There are other threads executing the method, in which case we 806 * will wait until the last thread has completed. 807 */ 808 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && 809 (MethodDesc->Method.ThreadCount == 1)) 810 { 811 /* Delete any direct children of (created by) this method */ 812 813 AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); 814 815 /* 816 * Delete any objects that were created by this method 817 * elsewhere in the namespace (if any were created). 818 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 819 * deletion such that we don't have to perform an entire 820 * namespace walk for every control method execution. 821 */ 822 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) 823 { 824 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); 825 MethodDesc->Method.InfoFlags &= 826 ~ACPI_METHOD_MODIFIED_NAMESPACE; 827 } 828 } 829 } 830 831 /* Decrement the thread count on the method */ 832 833 if (MethodDesc->Method.ThreadCount) 834 { 835 MethodDesc->Method.ThreadCount--; 836 } 837 else 838 { 839 ACPI_ERROR ((AE_INFO, 840 "Invalid zero thread count in method")); 841 } 842 843 /* Are there any other threads currently executing this method? */ 844 845 if (MethodDesc->Method.ThreadCount) 846 { 847 /* 848 * Additional threads. Do not release the OwnerId in this case, 849 * we immediately reuse it for the next thread executing this method 850 */ 851 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 852 "*** Completed execution of one thread, %u threads remaining\n", 853 MethodDesc->Method.ThreadCount)); 854 } 855 else 856 { 857 /* This is the only executing thread for this method */ 858 859 /* 860 * Support to dynamically change a method from NotSerialized to 861 * Serialized if it appears that the method is incorrectly written and 862 * does not support multiple thread execution. The best example of this 863 * is if such a method creates namespace objects and blocks. A second 864 * thread will fail with an AE_ALREADY_EXISTS exception. 865 * 866 * This code is here because we must wait until the last thread exits 867 * before marking the method as serialized. 868 */ 869 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) 870 { 871 if (WalkState) 872 { 873 ACPI_INFO (( 874 "Marking method %4.4s as Serialized " 875 "because of AE_ALREADY_EXISTS error", 876 WalkState->MethodNode->Name.Ascii)); 877 } 878 879 /* 880 * Method tried to create an object twice and was marked as 881 * "pending serialized". The probable cause is that the method 882 * cannot handle reentrancy. 883 * 884 * The method was created as NotSerialized, but it tried to create 885 * a named object and then blocked, causing the second thread 886 * entrance to begin and then fail. Workaround this problem by 887 * marking the method permanently as Serialized when the last 888 * thread exits here. 889 */ 890 MethodDesc->Method.InfoFlags &= 891 ~ACPI_METHOD_SERIALIZED_PENDING; 892 893 MethodDesc->Method.InfoFlags |= 894 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 895 MethodDesc->Method.SyncLevel = 0; 896 } 897 898 /* No more threads, we can free the OwnerId */ 899 900 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) 901 { 902 AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); 903 } 904 } 905 906 AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node, 907 MethodDesc, WalkState); 908 909 return_VOID; 910 } 911