1 /****************************************************************************** 2 * 3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 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 #include <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acdispat.h> 47 #include <contrib/dev/acpica/include/acinterp.h> 48 #include <contrib/dev/acpica/include/acnamesp.h> 49 #include <contrib/dev/acpica/include/acparser.h> 50 #include <contrib/dev/acpica/include/amlcode.h> 51 #include <contrib/dev/acpica/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, ObjDesc->Method.AmlStart, 131 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 > ObjDesc->Method.Mutex->Mutex.SyncLevel)) 404 { 405 ACPI_ERROR ((AE_INFO, 406 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", 407 AcpiUtGetNodeName (MethodNode), 408 WalkState->Thread->CurrentSyncLevel)); 409 410 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 411 } 412 413 /* 414 * Obtain the method mutex if necessary. Do not acquire mutex for a 415 * recursive call. 416 */ 417 if (!WalkState || 418 !ObjDesc->Method.Mutex->Mutex.ThreadId || 419 (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId)) 420 { 421 /* 422 * Acquire the method mutex. This releases the interpreter if we 423 * block (and reacquires it before it returns) 424 */ 425 Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex, 426 ACPI_WAIT_FOREVER); 427 if (ACPI_FAILURE (Status)) 428 { 429 return_ACPI_STATUS (Status); 430 } 431 432 /* Update the mutex and walk info and save the original SyncLevel */ 433 434 if (WalkState) 435 { 436 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 437 WalkState->Thread->CurrentSyncLevel; 438 439 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId; 440 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel; 441 } 442 else 443 { 444 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 445 ObjDesc->Method.Mutex->Mutex.SyncLevel; 446 } 447 } 448 449 /* Always increase acquisition depth */ 450 451 ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; 452 } 453 454 /* 455 * Allocate an Owner ID for this method, only if this is the first thread 456 * to begin concurrent execution. We only need one OwnerId, even if the 457 * method is invoked recursively. 458 */ 459 if (!ObjDesc->Method.OwnerId) 460 { 461 Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 462 if (ACPI_FAILURE (Status)) 463 { 464 goto Cleanup; 465 } 466 } 467 468 /* 469 * Increment the method parse tree thread count since it has been 470 * reentered one more time (even if it is the same thread) 471 */ 472 ObjDesc->Method.ThreadCount++; 473 AcpiMethodCount++; 474 return_ACPI_STATUS (Status); 475 476 477 Cleanup: 478 /* On error, must release the method mutex (if present) */ 479 480 if (ObjDesc->Method.Mutex) 481 { 482 AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); 483 } 484 return_ACPI_STATUS (Status); 485 } 486 487 488 /******************************************************************************* 489 * 490 * FUNCTION: AcpiDsCallControlMethod 491 * 492 * PARAMETERS: Thread - Info for this thread 493 * ThisWalkState - Current walk state 494 * Op - Current Op to be walked 495 * 496 * RETURN: Status 497 * 498 * DESCRIPTION: Transfer execution to a called control method 499 * 500 ******************************************************************************/ 501 502 ACPI_STATUS 503 AcpiDsCallControlMethod ( 504 ACPI_THREAD_STATE *Thread, 505 ACPI_WALK_STATE *ThisWalkState, 506 ACPI_PARSE_OBJECT *Op) 507 { 508 ACPI_STATUS Status; 509 ACPI_NAMESPACE_NODE *MethodNode; 510 ACPI_WALK_STATE *NextWalkState = NULL; 511 ACPI_OPERAND_OBJECT *ObjDesc; 512 ACPI_EVALUATE_INFO *Info; 513 UINT32 i; 514 515 516 ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); 517 518 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", 519 ThisWalkState->PrevOp, ThisWalkState)); 520 521 /* 522 * Get the namespace entry for the control method we are about to call 523 */ 524 MethodNode = ThisWalkState->MethodCallNode; 525 if (!MethodNode) 526 { 527 return_ACPI_STATUS (AE_NULL_ENTRY); 528 } 529 530 ObjDesc = AcpiNsGetAttachedObject (MethodNode); 531 if (!ObjDesc) 532 { 533 return_ACPI_STATUS (AE_NULL_OBJECT); 534 } 535 536 /* Init for new method, possibly wait on method mutex */ 537 538 Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, 539 ThisWalkState); 540 if (ACPI_FAILURE (Status)) 541 { 542 return_ACPI_STATUS (Status); 543 } 544 545 /* Begin method parse/execution. Create a new walk state */ 546 547 NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, 548 NULL, ObjDesc, Thread); 549 if (!NextWalkState) 550 { 551 Status = AE_NO_MEMORY; 552 goto Cleanup; 553 } 554 555 /* 556 * The resolved arguments were put on the previous walk state's operand 557 * stack. Operands on the previous walk state stack always 558 * start at index 0. Also, null terminate the list of arguments 559 */ 560 ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; 561 562 /* 563 * Allocate and initialize the evaluation information block 564 * TBD: this is somewhat inefficient, should change interface to 565 * DsInitAmlWalk. For now, keeps this struct off the CPU stack 566 */ 567 Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 568 if (!Info) 569 { 570 Status = AE_NO_MEMORY; 571 goto Cleanup; 572 } 573 574 Info->Parameters = &ThisWalkState->Operands[0]; 575 576 Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, 577 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, 578 Info, ACPI_IMODE_EXECUTE); 579 580 ACPI_FREE (Info); 581 if (ACPI_FAILURE (Status)) 582 { 583 goto Cleanup; 584 } 585 586 /* 587 * Delete the operands on the previous walkstate operand stack 588 * (they were copied to new objects) 589 */ 590 for (i = 0; i < ObjDesc->Method.ParamCount; i++) 591 { 592 AcpiUtRemoveReference (ThisWalkState->Operands [i]); 593 ThisWalkState->Operands [i] = NULL; 594 } 595 596 /* Clear the operand stack */ 597 598 ThisWalkState->NumOperands = 0; 599 600 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 601 "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 602 MethodNode->Name.Ascii, NextWalkState)); 603 604 /* Invoke an internal method if necessary */ 605 606 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) 607 { 608 Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); 609 if (Status == AE_OK) 610 { 611 Status = AE_CTRL_TERMINATE; 612 } 613 } 614 615 return_ACPI_STATUS (Status); 616 617 618 Cleanup: 619 620 /* On error, we must terminate the method properly */ 621 622 AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); 623 AcpiDsDeleteWalkState (NextWalkState); 624 625 return_ACPI_STATUS (Status); 626 } 627 628 629 /******************************************************************************* 630 * 631 * FUNCTION: AcpiDsRestartControlMethod 632 * 633 * PARAMETERS: WalkState - State for preempted method (caller) 634 * ReturnDesc - Return value from the called method 635 * 636 * RETURN: Status 637 * 638 * DESCRIPTION: Restart a method that was preempted by another (nested) method 639 * invocation. Handle the return value (if any) from the callee. 640 * 641 ******************************************************************************/ 642 643 ACPI_STATUS 644 AcpiDsRestartControlMethod ( 645 ACPI_WALK_STATE *WalkState, 646 ACPI_OPERAND_OBJECT *ReturnDesc) 647 { 648 ACPI_STATUS Status; 649 int SameAsImplicitReturn; 650 651 652 ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); 653 654 655 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 656 "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 657 AcpiUtGetNodeName (WalkState->MethodNode), 658 WalkState->MethodCallOp, ReturnDesc)); 659 660 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 661 " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 662 WalkState->ReturnUsed, 663 WalkState->Results, WalkState)); 664 665 /* Did the called method return a value? */ 666 667 if (ReturnDesc) 668 { 669 /* Is the implicit return object the same as the return desc? */ 670 671 SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); 672 673 /* Are we actually going to use the return value? */ 674 675 if (WalkState->ReturnUsed) 676 { 677 /* Save the return value from the previous method */ 678 679 Status = AcpiDsResultPush (ReturnDesc, WalkState); 680 if (ACPI_FAILURE (Status)) 681 { 682 AcpiUtRemoveReference (ReturnDesc); 683 return_ACPI_STATUS (Status); 684 } 685 686 /* 687 * Save as THIS method's return value in case it is returned 688 * immediately to yet another method 689 */ 690 WalkState->ReturnDesc = ReturnDesc; 691 } 692 693 /* 694 * The following code is the optional support for the so-called 695 * "implicit return". Some AML code assumes that the last value of the 696 * method is "implicitly" returned to the caller, in the absence of an 697 * explicit return value. 698 * 699 * Just save the last result of the method as the return value. 700 * 701 * NOTE: this is optional because the ASL language does not actually 702 * support this behavior. 703 */ 704 else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || 705 SameAsImplicitReturn) 706 { 707 /* 708 * Delete the return value if it will not be used by the 709 * calling method or remove one reference if the explicit return 710 * is the same as the implicit return value. 711 */ 712 AcpiUtRemoveReference (ReturnDesc); 713 } 714 } 715 716 return_ACPI_STATUS (AE_OK); 717 } 718 719 720 /******************************************************************************* 721 * 722 * FUNCTION: AcpiDsTerminateControlMethod 723 * 724 * PARAMETERS: MethodDesc - Method object 725 * WalkState - State associated with the method 726 * 727 * RETURN: None 728 * 729 * DESCRIPTION: Terminate a control method. Delete everything that the method 730 * created, delete all locals and arguments, and delete the parse 731 * tree if requested. 732 * 733 * MUTEX: Interpreter is locked 734 * 735 ******************************************************************************/ 736 737 void 738 AcpiDsTerminateControlMethod ( 739 ACPI_OPERAND_OBJECT *MethodDesc, 740 ACPI_WALK_STATE *WalkState) 741 { 742 743 ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); 744 745 746 /* MethodDesc is required, WalkState is optional */ 747 748 if (!MethodDesc) 749 { 750 return_VOID; 751 } 752 753 if (WalkState) 754 { 755 /* Delete all arguments and locals */ 756 757 AcpiDsMethodDataDeleteAll (WalkState); 758 759 /* 760 * If method is serialized, release the mutex and restore the 761 * current sync level for this thread 762 */ 763 if (MethodDesc->Method.Mutex) 764 { 765 /* Acquisition Depth handles recursive calls */ 766 767 MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; 768 if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) 769 { 770 WalkState->Thread->CurrentSyncLevel = 771 MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; 772 773 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); 774 MethodDesc->Method.Mutex->Mutex.ThreadId = 0; 775 } 776 } 777 778 /* 779 * Delete any namespace objects created anywhere within the 780 * namespace by the execution of this method. Unless: 781 * 1) This method is a module-level executable code method, in which 782 * case we want make the objects permanent. 783 * 2) There are other threads executing the method, in which case we 784 * will wait until the last thread has completed. 785 */ 786 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && 787 (MethodDesc->Method.ThreadCount == 1)) 788 { 789 /* Delete any direct children of (created by) this method */ 790 791 AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); 792 793 /* 794 * Delete any objects that were created by this method 795 * elsewhere in the namespace (if any were created). 796 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 797 * deletion such that we don't have to perform an entire 798 * namespace walk for every control method execution. 799 */ 800 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) 801 { 802 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); 803 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; 804 } 805 } 806 } 807 808 /* Decrement the thread count on the method */ 809 810 if (MethodDesc->Method.ThreadCount) 811 { 812 MethodDesc->Method.ThreadCount--; 813 } 814 else 815 { 816 ACPI_ERROR ((AE_INFO, 817 "Invalid zero thread count in method")); 818 } 819 820 /* Are there any other threads currently executing this method? */ 821 822 if (MethodDesc->Method.ThreadCount) 823 { 824 /* 825 * Additional threads. Do not release the OwnerId in this case, 826 * we immediately reuse it for the next thread executing this method 827 */ 828 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 829 "*** Completed execution of one thread, %u threads remaining\n", 830 MethodDesc->Method.ThreadCount)); 831 } 832 else 833 { 834 /* This is the only executing thread for this method */ 835 836 /* 837 * Support to dynamically change a method from NotSerialized to 838 * Serialized if it appears that the method is incorrectly written and 839 * does not support multiple thread execution. The best example of this 840 * is if such a method creates namespace objects and blocks. A second 841 * thread will fail with an AE_ALREADY_EXISTS exception. 842 * 843 * This code is here because we must wait until the last thread exits 844 * before marking the method as serialized. 845 */ 846 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) 847 { 848 if (WalkState) 849 { 850 ACPI_INFO ((AE_INFO, 851 "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", 852 WalkState->MethodNode->Name.Ascii)); 853 } 854 855 /* 856 * Method tried to create an object twice and was marked as 857 * "pending serialized". The probable cause is that the method 858 * cannot handle reentrancy. 859 * 860 * The method was created as NotSerialized, but it tried to create 861 * a named object and then blocked, causing the second thread 862 * entrance to begin and then fail. Workaround this problem by 863 * marking the method permanently as Serialized when the last 864 * thread exits here. 865 */ 866 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING; 867 MethodDesc->Method.InfoFlags |= 868 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 869 MethodDesc->Method.SyncLevel = 0; 870 } 871 872 /* No more threads, we can free the OwnerId */ 873 874 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) 875 { 876 AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); 877 } 878 } 879 880 AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node, 881 MethodDesc, WalkState); 882 883 return_VOID; 884 } 885