![]() |
|
|||
File indexing completed on 2025-05-11 08:24:02
0001 /****************************************************************************** 0002 * 0003 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 0004 * 0005 *****************************************************************************/ 0006 0007 /****************************************************************************** 0008 * 0009 * 1. Copyright Notice 0010 * 0011 * Some or all of this work - Copyright (c) 1999 - 2024, Intel Corp. 0012 * All rights reserved. 0013 * 0014 * 2. License 0015 * 0016 * 2.1. This is your license from Intel Corp. under its intellectual property 0017 * rights. You may have additional license terms from the party that provided 0018 * you this software, covering your right to use that party's intellectual 0019 * property rights. 0020 * 0021 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 0022 * copy of the source code appearing in this file ("Covered Code") an 0023 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 0024 * base code distributed originally by Intel ("Original Intel Code") to copy, 0025 * make derivatives, distribute, use and display any portion of the Covered 0026 * Code in any form, with the right to sublicense such rights; and 0027 * 0028 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 0029 * license (with the right to sublicense), under only those claims of Intel 0030 * patents that are infringed by the Original Intel Code, to make, use, sell, 0031 * offer to sell, and import the Covered Code and derivative works thereof 0032 * solely to the minimum extent necessary to exercise the above copyright 0033 * license, and in no event shall the patent license extend to any additions 0034 * to or modifications of the Original Intel Code. No other license or right 0035 * is granted directly or by implication, estoppel or otherwise; 0036 * 0037 * The above copyright and patent license is granted only if the following 0038 * conditions are met: 0039 * 0040 * 3. Conditions 0041 * 0042 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 0043 * Redistribution of source code of any substantial portion of the Covered 0044 * Code or modification with rights to further distribute source must include 0045 * the above Copyright Notice, the above License, this list of Conditions, 0046 * and the following Disclaimer and Export Compliance provision. In addition, 0047 * Licensee must cause all Covered Code to which Licensee contributes to 0048 * contain a file documenting the changes Licensee made to create that Covered 0049 * Code and the date of any change. Licensee must include in that file the 0050 * documentation of any changes made by any predecessor Licensee. Licensee 0051 * must include a prominent statement that the modification is derived, 0052 * directly or indirectly, from Original Intel Code. 0053 * 0054 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 0055 * Redistribution of source code of any substantial portion of the Covered 0056 * Code or modification without rights to further distribute source must 0057 * include the following Disclaimer and Export Compliance provision in the 0058 * documentation and/or other materials provided with distribution. In 0059 * addition, Licensee may not authorize further sublicense of source of any 0060 * portion of the Covered Code, and must include terms to the effect that the 0061 * license from Licensee to its licensee is limited to the intellectual 0062 * property embodied in the software Licensee provides to its licensee, and 0063 * not to intellectual property embodied in modifications its licensee may 0064 * make. 0065 * 0066 * 3.3. Redistribution of Executable. Redistribution in executable form of any 0067 * substantial portion of the Covered Code or modification must reproduce the 0068 * above Copyright Notice, and the following Disclaimer and Export Compliance 0069 * provision in the documentation and/or other materials provided with the 0070 * distribution. 0071 * 0072 * 3.4. Intel retains all right, title, and interest in and to the Original 0073 * Intel Code. 0074 * 0075 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 0076 * Intel shall be used in advertising or otherwise to promote the sale, use or 0077 * other dealings in products derived from or relating to the Covered Code 0078 * without prior written authorization from Intel. 0079 * 0080 * 4. Disclaimer and Export Compliance 0081 * 0082 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 0083 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 0084 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 0085 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 0086 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 0087 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 0088 * PARTICULAR PURPOSE. 0089 * 0090 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 0091 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 0092 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 0093 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 0094 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 0095 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 0096 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 0097 * LIMITED REMEDY. 0098 * 0099 * 4.3. Licensee shall not export, either directly or indirectly, any of this 0100 * software or system incorporating such software without first obtaining any 0101 * required license or other approval from the U. S. Department of Commerce or 0102 * any other agency or department of the United States Government. In the 0103 * event Licensee exports any such software from the United States or 0104 * re-exports any such software from a foreign destination, Licensee shall 0105 * ensure that the distribution and export/re-export of the software is in 0106 * compliance with all laws, regulations, orders, or other restrictions of the 0107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 0108 * any of its subsidiaries will export/re-export any technical data, process, 0109 * software, or service, directly or indirectly, to any country for which the 0110 * United States government or any agency thereof requires an export license, 0111 * other governmental approval, or letter of assurance, without first obtaining 0112 * such license, approval or letter. 0113 * 0114 ***************************************************************************** 0115 * 0116 * Alternatively, you may choose to be licensed under the terms of the 0117 * following license: 0118 * 0119 * Redistribution and use in source and binary forms, with or without 0120 * modification, are permitted provided that the following conditions 0121 * are met: 0122 * 1. Redistributions of source code must retain the above copyright 0123 * notice, this list of conditions, and the following disclaimer, 0124 * without modification. 0125 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 0126 * substantially similar to the "NO WARRANTY" disclaimer below 0127 * ("Disclaimer") and any redistribution must be conditioned upon 0128 * including a substantially similar Disclaimer requirement for further 0129 * binary redistribution. 0130 * 3. Neither the names of the above-listed copyright holders nor the names 0131 * of any contributors may be used to endorse or promote products derived 0132 * from this software without specific prior written permission. 0133 * 0134 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 0135 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 0136 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 0137 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 0138 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 0139 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 0140 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0141 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0142 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0143 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 0144 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0145 * 0146 * Alternatively, you may choose to be licensed under the terms of the 0147 * GNU General Public License ("GPL") version 2 as published by the Free 0148 * Software Foundation. 0149 * 0150 *****************************************************************************/ 0151 0152 #include "acpi.h" 0153 #include "accommon.h" 0154 #include "acdispat.h" 0155 #include "acinterp.h" 0156 #include "acnamesp.h" 0157 #include "acparser.h" 0158 #include "amlcode.h" 0159 #include "acdebug.h" 0160 0161 0162 #define _COMPONENT ACPI_DISPATCHER 0163 ACPI_MODULE_NAME ("dsmethod") 0164 0165 /* Local prototypes */ 0166 0167 static ACPI_STATUS 0168 AcpiDsDetectNamedOpcodes ( 0169 ACPI_WALK_STATE *WalkState, 0170 ACPI_PARSE_OBJECT **OutOp); 0171 0172 static ACPI_STATUS 0173 AcpiDsCreateMethodMutex ( 0174 ACPI_OPERAND_OBJECT *MethodDesc); 0175 0176 0177 /******************************************************************************* 0178 * 0179 * FUNCTION: AcpiDsAutoSerializeMethod 0180 * 0181 * PARAMETERS: Node - Namespace Node of the method 0182 * ObjDesc - Method object attached to node 0183 * 0184 * RETURN: Status 0185 * 0186 * DESCRIPTION: Parse a control method AML to scan for control methods that 0187 * need serialization due to the creation of named objects. 0188 * 0189 * NOTE: It is a bit of overkill to mark all such methods serialized, since 0190 * there is only a problem if the method actually blocks during execution. 0191 * A blocking operation is, for example, a Sleep() operation, or any access 0192 * to an operation region. However, it is probably not possible to easily 0193 * detect whether a method will block or not, so we simply mark all suspicious 0194 * methods as serialized. 0195 * 0196 * NOTE2: This code is essentially a generic routine for parsing a single 0197 * control method. 0198 * 0199 ******************************************************************************/ 0200 0201 ACPI_STATUS 0202 AcpiDsAutoSerializeMethod ( 0203 ACPI_NAMESPACE_NODE *Node, 0204 ACPI_OPERAND_OBJECT *ObjDesc) 0205 { 0206 ACPI_STATUS Status; 0207 ACPI_PARSE_OBJECT *Op = NULL; 0208 ACPI_WALK_STATE *WalkState; 0209 0210 0211 ACPI_FUNCTION_TRACE_PTR (DsAutoSerializeMethod, Node); 0212 0213 0214 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, 0215 "Method auto-serialization parse [%4.4s] %p\n", 0216 AcpiUtGetNodeName (Node), Node)); 0217 0218 /* Create/Init a root op for the method parse tree */ 0219 0220 Op = AcpiPsAllocOp (AML_METHOD_OP, ObjDesc->Method.AmlStart); 0221 if (!Op) 0222 { 0223 return_ACPI_STATUS (AE_NO_MEMORY); 0224 } 0225 0226 AcpiPsSetName (Op, Node->Name.Integer); 0227 Op->Common.Node = Node; 0228 0229 /* Create and initialize a new walk state */ 0230 0231 WalkState = AcpiDsCreateWalkState (Node->OwnerId, NULL, NULL, NULL); 0232 if (!WalkState) 0233 { 0234 AcpiPsFreeOp (Op); 0235 return_ACPI_STATUS (AE_NO_MEMORY); 0236 } 0237 0238 Status = AcpiDsInitAmlWalk (WalkState, Op, Node, 0239 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, NULL, 0); 0240 if (ACPI_FAILURE (Status)) 0241 { 0242 AcpiDsDeleteWalkState (WalkState); 0243 AcpiPsFreeOp (Op); 0244 return_ACPI_STATUS (Status); 0245 } 0246 0247 WalkState->DescendingCallback = AcpiDsDetectNamedOpcodes; 0248 0249 /* Parse the method, scan for creation of named objects */ 0250 0251 Status = AcpiPsParseAml (WalkState); 0252 0253 AcpiPsDeleteParseTree (Op); 0254 return_ACPI_STATUS (Status); 0255 } 0256 0257 0258 /******************************************************************************* 0259 * 0260 * FUNCTION: AcpiDsDetectNamedOpcodes 0261 * 0262 * PARAMETERS: WalkState - Current state of the parse tree walk 0263 * OutOp - Unused, required for parser interface 0264 * 0265 * RETURN: Status 0266 * 0267 * DESCRIPTION: Descending callback used during the loading of ACPI tables. 0268 * Currently used to detect methods that must be marked serialized 0269 * in order to avoid problems with the creation of named objects. 0270 * 0271 ******************************************************************************/ 0272 0273 static ACPI_STATUS 0274 AcpiDsDetectNamedOpcodes ( 0275 ACPI_WALK_STATE *WalkState, 0276 ACPI_PARSE_OBJECT **OutOp) 0277 { 0278 0279 ACPI_FUNCTION_NAME (AcpiDsDetectNamedOpcodes); 0280 0281 0282 /* We are only interested in opcodes that create a new name */ 0283 0284 if (!(WalkState->OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_FIELD))) 0285 { 0286 return (AE_OK); 0287 } 0288 0289 /* 0290 * At this point, we know we have a Named object opcode. 0291 * Mark the method as serialized. Later code will create a mutex for 0292 * this method to enforce serialization. 0293 * 0294 * Note, ACPI_METHOD_IGNORE_SYNC_LEVEL flag means that we will ignore the 0295 * Sync Level mechanism for this method, even though it is now serialized. 0296 * Otherwise, there can be conflicts with existing ASL code that actually 0297 * uses sync levels. 0298 */ 0299 WalkState->MethodDesc->Method.SyncLevel = 0; 0300 WalkState->MethodDesc->Method.InfoFlags |= 0301 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 0302 0303 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 0304 "Method serialized [%4.4s] %p - [%s] (%4.4X)\n", 0305 WalkState->MethodNode->Name.Ascii, WalkState->MethodNode, 0306 WalkState->OpInfo->Name, WalkState->Opcode)); 0307 0308 /* Abort the parse, no need to examine this method any further */ 0309 0310 return (AE_CTRL_TERMINATE); 0311 } 0312 0313 0314 /******************************************************************************* 0315 * 0316 * FUNCTION: AcpiDsMethodError 0317 * 0318 * PARAMETERS: Status - Execution status 0319 * WalkState - Current state 0320 * 0321 * RETURN: Status 0322 * 0323 * DESCRIPTION: Called on method error. Invoke the global exception handler if 0324 * present, dump the method data if the debugger is configured 0325 * 0326 * Note: Allows the exception handler to change the status code 0327 * 0328 ******************************************************************************/ 0329 0330 ACPI_STATUS 0331 AcpiDsMethodError ( 0332 ACPI_STATUS Status, 0333 ACPI_WALK_STATE *WalkState) 0334 { 0335 UINT32 AmlOffset; 0336 ACPI_NAME Name = 0; 0337 0338 0339 ACPI_FUNCTION_ENTRY (); 0340 0341 0342 /* Ignore AE_OK and control exception codes */ 0343 0344 if (ACPI_SUCCESS (Status) || 0345 (Status & AE_CODE_CONTROL)) 0346 { 0347 return (Status); 0348 } 0349 0350 /* Invoke the global exception handler */ 0351 0352 if (AcpiGbl_ExceptionHandler) 0353 { 0354 /* Exit the interpreter, allow handler to execute methods */ 0355 0356 AcpiExExitInterpreter (); 0357 0358 /* 0359 * Handler can map the exception code to anything it wants, including 0360 * AE_OK, in which case the executing method will not be aborted. 0361 */ 0362 AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->Aml, 0363 WalkState->ParserState.AmlStart); 0364 0365 if (WalkState->MethodNode) 0366 { 0367 Name = WalkState->MethodNode->Name.Integer; 0368 } 0369 else if (WalkState->DeferredNode) 0370 { 0371 Name = WalkState->DeferredNode->Name.Integer; 0372 } 0373 0374 Status = AcpiGbl_ExceptionHandler (Status, Name, 0375 WalkState->Opcode, AmlOffset, NULL); 0376 AcpiExEnterInterpreter (); 0377 } 0378 0379 AcpiDsClearImplicitReturn (WalkState); 0380 0381 if (ACPI_FAILURE (Status)) 0382 { 0383 AcpiDsDumpMethodStack (Status, WalkState, WalkState->Op); 0384 0385 /* Display method locals/args if debugger is present */ 0386 0387 #ifdef ACPI_DEBUGGER 0388 AcpiDbDumpMethodInfo (Status, WalkState); 0389 #endif 0390 } 0391 0392 return (Status); 0393 } 0394 0395 0396 /******************************************************************************* 0397 * 0398 * FUNCTION: AcpiDsCreateMethodMutex 0399 * 0400 * PARAMETERS: ObjDesc - The method object 0401 * 0402 * RETURN: Status 0403 * 0404 * DESCRIPTION: Create a mutex object for a serialized control method 0405 * 0406 ******************************************************************************/ 0407 0408 static ACPI_STATUS 0409 AcpiDsCreateMethodMutex ( 0410 ACPI_OPERAND_OBJECT *MethodDesc) 0411 { 0412 ACPI_OPERAND_OBJECT *MutexDesc; 0413 ACPI_STATUS Status; 0414 0415 0416 ACPI_FUNCTION_TRACE (DsCreateMethodMutex); 0417 0418 0419 /* Create the new mutex object */ 0420 0421 MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); 0422 if (!MutexDesc) 0423 { 0424 return_ACPI_STATUS (AE_NO_MEMORY); 0425 } 0426 0427 /* Create the actual OS Mutex */ 0428 0429 Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); 0430 if (ACPI_FAILURE (Status)) 0431 { 0432 AcpiUtDeleteObjectDesc (MutexDesc); 0433 return_ACPI_STATUS (Status); 0434 } 0435 0436 MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; 0437 MethodDesc->Method.Mutex = MutexDesc; 0438 return_ACPI_STATUS (AE_OK); 0439 } 0440 0441 0442 /******************************************************************************* 0443 * 0444 * FUNCTION: AcpiDsBeginMethodExecution 0445 * 0446 * PARAMETERS: MethodNode - Node of the method 0447 * ObjDesc - The method object 0448 * WalkState - current state, NULL if not yet executing 0449 * a method. 0450 * 0451 * RETURN: Status 0452 * 0453 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, 0454 * increments the thread count, and waits at the method semaphore 0455 * for clearance to execute. 0456 * 0457 ******************************************************************************/ 0458 0459 ACPI_STATUS 0460 AcpiDsBeginMethodExecution ( 0461 ACPI_NAMESPACE_NODE *MethodNode, 0462 ACPI_OPERAND_OBJECT *ObjDesc, 0463 ACPI_WALK_STATE *WalkState) 0464 { 0465 ACPI_STATUS Status = AE_OK; 0466 0467 0468 ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); 0469 0470 0471 if (!MethodNode) 0472 { 0473 return_ACPI_STATUS (AE_NULL_ENTRY); 0474 } 0475 0476 AcpiExStartTraceMethod (MethodNode, ObjDesc, WalkState); 0477 0478 /* Prevent wraparound of thread count */ 0479 0480 if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) 0481 { 0482 ACPI_ERROR ((AE_INFO, 0483 "Method reached maximum reentrancy limit (255)")); 0484 return_ACPI_STATUS (AE_AML_METHOD_LIMIT); 0485 } 0486 0487 /* 0488 * If this method is serialized, we need to acquire the method mutex. 0489 */ 0490 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) 0491 { 0492 /* 0493 * Create a mutex for the method if it is defined to be Serialized 0494 * and a mutex has not already been created. We defer the mutex creation 0495 * until a method is actually executed, to minimize the object count 0496 */ 0497 if (!ObjDesc->Method.Mutex) 0498 { 0499 Status = AcpiDsCreateMethodMutex (ObjDesc); 0500 if (ACPI_FAILURE (Status)) 0501 { 0502 return_ACPI_STATUS (Status); 0503 } 0504 } 0505 0506 /* 0507 * The CurrentSyncLevel (per-thread) must be less than or equal to 0508 * the sync level of the method. This mechanism provides some 0509 * deadlock prevention. 0510 * 0511 * If the method was auto-serialized, we just ignore the sync level 0512 * mechanism, because auto-serialization of methods can interfere 0513 * with ASL code that actually uses sync levels. 0514 * 0515 * Top-level method invocation has no walk state at this point 0516 */ 0517 if (WalkState && 0518 (!(ObjDesc->Method.InfoFlags & ACPI_METHOD_IGNORE_SYNC_LEVEL)) && 0519 (WalkState->Thread->CurrentSyncLevel > 0520 ObjDesc->Method.Mutex->Mutex.SyncLevel)) 0521 { 0522 ACPI_ERROR ((AE_INFO, 0523 "Cannot acquire Mutex for method [%4.4s]" 0524 ", current SyncLevel is too large (%u)", 0525 AcpiUtGetNodeName (MethodNode), 0526 WalkState->Thread->CurrentSyncLevel)); 0527 0528 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 0529 } 0530 0531 /* 0532 * Obtain the method mutex if necessary. Do not acquire mutex for a 0533 * recursive call. 0534 */ 0535 if (!WalkState || 0536 !ObjDesc->Method.Mutex->Mutex.ThreadId || 0537 (WalkState->Thread->ThreadId != 0538 ObjDesc->Method.Mutex->Mutex.ThreadId)) 0539 { 0540 /* 0541 * Acquire the method mutex. This releases the interpreter if we 0542 * block (and reacquires it before it returns) 0543 */ 0544 Status = AcpiExSystemWaitMutex ( 0545 ObjDesc->Method.Mutex->Mutex.OsMutex, ACPI_WAIT_FOREVER); 0546 if (ACPI_FAILURE (Status)) 0547 { 0548 return_ACPI_STATUS (Status); 0549 } 0550 0551 /* Update the mutex and walk info and save the original SyncLevel */ 0552 0553 if (WalkState) 0554 { 0555 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 0556 WalkState->Thread->CurrentSyncLevel; 0557 0558 ObjDesc->Method.Mutex->Mutex.ThreadId = 0559 WalkState->Thread->ThreadId; 0560 0561 /* 0562 * Update the current SyncLevel only if this is not an auto- 0563 * serialized method. In the auto case, we have to ignore 0564 * the sync level for the method mutex (created for the 0565 * auto-serialization) because we have no idea of what the 0566 * sync level should be. Therefore, just ignore it. 0567 */ 0568 if (!(ObjDesc->Method.InfoFlags & 0569 ACPI_METHOD_IGNORE_SYNC_LEVEL)) 0570 { 0571 WalkState->Thread->CurrentSyncLevel = 0572 ObjDesc->Method.SyncLevel; 0573 } 0574 } 0575 else 0576 { 0577 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 0578 ObjDesc->Method.Mutex->Mutex.SyncLevel; 0579 0580 ObjDesc->Method.Mutex->Mutex.ThreadId = 0581 AcpiOsGetThreadId (); 0582 } 0583 } 0584 0585 /* Always increase acquisition depth */ 0586 0587 ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; 0588 } 0589 0590 /* 0591 * Allocate an Owner ID for this method, only if this is the first thread 0592 * to begin concurrent execution. We only need one OwnerId, even if the 0593 * method is invoked recursively. 0594 */ 0595 if (!ObjDesc->Method.OwnerId) 0596 { 0597 Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 0598 if (ACPI_FAILURE (Status)) 0599 { 0600 goto Cleanup; 0601 } 0602 } 0603 0604 /* 0605 * Increment the method parse tree thread count since it has been 0606 * reentered one more time (even if it is the same thread) 0607 */ 0608 ObjDesc->Method.ThreadCount++; 0609 AcpiMethodCount++; 0610 return_ACPI_STATUS (Status); 0611 0612 0613 Cleanup: 0614 /* On error, must release the method mutex (if present) */ 0615 0616 if (ObjDesc->Method.Mutex) 0617 { 0618 AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); 0619 } 0620 return_ACPI_STATUS (Status); 0621 } 0622 0623 0624 /******************************************************************************* 0625 * 0626 * FUNCTION: AcpiDsCallControlMethod 0627 * 0628 * PARAMETERS: Thread - Info for this thread 0629 * ThisWalkState - Current walk state 0630 * Op - Current Op to be walked 0631 * 0632 * RETURN: Status 0633 * 0634 * DESCRIPTION: Transfer execution to a called control method 0635 * 0636 ******************************************************************************/ 0637 0638 ACPI_STATUS 0639 AcpiDsCallControlMethod ( 0640 ACPI_THREAD_STATE *Thread, 0641 ACPI_WALK_STATE *ThisWalkState, 0642 ACPI_PARSE_OBJECT *Op) 0643 { 0644 ACPI_STATUS Status; 0645 ACPI_NAMESPACE_NODE *MethodNode; 0646 ACPI_WALK_STATE *NextWalkState = NULL; 0647 ACPI_OPERAND_OBJECT *ObjDesc; 0648 ACPI_EVALUATE_INFO *Info; 0649 UINT32 i; 0650 0651 0652 ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); 0653 0654 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 0655 "Calling method %p, currentstate=%p\n", 0656 ThisWalkState->PrevOp, ThisWalkState)); 0657 0658 /* 0659 * Get the namespace entry for the control method we are about to call 0660 */ 0661 MethodNode = ThisWalkState->MethodCallNode; 0662 if (!MethodNode) 0663 { 0664 return_ACPI_STATUS (AE_NULL_ENTRY); 0665 } 0666 0667 ObjDesc = AcpiNsGetAttachedObject (MethodNode); 0668 if (!ObjDesc) 0669 { 0670 return_ACPI_STATUS (AE_NULL_OBJECT); 0671 } 0672 0673 /* Init for new method, possibly wait on method mutex */ 0674 0675 Status = AcpiDsBeginMethodExecution ( 0676 MethodNode, ObjDesc, ThisWalkState); 0677 if (ACPI_FAILURE (Status)) 0678 { 0679 return_ACPI_STATUS (Status); 0680 } 0681 0682 /* Begin method parse/execution. Create a new walk state */ 0683 0684 NextWalkState = AcpiDsCreateWalkState ( 0685 ObjDesc->Method.OwnerId, NULL, ObjDesc, Thread); 0686 if (!NextWalkState) 0687 { 0688 Status = AE_NO_MEMORY; 0689 goto Cleanup; 0690 } 0691 0692 /* 0693 * The resolved arguments were put on the previous walk state's operand 0694 * stack. Operands on the previous walk state stack always 0695 * start at index 0. Also, null terminate the list of arguments 0696 */ 0697 ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; 0698 0699 /* 0700 * Allocate and initialize the evaluation information block 0701 * TBD: this is somewhat inefficient, should change interface to 0702 * DsInitAmlWalk. For now, keeps this struct off the CPU stack 0703 */ 0704 Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 0705 if (!Info) 0706 { 0707 Status = AE_NO_MEMORY; 0708 goto PopWalkState; 0709 } 0710 0711 Info->Parameters = &ThisWalkState->Operands[0]; 0712 0713 Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, 0714 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, 0715 Info, ACPI_IMODE_EXECUTE); 0716 0717 ACPI_FREE (Info); 0718 if (ACPI_FAILURE (Status)) 0719 { 0720 goto PopWalkState; 0721 } 0722 0723 NextWalkState->MethodNestingDepth = ThisWalkState->MethodNestingDepth + 1; 0724 0725 /* 0726 * Delete the operands on the previous walkstate operand stack 0727 * (they were copied to new objects) 0728 */ 0729 for (i = 0; i < ObjDesc->Method.ParamCount; i++) 0730 { 0731 AcpiUtRemoveReference (ThisWalkState->Operands [i]); 0732 ThisWalkState->Operands [i] = NULL; 0733 } 0734 0735 /* Clear the operand stack */ 0736 0737 ThisWalkState->NumOperands = 0; 0738 0739 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 0740 "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 0741 MethodNode->Name.Ascii, NextWalkState)); 0742 0743 ThisWalkState->MethodPathname = AcpiNsGetNormalizedPathname (MethodNode, TRUE); 0744 ThisWalkState->MethodIsNested = TRUE; 0745 0746 /* Optional object evaluation log */ 0747 0748 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EVALUATION, 0749 "%-26s: %*s%s\n", " Nested method call", 0750 NextWalkState->MethodNestingDepth * 3, " ", 0751 &ThisWalkState->MethodPathname[1])); 0752 0753 /* Invoke an internal method if necessary */ 0754 0755 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) 0756 { 0757 Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); 0758 if (Status == AE_OK) 0759 { 0760 Status = AE_CTRL_TERMINATE; 0761 } 0762 } 0763 0764 return_ACPI_STATUS (Status); 0765 0766 0767 PopWalkState: 0768 0769 /* On error, pop the walk state to be deleted from thread */ 0770 0771 AcpiDsPopWalkState(Thread); 0772 0773 Cleanup: 0774 0775 /* On error, we must terminate the method properly */ 0776 0777 AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); 0778 AcpiDsDeleteWalkState (NextWalkState); 0779 0780 return_ACPI_STATUS (Status); 0781 } 0782 0783 0784 /******************************************************************************* 0785 * 0786 * FUNCTION: AcpiDsRestartControlMethod 0787 * 0788 * PARAMETERS: WalkState - State for preempted method (caller) 0789 * ReturnDesc - Return value from the called method 0790 * 0791 * RETURN: Status 0792 * 0793 * DESCRIPTION: Restart a method that was preempted by another (nested) method 0794 * invocation. Handle the return value (if any) from the callee. 0795 * 0796 ******************************************************************************/ 0797 0798 ACPI_STATUS 0799 AcpiDsRestartControlMethod ( 0800 ACPI_WALK_STATE *WalkState, 0801 ACPI_OPERAND_OBJECT *ReturnDesc) 0802 { 0803 ACPI_STATUS Status; 0804 int SameAsImplicitReturn; 0805 0806 0807 ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); 0808 0809 0810 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 0811 "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 0812 AcpiUtGetNodeName (WalkState->MethodNode), 0813 WalkState->MethodCallOp, ReturnDesc)); 0814 0815 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 0816 " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 0817 WalkState->ReturnUsed, 0818 WalkState->Results, WalkState)); 0819 0820 /* Did the called method return a value? */ 0821 0822 if (ReturnDesc) 0823 { 0824 /* Is the implicit return object the same as the return desc? */ 0825 0826 SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); 0827 0828 /* Are we actually going to use the return value? */ 0829 0830 if (WalkState->ReturnUsed) 0831 { 0832 /* Save the return value from the previous method */ 0833 0834 Status = AcpiDsResultPush (ReturnDesc, WalkState); 0835 if (ACPI_FAILURE (Status)) 0836 { 0837 AcpiUtRemoveReference (ReturnDesc); 0838 return_ACPI_STATUS (Status); 0839 } 0840 0841 /* 0842 * Save as THIS method's return value in case it is returned 0843 * immediately to yet another method 0844 */ 0845 WalkState->ReturnDesc = ReturnDesc; 0846 } 0847 0848 /* 0849 * The following code is the optional support for the so-called 0850 * "implicit return". Some AML code assumes that the last value of the 0851 * method is "implicitly" returned to the caller, in the absence of an 0852 * explicit return value. 0853 * 0854 * Just save the last result of the method as the return value. 0855 * 0856 * NOTE: this is optional because the ASL language does not actually 0857 * support this behavior. 0858 */ 0859 else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || 0860 SameAsImplicitReturn) 0861 { 0862 /* 0863 * Delete the return value if it will not be used by the 0864 * calling method or remove one reference if the explicit return 0865 * is the same as the implicit return value. 0866 */ 0867 AcpiUtRemoveReference (ReturnDesc); 0868 } 0869 } 0870 0871 return_ACPI_STATUS (AE_OK); 0872 } 0873 0874 0875 /******************************************************************************* 0876 * 0877 * FUNCTION: AcpiDsTerminateControlMethod 0878 * 0879 * PARAMETERS: MethodDesc - Method object 0880 * WalkState - State associated with the method 0881 * 0882 * RETURN: None 0883 * 0884 * DESCRIPTION: Terminate a control method. Delete everything that the method 0885 * created, delete all locals and arguments, and delete the parse 0886 * tree if requested. 0887 * 0888 * MUTEX: Interpreter is locked 0889 * 0890 ******************************************************************************/ 0891 0892 void 0893 AcpiDsTerminateControlMethod ( 0894 ACPI_OPERAND_OBJECT *MethodDesc, 0895 ACPI_WALK_STATE *WalkState) 0896 { 0897 0898 ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); 0899 0900 0901 /* MethodDesc is required, WalkState is optional */ 0902 0903 if (!MethodDesc) 0904 { 0905 return_VOID; 0906 } 0907 0908 if (WalkState) 0909 { 0910 /* Delete all arguments and locals */ 0911 0912 AcpiDsMethodDataDeleteAll (WalkState); 0913 0914 /* 0915 * Delete any namespace objects created anywhere within the 0916 * namespace by the execution of this method. Unless: 0917 * 1) This method is a module-level executable code method, in which 0918 * case we want make the objects permanent. 0919 * 2) There are other threads executing the method, in which case we 0920 * will wait until the last thread has completed. 0921 */ 0922 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && 0923 (MethodDesc->Method.ThreadCount == 1)) 0924 { 0925 /* Delete any direct children of (created by) this method */ 0926 0927 (void) AcpiExExitInterpreter (); 0928 AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); 0929 (void) AcpiExEnterInterpreter (); 0930 0931 /* 0932 * Delete any objects that were created by this method 0933 * elsewhere in the namespace (if any were created). 0934 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 0935 * deletion such that we don't have to perform an entire 0936 * namespace walk for every control method execution. 0937 */ 0938 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) 0939 { 0940 (void) AcpiExExitInterpreter (); 0941 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); 0942 (void) AcpiExEnterInterpreter (); 0943 MethodDesc->Method.InfoFlags &= 0944 ~ACPI_METHOD_MODIFIED_NAMESPACE; 0945 } 0946 } 0947 0948 /* 0949 * If method is serialized, release the mutex and restore the 0950 * current sync level for this thread 0951 */ 0952 if (MethodDesc->Method.Mutex) 0953 { 0954 /* Acquisition Depth handles recursive calls */ 0955 0956 MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; 0957 if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) 0958 { 0959 WalkState->Thread->CurrentSyncLevel = 0960 MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; 0961 0962 AcpiOsReleaseMutex ( 0963 MethodDesc->Method.Mutex->Mutex.OsMutex); 0964 MethodDesc->Method.Mutex->Mutex.ThreadId = 0; 0965 } 0966 } 0967 } 0968 0969 /* Decrement the thread count on the method */ 0970 0971 if (MethodDesc->Method.ThreadCount) 0972 { 0973 MethodDesc->Method.ThreadCount--; 0974 } 0975 else 0976 { 0977 ACPI_ERROR ((AE_INFO, 0978 "Invalid zero thread count in method")); 0979 } 0980 0981 /* Are there any other threads currently executing this method? */ 0982 0983 if (MethodDesc->Method.ThreadCount) 0984 { 0985 /* 0986 * Additional threads. Do not release the OwnerId in this case, 0987 * we immediately reuse it for the next thread executing this method 0988 */ 0989 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 0990 "*** Completed execution of one thread, %u threads remaining\n", 0991 MethodDesc->Method.ThreadCount)); 0992 } 0993 else 0994 { 0995 /* This is the only executing thread for this method */ 0996 0997 /* 0998 * Support to dynamically change a method from NotSerialized to 0999 * Serialized if it appears that the method is incorrectly written and 1000 * does not support multiple thread execution. The best example of this 1001 * is if such a method creates namespace objects and blocks. A second 1002 * thread will fail with an AE_ALREADY_EXISTS exception. 1003 * 1004 * This code is here because we must wait until the last thread exits 1005 * before marking the method as serialized. 1006 */ 1007 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) 1008 { 1009 if (WalkState) 1010 { 1011 ACPI_INFO (( 1012 "Marking method %4.4s as Serialized " 1013 "because of AE_ALREADY_EXISTS error", 1014 WalkState->MethodNode->Name.Ascii)); 1015 } 1016 1017 /* 1018 * Method tried to create an object twice and was marked as 1019 * "pending serialized". The probable cause is that the method 1020 * cannot handle reentrancy. 1021 * 1022 * The method was created as NotSerialized, but it tried to create 1023 * a named object and then blocked, causing the second thread 1024 * entrance to begin and then fail. Workaround this problem by 1025 * marking the method permanently as Serialized when the last 1026 * thread exits here. 1027 */ 1028 MethodDesc->Method.InfoFlags &= 1029 ~ACPI_METHOD_SERIALIZED_PENDING; 1030 1031 MethodDesc->Method.InfoFlags |= 1032 (ACPI_METHOD_SERIALIZED | ACPI_METHOD_IGNORE_SYNC_LEVEL); 1033 MethodDesc->Method.SyncLevel = 0; 1034 } 1035 1036 /* No more threads, we can free the OwnerId */ 1037 1038 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) 1039 { 1040 AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); 1041 } 1042 } 1043 1044 AcpiExStopTraceMethod ((ACPI_NAMESPACE_NODE *) MethodDesc->Method.Node, 1045 MethodDesc, WalkState); 1046 1047 return_VOID; 1048 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |