1 /*******************************************************************************
2  *
3  * Module Name: dsutils - Dispatcher utilities
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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 "acpi.h"
45 #include "accommon.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acdispat.h"
49 #include "acinterp.h"
50 #include "acnamesp.h"
51 #include "acdebug.h"
52 
53 #define _COMPONENT          ACPI_DISPATCHER
54         ACPI_MODULE_NAME    ("dsutils")
55 
56 
57 /*******************************************************************************
58  *
59  * FUNCTION:    AcpiDsClearImplicitReturn
60  *
61  * PARAMETERS:  WalkState           - Current State
62  *
63  * RETURN:      None.
64  *
65  * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
66  *              to delete "stale" return values (if enabled, the return value
67  *              from every operator is saved at least momentarily, in case the
68  *              parent method exits.)
69  *
70  ******************************************************************************/
71 
72 void
AcpiDsClearImplicitReturn(ACPI_WALK_STATE * WalkState)73 AcpiDsClearImplicitReturn (
74     ACPI_WALK_STATE         *WalkState)
75 {
76     ACPI_FUNCTION_NAME (DsClearImplicitReturn);
77 
78 
79     /*
80      * Slack must be enabled for this feature
81      */
82     if (!AcpiGbl_EnableInterpreterSlack)
83     {
84         return;
85     }
86 
87     if (WalkState->ImplicitReturnObj)
88     {
89         /*
90          * Delete any "stale" implicit return. However, in
91          * complex statements, the implicit return value can be
92          * bubbled up several levels.
93          */
94         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
95             "Removing reference on stale implicit return obj %p\n",
96             WalkState->ImplicitReturnObj));
97 
98         AcpiUtRemoveReference (WalkState->ImplicitReturnObj);
99         WalkState->ImplicitReturnObj = NULL;
100     }
101 }
102 
103 
104 /*******************************************************************************
105  *
106  * FUNCTION:    AcpiDsDoImplicitReturn
107  *
108  * PARAMETERS:  ReturnDesc          - The return value
109  *              WalkState           - Current State
110  *              AddReference        - True if a reference should be added to the
111  *                                    return object
112  *
113  * RETURN:      TRUE if implicit return enabled, FALSE otherwise
114  *
115  * DESCRIPTION: Implements the optional "implicit return".  We save the result
116  *              of every ASL operator and control method invocation in case the
117  *              parent method exit. Before storing a new return value, we
118  *              delete the previous return value.
119  *
120  ******************************************************************************/
121 
122 BOOLEAN
AcpiDsDoImplicitReturn(ACPI_OPERAND_OBJECT * ReturnDesc,ACPI_WALK_STATE * WalkState,BOOLEAN AddReference)123 AcpiDsDoImplicitReturn (
124     ACPI_OPERAND_OBJECT     *ReturnDesc,
125     ACPI_WALK_STATE         *WalkState,
126     BOOLEAN                 AddReference)
127 {
128     ACPI_FUNCTION_NAME (DsDoImplicitReturn);
129 
130 
131     /*
132      * Slack must be enabled for this feature, and we must
133      * have a valid return object
134      */
135     if ((!AcpiGbl_EnableInterpreterSlack) ||
136         (!ReturnDesc))
137     {
138         return (FALSE);
139     }
140 
141     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
142         "Result %p will be implicitly returned; Prev=%p\n",
143         ReturnDesc,
144         WalkState->ImplicitReturnObj));
145 
146     /*
147      * Delete any "stale" implicit return value first. However, in
148      * complex statements, the implicit return value can be
149      * bubbled up several levels, so we don't clear the value if it
150      * is the same as the ReturnDesc.
151      */
152     if (WalkState->ImplicitReturnObj)
153     {
154         if (WalkState->ImplicitReturnObj == ReturnDesc)
155         {
156             return (TRUE);
157         }
158         AcpiDsClearImplicitReturn (WalkState);
159     }
160 
161     /* Save the implicit return value, add a reference if requested */
162 
163     WalkState->ImplicitReturnObj = ReturnDesc;
164     if (AddReference)
165     {
166         AcpiUtAddReference (ReturnDesc);
167     }
168 
169     return (TRUE);
170 }
171 
172 
173 /*******************************************************************************
174  *
175  * FUNCTION:    AcpiDsIsResultUsed
176  *
177  * PARAMETERS:  Op                  - Current Op
178  *              WalkState           - Current State
179  *
180  * RETURN:      TRUE if result is used, FALSE otherwise
181  *
182  * DESCRIPTION: Check if a result object will be used by the parent
183  *
184  ******************************************************************************/
185 
186 BOOLEAN
AcpiDsIsResultUsed(ACPI_PARSE_OBJECT * Op,ACPI_WALK_STATE * WalkState)187 AcpiDsIsResultUsed (
188     ACPI_PARSE_OBJECT       *Op,
189     ACPI_WALK_STATE         *WalkState)
190 {
191     const ACPI_OPCODE_INFO  *ParentInfo;
192 
193     ACPI_FUNCTION_TRACE_PTR (DsIsResultUsed, Op);
194 
195 
196     /* Must have both an Op and a Result Object */
197 
198     if (!Op)
199     {
200         ACPI_ERROR ((AE_INFO, "Null Op"));
201         return_UINT8 (TRUE);
202     }
203 
204     /*
205      * We know that this operator is not a
206      * Return() operator (would not come here.) The following code is the
207      * optional support for a so-called "implicit return". Some AML code
208      * assumes that the last value of the method is "implicitly" returned
209      * to the caller. Just save the last result as the return value.
210      * NOTE: this is optional because the ASL language does not actually
211      * support this behavior.
212      */
213     (void) AcpiDsDoImplicitReturn (WalkState->ResultObj, WalkState, TRUE);
214 
215     /*
216      * Now determine if the parent will use the result
217      *
218      * If there is no parent, or the parent is a ScopeOp, we are executing
219      * at the method level. An executing method typically has no parent,
220      * since each method is parsed separately. A method invoked externally
221      * via ExecuteControlMethod has a ScopeOp as the parent.
222      */
223     if ((!Op->Common.Parent) ||
224         (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
225     {
226         /* No parent, the return value cannot possibly be used */
227 
228         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
229             "At Method level, result of [%s] not used\n",
230             AcpiPsGetOpcodeName (Op->Common.AmlOpcode)));
231         return_UINT8 (FALSE);
232     }
233 
234     /* Get info on the parent. The RootOp is AML_SCOPE */
235 
236     ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode);
237     if (ParentInfo->Class == AML_CLASS_UNKNOWN)
238     {
239         ACPI_ERROR ((AE_INFO,
240             "Unknown parent opcode Op=%p", Op));
241         return_UINT8 (FALSE);
242     }
243 
244     /*
245      * Decide what to do with the result based on the parent. If
246      * the parent opcode will not use the result, delete the object.
247      * Otherwise leave it as is, it will be deleted when it is used
248      * as an operand later.
249      */
250     switch (ParentInfo->Class)
251     {
252     case AML_CLASS_CONTROL:
253 
254         switch (Op->Common.Parent->Common.AmlOpcode)
255         {
256         case AML_RETURN_OP:
257 
258             /* Never delete the return value associated with a return opcode */
259 
260             goto ResultUsed;
261 
262         case AML_IF_OP:
263         case AML_WHILE_OP:
264             /*
265              * If we are executing the predicate AND this is the predicate op,
266              * we will use the return value
267              */
268             if ((WalkState->ControlState->Common.State ==
269                     ACPI_CONTROL_PREDICATE_EXECUTING) &&
270                 (WalkState->ControlState->Control.PredicateOp == Op))
271             {
272                 goto ResultUsed;
273             }
274             break;
275 
276         default:
277 
278             /* Ignore other control opcodes */
279 
280             break;
281         }
282 
283         /* The general control opcode returns no result */
284 
285         goto ResultNotUsed;
286 
287     case AML_CLASS_CREATE:
288         /*
289          * These opcodes allow TermArg(s) as operands and therefore
290          * the operands can be method calls. The result is used.
291          */
292         goto ResultUsed;
293 
294     case AML_CLASS_NAMED_OBJECT:
295 
296         if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP)       ||
297             (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP)  ||
298             (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP)      ||
299             (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP)       ||
300             (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP) ||
301             (Op->Common.Parent->Common.AmlOpcode == AML_INT_EVAL_SUBTREE_OP) ||
302             (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP))
303         {
304             /*
305              * These opcodes allow TermArg(s) as operands and therefore
306              * the operands can be method calls. The result is used.
307              */
308             goto ResultUsed;
309         }
310 
311         goto ResultNotUsed;
312 
313     default:
314         /*
315          * In all other cases. the parent will actually use the return
316          * object, so keep it.
317          */
318         goto ResultUsed;
319     }
320 
321 
322 ResultUsed:
323     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
324         "Result of [%s] used by Parent [%s] Op=%p\n",
325         AcpiPsGetOpcodeName (Op->Common.AmlOpcode),
326         AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op));
327 
328     return_UINT8 (TRUE);
329 
330 
331 ResultNotUsed:
332     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
333         "Result of [%s] not used by Parent [%s] Op=%p\n",
334         AcpiPsGetOpcodeName (Op->Common.AmlOpcode),
335         AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op));
336 
337     return_UINT8 (FALSE);
338 }
339 
340 
341 /*******************************************************************************
342  *
343  * FUNCTION:    AcpiDsDeleteResultIfNotUsed
344  *
345  * PARAMETERS:  Op              - Current parse Op
346  *              ResultObj       - Result of the operation
347  *              WalkState       - Current state
348  *
349  * RETURN:      Status
350  *
351  * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
352  *              result descriptor, check if the parent opcode will actually use
353  *              this result. If not, delete the result now so that it will
354  *              not become orphaned.
355  *
356  ******************************************************************************/
357 
358 void
AcpiDsDeleteResultIfNotUsed(ACPI_PARSE_OBJECT * Op,ACPI_OPERAND_OBJECT * ResultObj,ACPI_WALK_STATE * WalkState)359 AcpiDsDeleteResultIfNotUsed (
360     ACPI_PARSE_OBJECT       *Op,
361     ACPI_OPERAND_OBJECT     *ResultObj,
362     ACPI_WALK_STATE         *WalkState)
363 {
364     ACPI_OPERAND_OBJECT     *ObjDesc;
365     ACPI_STATUS             Status;
366 
367 
368     ACPI_FUNCTION_TRACE_PTR (DsDeleteResultIfNotUsed, ResultObj);
369 
370 
371     if (!Op)
372     {
373         ACPI_ERROR ((AE_INFO, "Null Op"));
374         return_VOID;
375     }
376 
377     if (!ResultObj)
378     {
379         return_VOID;
380     }
381 
382     if (!AcpiDsIsResultUsed (Op, WalkState))
383     {
384         /* Must pop the result stack (ObjDesc should be equal to ResultObj) */
385 
386         Status = AcpiDsResultPop (&ObjDesc, WalkState);
387         if (ACPI_SUCCESS (Status))
388         {
389             AcpiUtRemoveReference (ResultObj);
390         }
391     }
392 
393     return_VOID;
394 }
395 
396 
397 /*******************************************************************************
398  *
399  * FUNCTION:    AcpiDsResolveOperands
400  *
401  * PARAMETERS:  WalkState           - Current walk state with operands on stack
402  *
403  * RETURN:      Status
404  *
405  * DESCRIPTION: Resolve all operands to their values. Used to prepare
406  *              arguments to a control method invocation (a call from one
407  *              method to another.)
408  *
409  ******************************************************************************/
410 
411 ACPI_STATUS
AcpiDsResolveOperands(ACPI_WALK_STATE * WalkState)412 AcpiDsResolveOperands (
413     ACPI_WALK_STATE         *WalkState)
414 {
415     UINT32                  i;
416     ACPI_STATUS             Status = AE_OK;
417 
418 
419     ACPI_FUNCTION_TRACE_PTR (DsResolveOperands, WalkState);
420 
421 
422     /*
423      * Attempt to resolve each of the valid operands
424      * Method arguments are passed by reference, not by value. This means
425      * that the actual objects are passed, not copies of the objects.
426      */
427     for (i = 0; i < WalkState->NumOperands; i++)
428     {
429         Status = AcpiExResolveToValue (&WalkState->Operands[i], WalkState);
430         if (ACPI_FAILURE (Status))
431         {
432             break;
433         }
434     }
435 
436     return_ACPI_STATUS (Status);
437 }
438 
439 
440 /*******************************************************************************
441  *
442  * FUNCTION:    AcpiDsClearOperands
443  *
444  * PARAMETERS:  WalkState           - Current walk state with operands on stack
445  *
446  * RETURN:      None
447  *
448  * DESCRIPTION: Clear all operands on the current walk state operand stack.
449  *
450  ******************************************************************************/
451 
452 void
AcpiDsClearOperands(ACPI_WALK_STATE * WalkState)453 AcpiDsClearOperands (
454     ACPI_WALK_STATE         *WalkState)
455 {
456     UINT32                  i;
457 
458 
459     ACPI_FUNCTION_TRACE_PTR (DsClearOperands, WalkState);
460 
461 
462     /* Remove a reference on each operand on the stack */
463 
464     for (i = 0; i < WalkState->NumOperands; i++)
465     {
466         /*
467          * Remove a reference to all operands, including both
468          * "Arguments" and "Targets".
469          */
470         AcpiUtRemoveReference (WalkState->Operands[i]);
471         WalkState->Operands[i] = NULL;
472     }
473 
474     WalkState->NumOperands = 0;
475     return_VOID;
476 }
477 
478 
479 /*******************************************************************************
480  *
481  * FUNCTION:    AcpiDsCreateOperand
482  *
483  * PARAMETERS:  WalkState       - Current walk state
484  *              Arg             - Parse object for the argument
485  *              ArgIndex        - Which argument (zero based)
486  *
487  * RETURN:      Status
488  *
489  * DESCRIPTION: Translate a parse tree object that is an argument to an AML
490  *              opcode to the equivalent interpreter object. This may include
491  *              looking up a name or entering a new name into the internal
492  *              namespace.
493  *
494  ******************************************************************************/
495 
496 ACPI_STATUS
AcpiDsCreateOperand(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Arg,UINT32 ArgIndex)497 AcpiDsCreateOperand (
498     ACPI_WALK_STATE         *WalkState,
499     ACPI_PARSE_OBJECT       *Arg,
500     UINT32                  ArgIndex)
501 {
502     ACPI_STATUS             Status = AE_OK;
503     char                    *NameString;
504     UINT32                  NameLength;
505     ACPI_OPERAND_OBJECT     *ObjDesc;
506     ACPI_PARSE_OBJECT       *ParentOp;
507     UINT16                  Opcode;
508     ACPI_INTERPRETER_MODE   InterpreterMode;
509     const ACPI_OPCODE_INFO  *OpInfo;
510 
511 
512     ACPI_FUNCTION_TRACE_PTR (DsCreateOperand, Arg);
513 
514 
515     /* A valid name must be looked up in the namespace */
516 
517     if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
518         (Arg->Common.Value.String) &&
519         !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
520     {
521         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", Arg));
522 
523         /* Get the entire name string from the AML stream */
524 
525         Status = AcpiExGetNameString (ACPI_TYPE_ANY,
526             Arg->Common.Value.Buffer, &NameString, &NameLength);
527 
528         if (ACPI_FAILURE (Status))
529         {
530             return_ACPI_STATUS (Status);
531         }
532 
533         /* All prefixes have been handled, and the name is in NameString */
534 
535         /*
536          * Special handling for BufferField declarations. This is a deferred
537          * opcode that unfortunately defines the field name as the last
538          * parameter instead of the first. We get here when we are performing
539          * the deferred execution, so the actual name of the field is already
540          * in the namespace. We don't want to attempt to look it up again
541          * because we may be executing in a different scope than where the
542          * actual opcode exists.
543          */
544         if ((WalkState->DeferredNode) &&
545             (WalkState->DeferredNode->Type == ACPI_TYPE_BUFFER_FIELD) &&
546             (ArgIndex == (UINT32)
547                 ((WalkState->Opcode == AML_CREATE_FIELD_OP) ? 3 : 2)))
548         {
549             ObjDesc = ACPI_CAST_PTR (
550                 ACPI_OPERAND_OBJECT, WalkState->DeferredNode);
551             Status = AE_OK;
552         }
553         else    /* All other opcodes */
554         {
555             /*
556              * Differentiate between a namespace "create" operation
557              * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
558              * IMODE_EXECUTE) in order to support the creation of
559              * namespace objects during the execution of control methods.
560              */
561             ParentOp = Arg->Common.Parent;
562             OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode);
563 
564             if ((OpInfo->Flags & AML_NSNODE) &&
565                 (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) &&
566                 (ParentOp->Common.AmlOpcode != AML_REGION_OP) &&
567                 (ParentOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP))
568             {
569                 /* Enter name into namespace if not found */
570 
571                 InterpreterMode = ACPI_IMODE_LOAD_PASS2;
572             }
573             else
574             {
575                 /* Return a failure if name not found */
576 
577                 InterpreterMode = ACPI_IMODE_EXECUTE;
578             }
579 
580             Status = AcpiNsLookup (WalkState->ScopeInfo, NameString,
581                 ACPI_TYPE_ANY, InterpreterMode,
582                 ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, WalkState,
583                 ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &ObjDesc));
584             /*
585              * The only case where we pass through (ignore) a NOT_FOUND
586              * error is for the CondRefOf opcode.
587              */
588             if (Status == AE_NOT_FOUND)
589             {
590                 if (ParentOp->Common.AmlOpcode == AML_CONDITIONAL_REF_OF_OP)
591                 {
592                     /*
593                      * For the Conditional Reference op, it's OK if
594                      * the name is not found;  We just need a way to
595                      * indicate this to the interpreter, set the
596                      * object to the root
597                      */
598                     ObjDesc = ACPI_CAST_PTR (
599                         ACPI_OPERAND_OBJECT, AcpiGbl_RootNode);
600                     Status = AE_OK;
601                 }
602                 else if (ParentOp->Common.AmlOpcode == AML_EXTERNAL_OP)
603                 {
604                     /*
605                      * This opcode should never appear here. It is used only
606                      * by AML disassemblers and is surrounded by an If(0)
607                      * by the ASL compiler.
608                      *
609                      * Therefore, if we see it here, it is a serious error.
610                      */
611                     Status = AE_AML_BAD_OPCODE;
612                 }
613                 else
614                 {
615                     /*
616                      * We just plain didn't find it -- which is a
617                      * very serious error at this point
618                      */
619                     Status = AE_AML_NAME_NOT_FOUND;
620                 }
621             }
622 
623             if (ACPI_FAILURE (Status))
624             {
625                 ACPI_ERROR_NAMESPACE (WalkState->ScopeInfo,
626                     NameString, Status);
627             }
628         }
629 
630         /* Free the namestring created above */
631 
632         ACPI_FREE (NameString);
633 
634         /* Check status from the lookup */
635 
636         if (ACPI_FAILURE (Status))
637         {
638             return_ACPI_STATUS (Status);
639         }
640 
641         /* Put the resulting object onto the current object stack */
642 
643         Status = AcpiDsObjStackPush (ObjDesc, WalkState);
644         if (ACPI_FAILURE (Status))
645         {
646             return_ACPI_STATUS (Status);
647         }
648 
649         AcpiDbDisplayArgumentObject (ObjDesc, WalkState);
650     }
651     else
652     {
653         /* Check for null name case */
654 
655         if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
656             !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
657         {
658             /*
659              * If the name is null, this means that this is an
660              * optional result parameter that was not specified
661              * in the original ASL. Create a Zero Constant for a
662              * placeholder. (Store to a constant is a Noop.)
663              */
664             Opcode = AML_ZERO_OP;       /* Has no arguments! */
665 
666             ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
667                 "Null namepath: Arg=%p\n", Arg));
668         }
669         else
670         {
671             Opcode = Arg->Common.AmlOpcode;
672         }
673 
674         /* Get the object type of the argument */
675 
676         OpInfo = AcpiPsGetOpcodeInfo (Opcode);
677         if (OpInfo->ObjectType == ACPI_TYPE_INVALID)
678         {
679             return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
680         }
681 
682         if ((OpInfo->Flags & AML_HAS_RETVAL) ||
683             (Arg->Common.Flags & ACPI_PARSEOP_IN_STACK))
684         {
685             /*
686              * Use value that was already previously returned
687              * by the evaluation of this argument
688              */
689             Status = AcpiDsResultPop (&ObjDesc, WalkState);
690             if (ACPI_FAILURE (Status))
691             {
692                 /*
693                  * Only error is underflow, and this indicates
694                  * a missing or null operand!
695                  */
696                 ACPI_EXCEPTION ((AE_INFO, Status,
697                     "Missing or null operand"));
698                 return_ACPI_STATUS (Status);
699             }
700         }
701         else
702         {
703             /* Create an ACPI_INTERNAL_OBJECT for the argument */
704 
705             ObjDesc = AcpiUtCreateInternalObject (OpInfo->ObjectType);
706             if (!ObjDesc)
707             {
708                 return_ACPI_STATUS (AE_NO_MEMORY);
709             }
710 
711             /* Initialize the new object */
712 
713             Status = AcpiDsInitObjectFromOp (
714                 WalkState, Arg, Opcode, &ObjDesc);
715             if (ACPI_FAILURE (Status))
716             {
717                 AcpiUtDeleteObjectDesc (ObjDesc);
718                 return_ACPI_STATUS (Status);
719             }
720         }
721 
722         /* Put the operand object on the object stack */
723 
724         Status = AcpiDsObjStackPush (ObjDesc, WalkState);
725         if (ACPI_FAILURE (Status))
726         {
727             return_ACPI_STATUS (Status);
728         }
729 
730         AcpiDbDisplayArgumentObject (ObjDesc, WalkState);
731     }
732 
733     return_ACPI_STATUS (AE_OK);
734 }
735 
736 
737 /*******************************************************************************
738  *
739  * FUNCTION:    AcpiDsCreateOperands
740  *
741  * PARAMETERS:  WalkState           - Current state
742  *              FirstArg            - First argument of a parser argument tree
743  *
744  * RETURN:      Status
745  *
746  * DESCRIPTION: Convert an operator's arguments from a parse tree format to
747  *              namespace objects and place those argument object on the object
748  *              stack in preparation for evaluation by the interpreter.
749  *
750  ******************************************************************************/
751 
752 ACPI_STATUS
AcpiDsCreateOperands(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * FirstArg)753 AcpiDsCreateOperands (
754     ACPI_WALK_STATE         *WalkState,
755     ACPI_PARSE_OBJECT       *FirstArg)
756 {
757     ACPI_STATUS             Status = AE_OK;
758     ACPI_PARSE_OBJECT       *Arg;
759     ACPI_PARSE_OBJECT       *Arguments[ACPI_OBJ_NUM_OPERANDS];
760     UINT32                  ArgCount = 0;
761     UINT32                  Index = WalkState->NumOperands;
762     UINT32                  i;
763 
764 
765     ACPI_FUNCTION_TRACE_PTR (DsCreateOperands, FirstArg);
766 
767 
768     /* Get all arguments in the list */
769 
770     Arg = FirstArg;
771     while (Arg)
772     {
773         if (Index >= ACPI_OBJ_NUM_OPERANDS)
774         {
775             return_ACPI_STATUS (AE_BAD_DATA);
776         }
777 
778         Arguments[Index] = Arg;
779         WalkState->Operands [Index] = NULL;
780 
781         /* Move on to next argument, if any */
782 
783         Arg = Arg->Common.Next;
784         ArgCount++;
785         Index++;
786     }
787 
788     ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
789         "NumOperands %d, ArgCount %d, Index %d\n",
790         WalkState->NumOperands, ArgCount, Index));
791 
792     /* Create the interpreter arguments, in reverse order */
793 
794     Index--;
795     for (i = 0; i < ArgCount; i++)
796     {
797         Arg = Arguments[Index];
798         WalkState->OperandIndex = (UINT8) Index;
799 
800         Status = AcpiDsCreateOperand (WalkState, Arg, Index);
801         if (ACPI_FAILURE (Status))
802         {
803             goto Cleanup;
804         }
805 
806         ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
807             "Created Arg #%u (%p) %u args total\n",
808             Index, Arg, ArgCount));
809         Index--;
810     }
811 
812     return_ACPI_STATUS (Status);
813 
814 
815 Cleanup:
816     /*
817      * We must undo everything done above; meaning that we must
818      * pop everything off of the operand stack and delete those
819      * objects
820      */
821     AcpiDsObjStackPopAndDelete (ArgCount, WalkState);
822 
823     ACPI_EXCEPTION ((AE_INFO, Status, "While creating Arg %u", Index));
824     return_ACPI_STATUS (Status);
825 }
826 
827 
828 /*****************************************************************************
829  *
830  * FUNCTION:    AcpiDsEvaluateNamePath
831  *
832  * PARAMETERS:  WalkState       - Current state of the parse tree walk,
833  *                                the opcode of current operation should be
834  *                                AML_INT_NAMEPATH_OP
835  *
836  * RETURN:      Status
837  *
838  * DESCRIPTION: Translate the -NamePath- parse tree object to the equivalent
839  *              interpreter object, convert it to value, if needed, duplicate
840  *              it, if needed, and push it onto the current result stack.
841  *
842  ****************************************************************************/
843 
844 ACPI_STATUS
AcpiDsEvaluateNamePath(ACPI_WALK_STATE * WalkState)845 AcpiDsEvaluateNamePath (
846     ACPI_WALK_STATE         *WalkState)
847 {
848     ACPI_STATUS             Status = AE_OK;
849     ACPI_PARSE_OBJECT       *Op = WalkState->Op;
850     ACPI_OPERAND_OBJECT     **Operand = &WalkState->Operands[0];
851     ACPI_OPERAND_OBJECT     *NewObjDesc;
852     UINT8                   Type;
853 
854 
855     ACPI_FUNCTION_TRACE_PTR (DsEvaluateNamePath, WalkState);
856 
857 
858     if (!Op->Common.Parent)
859     {
860         /* This happens after certain exception processing */
861 
862         goto Exit;
863     }
864 
865     if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
866         (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP) ||
867         (Op->Common.Parent->Common.AmlOpcode == AML_REF_OF_OP))
868     {
869         /* TBD: Should we specify this feature as a bit of OpInfo->Flags of these opcodes? */
870 
871         goto Exit;
872     }
873 
874     Status = AcpiDsCreateOperand (WalkState, Op, 0);
875     if (ACPI_FAILURE (Status))
876     {
877         goto Exit;
878     }
879 
880     if (Op->Common.Flags & ACPI_PARSEOP_TARGET)
881     {
882         NewObjDesc = *Operand;
883         goto PushResult;
884     }
885 
886     Type = (*Operand)->Common.Type;
887 
888     Status = AcpiExResolveToValue (Operand, WalkState);
889     if (ACPI_FAILURE (Status))
890     {
891         goto Exit;
892     }
893 
894     if (Type == ACPI_TYPE_INTEGER)
895     {
896         /* It was incremented by AcpiExResolveToValue */
897 
898         AcpiUtRemoveReference (*Operand);
899 
900         Status = AcpiUtCopyIobjectToIobject (
901             *Operand, &NewObjDesc, WalkState);
902         if (ACPI_FAILURE (Status))
903         {
904             goto Exit;
905         }
906     }
907     else
908     {
909         /*
910          * The object either was anew created or is
911          * a Namespace node - don't decrement it.
912          */
913         NewObjDesc = *Operand;
914     }
915 
916     /* Cleanup for name-path operand */
917 
918     Status = AcpiDsObjStackPop (1, WalkState);
919     if (ACPI_FAILURE (Status))
920     {
921         WalkState->ResultObj = NewObjDesc;
922         goto Exit;
923     }
924 
925 PushResult:
926 
927     WalkState->ResultObj = NewObjDesc;
928 
929     Status = AcpiDsResultPush (WalkState->ResultObj, WalkState);
930     if (ACPI_SUCCESS (Status))
931     {
932         /* Force to take it from stack */
933 
934         Op->Common.Flags |= ACPI_PARSEOP_IN_STACK;
935     }
936 
937 Exit:
938 
939     return_ACPI_STATUS (Status);
940 }
941