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