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