xref: /haiku/src/add-ons/kernel/bus_managers/acpi/acpica/components/parser/psparse.c (revision 632e56d8e514ba6ac41f582ce580e51a3cd8922e)
1 /******************************************************************************
2  *
3  * Module Name: psparse - Parser top level AML parse routines
4  *
5  *****************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2016, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government. In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************/
115 
116 /*
117  * Parse the AML and build an operation tree as most interpreters,
118  * like Perl, do. Parsing is done by hand rather than with a YACC
119  * generated parser to tightly constrain stack and dynamic memory
120  * usage. At the same time, parsing is kept flexible and the code
121  * fairly compact by parsing based on a list of AML opcode
122  * templates in AmlOpInfo[]
123  */
124 
125 #include "acpi.h"
126 #include "accommon.h"
127 #include "acparser.h"
128 #include "acdispat.h"
129 #include "amlcode.h"
130 #include "acinterp.h"
131 
132 #define _COMPONENT          ACPI_PARSER
133         ACPI_MODULE_NAME    ("psparse")
134 
135 
136 /*******************************************************************************
137  *
138  * FUNCTION:    AcpiPsGetOpcodeSize
139  *
140  * PARAMETERS:  Opcode          - An AML opcode
141  *
142  * RETURN:      Size of the opcode, in bytes (1 or 2)
143  *
144  * DESCRIPTION: Get the size of the current opcode.
145  *
146  ******************************************************************************/
147 
148 UINT32
149 AcpiPsGetOpcodeSize (
150     UINT32                  Opcode)
151 {
152 
153     /* Extended (2-byte) opcode if > 255 */
154 
155     if (Opcode > 0x00FF)
156     {
157         return (2);
158     }
159 
160     /* Otherwise, just a single byte opcode */
161 
162     return (1);
163 }
164 
165 
166 /*******************************************************************************
167  *
168  * FUNCTION:    AcpiPsPeekOpcode
169  *
170  * PARAMETERS:  ParserState         - A parser state object
171  *
172  * RETURN:      Next AML opcode
173  *
174  * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
175  *
176  ******************************************************************************/
177 
178 UINT16
179 AcpiPsPeekOpcode (
180     ACPI_PARSE_STATE        *ParserState)
181 {
182     UINT8                   *Aml;
183     UINT16                  Opcode;
184 
185 
186     Aml = ParserState->Aml;
187     Opcode = (UINT16) ACPI_GET8 (Aml);
188 
189     if (Opcode == AML_EXTENDED_OP_PREFIX)
190     {
191         /* Extended opcode, get the second opcode byte */
192 
193         Aml++;
194         Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml));
195     }
196 
197     return (Opcode);
198 }
199 
200 
201 /*******************************************************************************
202  *
203  * FUNCTION:    AcpiPsCompleteThisOp
204  *
205  * PARAMETERS:  WalkState       - Current State
206  *              Op              - Op to complete
207  *
208  * RETURN:      Status
209  *
210  * DESCRIPTION: Perform any cleanup at the completion of an Op.
211  *
212  ******************************************************************************/
213 
214 ACPI_STATUS
215 AcpiPsCompleteThisOp (
216     ACPI_WALK_STATE         *WalkState,
217     ACPI_PARSE_OBJECT       *Op)
218 {
219     ACPI_PARSE_OBJECT       *Prev;
220     ACPI_PARSE_OBJECT       *Next;
221     const ACPI_OPCODE_INFO  *ParentInfo;
222     ACPI_PARSE_OBJECT       *ReplacementOp = NULL;
223     ACPI_STATUS             Status = AE_OK;
224 
225 
226     ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op);
227 
228 
229     /* Check for null Op, can happen if AML code is corrupt */
230 
231     if (!Op)
232     {
233         return_ACPI_STATUS (AE_OK);  /* OK for now */
234     }
235 
236     AcpiExStopTraceOpcode (Op, WalkState);
237 
238     /* Delete this op and the subtree below it if asked to */
239 
240     if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
241          (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT))
242     {
243         return_ACPI_STATUS (AE_OK);
244     }
245 
246     /* Make sure that we only delete this subtree */
247 
248     if (Op->Common.Parent)
249     {
250         Prev = Op->Common.Parent->Common.Value.Arg;
251         if (!Prev)
252         {
253             /* Nothing more to do */
254 
255             goto Cleanup;
256         }
257 
258         /*
259          * Check if we need to replace the operator and its subtree
260          * with a return value op (placeholder op)
261          */
262         ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode);
263 
264         switch (ParentInfo->Class)
265         {
266         case AML_CLASS_CONTROL:
267 
268             break;
269 
270         case AML_CLASS_CREATE:
271             /*
272              * These opcodes contain TermArg operands. The current
273              * op must be replaced by a placeholder return op
274              */
275             ReplacementOp = AcpiPsAllocOp (
276                 AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
277             if (!ReplacementOp)
278             {
279                 Status = AE_NO_MEMORY;
280             }
281             break;
282 
283         case AML_CLASS_NAMED_OBJECT:
284             /*
285              * These opcodes contain TermArg operands. The current
286              * op must be replaced by a placeholder return op
287              */
288             if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP)       ||
289                 (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP)  ||
290                 (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP)       ||
291                 (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP)      ||
292                 (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)   ||
293                 (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
294             {
295                 ReplacementOp = AcpiPsAllocOp (
296                     AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
297                 if (!ReplacementOp)
298                 {
299                     Status = AE_NO_MEMORY;
300                 }
301             }
302             else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
303                      (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
304             {
305                 if ((Op->Common.AmlOpcode == AML_BUFFER_OP) ||
306                     (Op->Common.AmlOpcode == AML_PACKAGE_OP) ||
307                     (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP))
308                 {
309                     ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode,
310                         Op->Common.Aml);
311                     if (!ReplacementOp)
312                     {
313                         Status = AE_NO_MEMORY;
314                     }
315                     else
316                     {
317                         ReplacementOp->Named.Data = Op->Named.Data;
318                         ReplacementOp->Named.Length = Op->Named.Length;
319                     }
320                 }
321             }
322             break;
323 
324         default:
325 
326             ReplacementOp = AcpiPsAllocOp (
327                 AML_INT_RETURN_VALUE_OP, Op->Common.Aml);
328             if (!ReplacementOp)
329             {
330                 Status = AE_NO_MEMORY;
331             }
332         }
333 
334         /* We must unlink this op from the parent tree */
335 
336         if (Prev == Op)
337         {
338             /* This op is the first in the list */
339 
340             if (ReplacementOp)
341             {
342                 ReplacementOp->Common.Parent = Op->Common.Parent;
343                 ReplacementOp->Common.Value.Arg = NULL;
344                 ReplacementOp->Common.Node = Op->Common.Node;
345                 Op->Common.Parent->Common.Value.Arg = ReplacementOp;
346                 ReplacementOp->Common.Next = Op->Common.Next;
347             }
348             else
349             {
350                 Op->Common.Parent->Common.Value.Arg = Op->Common.Next;
351             }
352         }
353 
354         /* Search the parent list */
355 
356         else while (Prev)
357         {
358             /* Traverse all siblings in the parent's argument list */
359 
360             Next = Prev->Common.Next;
361             if (Next == Op)
362             {
363                 if (ReplacementOp)
364                 {
365                     ReplacementOp->Common.Parent = Op->Common.Parent;
366                     ReplacementOp->Common.Value.Arg = NULL;
367                     ReplacementOp->Common.Node = Op->Common.Node;
368                     Prev->Common.Next = ReplacementOp;
369                     ReplacementOp->Common.Next = Op->Common.Next;
370                     Next = NULL;
371                 }
372                 else
373                 {
374                     Prev->Common.Next = Op->Common.Next;
375                     Next = NULL;
376                 }
377             }
378             Prev = Next;
379         }
380     }
381 
382 
383 Cleanup:
384 
385     /* Now we can actually delete the subtree rooted at Op */
386 
387     AcpiPsDeleteParseTree (Op);
388     return_ACPI_STATUS (Status);
389 }
390 
391 
392 /*******************************************************************************
393  *
394  * FUNCTION:    AcpiPsNextParseState
395  *
396  * PARAMETERS:  WalkState           - Current state
397  *              Op                  - Current parse op
398  *              CallbackStatus      - Status from previous operation
399  *
400  * RETURN:      Status
401  *
402  * DESCRIPTION: Update the parser state based upon the return exception from
403  *              the parser callback.
404  *
405  ******************************************************************************/
406 
407 ACPI_STATUS
408 AcpiPsNextParseState (
409     ACPI_WALK_STATE         *WalkState,
410     ACPI_PARSE_OBJECT       *Op,
411     ACPI_STATUS             CallbackStatus)
412 {
413     ACPI_PARSE_STATE        *ParserState = &WalkState->ParserState;
414     ACPI_STATUS             Status = AE_CTRL_PENDING;
415 
416 
417     ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op);
418 
419 
420     switch (CallbackStatus)
421     {
422     case AE_CTRL_TERMINATE:
423         /*
424          * A control method was terminated via a RETURN statement.
425          * The walk of this method is complete.
426          */
427         ParserState->Aml = ParserState->AmlEnd;
428         Status = AE_CTRL_TERMINATE;
429         break;
430 
431     case AE_CTRL_BREAK:
432 
433         ParserState->Aml = WalkState->AmlLastWhile;
434         WalkState->ControlState->Common.Value = FALSE;
435         Status = AE_CTRL_BREAK;
436         break;
437 
438     case AE_CTRL_CONTINUE:
439 
440         ParserState->Aml = WalkState->AmlLastWhile;
441         Status = AE_CTRL_CONTINUE;
442         break;
443 
444     case AE_CTRL_PENDING:
445 
446         ParserState->Aml = WalkState->AmlLastWhile;
447         break;
448 
449 #if 0
450     case AE_CTRL_SKIP:
451 
452         ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
453         Status = AE_OK;
454         break;
455 #endif
456 
457     case AE_CTRL_TRUE:
458         /*
459          * Predicate of an IF was true, and we are at the matching ELSE.
460          * Just close out this package
461          */
462         ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState);
463         Status = AE_CTRL_PENDING;
464         break;
465 
466     case AE_CTRL_FALSE:
467         /*
468          * Either an IF/WHILE Predicate was false or we encountered a BREAK
469          * opcode. In both cases, we do not execute the rest of the
470          * package;  We simply close out the parent (finishing the walk of
471          * this branch of the tree) and continue execution at the parent
472          * level.
473          */
474         ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd;
475 
476         /* In the case of a BREAK, just force a predicate (if any) to FALSE */
477 
478         WalkState->ControlState->Common.Value = FALSE;
479         Status = AE_CTRL_END;
480         break;
481 
482     case AE_CTRL_TRANSFER:
483 
484         /* A method call (invocation) -- transfer control */
485 
486         Status = AE_CTRL_TRANSFER;
487         WalkState->PrevOp = Op;
488         WalkState->MethodCallOp = Op;
489         WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node;
490 
491         /* Will return value (if any) be used by the caller? */
492 
493         WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState);
494         break;
495 
496     default:
497 
498         Status = CallbackStatus;
499         if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL)
500         {
501             Status = AE_OK;
502         }
503         break;
504     }
505 
506     return_ACPI_STATUS (Status);
507 }
508 
509 
510 /*******************************************************************************
511  *
512  * FUNCTION:    AcpiPsParseAml
513  *
514  * PARAMETERS:  WalkState       - Current state
515  *
516  *
517  * RETURN:      Status
518  *
519  * DESCRIPTION: Parse raw AML and return a tree of ops
520  *
521  ******************************************************************************/
522 
523 ACPI_STATUS
524 AcpiPsParseAml (
525     ACPI_WALK_STATE         *WalkState)
526 {
527     ACPI_STATUS             Status;
528     ACPI_THREAD_STATE       *Thread;
529     ACPI_THREAD_STATE       *PrevWalkList = AcpiGbl_CurrentWalkList;
530     ACPI_WALK_STATE         *PreviousWalkState;
531 
532 
533     ACPI_FUNCTION_TRACE (PsParseAml);
534 
535     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
536         "Entered with WalkState=%p Aml=%p size=%X\n",
537         WalkState, WalkState->ParserState.Aml,
538         WalkState->ParserState.AmlSize));
539 
540     if (!WalkState->ParserState.Aml)
541     {
542         return_ACPI_STATUS (AE_NULL_OBJECT);
543     }
544 
545     /* Create and initialize a new thread state */
546 
547     Thread = AcpiUtCreateThreadState ();
548     if (!Thread)
549     {
550         if (WalkState->MethodDesc)
551         {
552             /* Executing a control method - additional cleanup */
553 
554             AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
555         }
556 
557         AcpiDsDeleteWalkState (WalkState);
558         return_ACPI_STATUS (AE_NO_MEMORY);
559     }
560 
561     WalkState->Thread = Thread;
562 
563     /*
564      * If executing a method, the starting SyncLevel is this method's
565      * SyncLevel
566      */
567     if (WalkState->MethodDesc)
568     {
569         WalkState->Thread->CurrentSyncLevel =
570             WalkState->MethodDesc->Method.SyncLevel;
571     }
572 
573     AcpiDsPushWalkState (WalkState, Thread);
574 
575     /*
576      * This global allows the AML debugger to get a handle to the currently
577      * executing control method.
578      */
579     AcpiGbl_CurrentWalkList = Thread;
580 
581     /*
582      * Execute the walk loop as long as there is a valid Walk State. This
583      * handles nested control method invocations without recursion.
584      */
585     ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", WalkState));
586 
587     Status = AE_OK;
588     while (WalkState)
589     {
590         if (ACPI_SUCCESS (Status))
591         {
592             /*
593              * The ParseLoop executes AML until the method terminates
594              * or calls another method.
595              */
596             Status = AcpiPsParseLoop (WalkState);
597         }
598 
599         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
600             "Completed one call to walk loop, %s State=%p\n",
601             AcpiFormatException (Status), WalkState));
602 
603         if (Status == AE_CTRL_TRANSFER)
604         {
605             /*
606              * A method call was detected.
607              * Transfer control to the called control method
608              */
609             Status = AcpiDsCallControlMethod (Thread, WalkState, NULL);
610             if (ACPI_FAILURE (Status))
611             {
612                 Status = AcpiDsMethodError (Status, WalkState);
613             }
614 
615             /*
616              * If the transfer to the new method method call worked
617              *, a new walk state was created -- get it
618              */
619             WalkState = AcpiDsGetCurrentWalkState (Thread);
620             continue;
621         }
622         else if (Status == AE_CTRL_TERMINATE)
623         {
624             Status = AE_OK;
625         }
626         else if ((Status != AE_OK) && (WalkState->MethodDesc))
627         {
628             /* Either the method parse or actual execution failed */
629 
630             ACPI_ERROR_METHOD ("Method parse/execution failed",
631                 WalkState->MethodNode, NULL, Status);
632 
633             /* Check for possible multi-thread reentrancy problem */
634 
635             if ((Status == AE_ALREADY_EXISTS) &&
636                 (!(WalkState->MethodDesc->Method.InfoFlags &
637                     ACPI_METHOD_SERIALIZED)))
638             {
639                 /*
640                  * Method is not serialized and tried to create an object
641                  * twice. The probable cause is that the method cannot
642                  * handle reentrancy. Mark as "pending serialized" now, and
643                  * then mark "serialized" when the last thread exits.
644                  */
645                 WalkState->MethodDesc->Method.InfoFlags |=
646                     ACPI_METHOD_SERIALIZED_PENDING;
647             }
648         }
649 
650         /* We are done with this walk, move on to the parent if any */
651 
652         WalkState = AcpiDsPopWalkState (Thread);
653 
654         /* Reset the current scope to the beginning of scope stack */
655 
656         AcpiDsScopeStackClear (WalkState);
657 
658         /*
659          * If we just returned from the execution of a control method or if we
660          * encountered an error during the method parse phase, there's lots of
661          * cleanup to do
662          */
663         if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) ==
664             ACPI_PARSE_EXECUTE) ||
665             (ACPI_FAILURE (Status)))
666         {
667             AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState);
668         }
669 
670         /* Delete this walk state and all linked control states */
671 
672         AcpiPsCleanupScope (&WalkState->ParserState);
673         PreviousWalkState = WalkState;
674 
675         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
676             "ReturnValue=%p, ImplicitValue=%p State=%p\n",
677             WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState));
678 
679         /* Check if we have restarted a preempted walk */
680 
681         WalkState = AcpiDsGetCurrentWalkState (Thread);
682         if (WalkState)
683         {
684             if (ACPI_SUCCESS (Status))
685             {
686                 /*
687                  * There is another walk state, restart it.
688                  * If the method return value is not used by the parent,
689                  * The object is deleted
690                  */
691                 if (!PreviousWalkState->ReturnDesc)
692                 {
693                     /*
694                      * In slack mode execution, if there is no return value
695                      * we should implicitly return zero (0) as a default value.
696                      */
697                     if (AcpiGbl_EnableInterpreterSlack &&
698                         !PreviousWalkState->ImplicitReturnObj)
699                     {
700                         PreviousWalkState->ImplicitReturnObj =
701                             AcpiUtCreateIntegerObject ((UINT64) 0);
702                         if (!PreviousWalkState->ImplicitReturnObj)
703                         {
704                             return_ACPI_STATUS (AE_NO_MEMORY);
705                         }
706                     }
707 
708                     /* Restart the calling control method */
709 
710                     Status = AcpiDsRestartControlMethod (WalkState,
711                         PreviousWalkState->ImplicitReturnObj);
712                 }
713                 else
714                 {
715                     /*
716                      * We have a valid return value, delete any implicit
717                      * return value.
718                      */
719                     AcpiDsClearImplicitReturn (PreviousWalkState);
720 
721                     Status = AcpiDsRestartControlMethod (WalkState,
722                         PreviousWalkState->ReturnDesc);
723                 }
724                 if (ACPI_SUCCESS (Status))
725                 {
726                     WalkState->WalkType |= ACPI_WALK_METHOD_RESTART;
727                 }
728             }
729             else
730             {
731                 /* On error, delete any return object or implicit return */
732 
733                 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
734                 AcpiDsClearImplicitReturn (PreviousWalkState);
735             }
736         }
737 
738         /*
739          * Just completed a 1st-level method, save the final internal return
740          * value (if any)
741          */
742         else if (PreviousWalkState->CallerReturnDesc)
743         {
744             if (PreviousWalkState->ImplicitReturnObj)
745             {
746                 *(PreviousWalkState->CallerReturnDesc) =
747                     PreviousWalkState->ImplicitReturnObj;
748             }
749             else
750             {
751                  /* NULL if no return value */
752 
753                 *(PreviousWalkState->CallerReturnDesc) =
754                     PreviousWalkState->ReturnDesc;
755             }
756         }
757         else
758         {
759             if (PreviousWalkState->ReturnDesc)
760             {
761                 /* Caller doesn't want it, must delete it */
762 
763                 AcpiUtRemoveReference (PreviousWalkState->ReturnDesc);
764             }
765             if (PreviousWalkState->ImplicitReturnObj)
766             {
767                 /* Caller doesn't want it, must delete it */
768 
769                 AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj);
770             }
771         }
772 
773         AcpiDsDeleteWalkState (PreviousWalkState);
774     }
775 
776     /* Normal exit */
777 
778     AcpiExReleaseAllMutexes (Thread);
779     AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread));
780     AcpiGbl_CurrentWalkList = PrevWalkList;
781     return_ACPI_STATUS (Status);
782 }
783