1 /******************************************************************************
2  *
3  * Module Name: asltree - parse tree management
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acapps.h"
47 #include <time.h>
48 
49 #define _COMPONENT          ACPI_COMPILER
50         ACPI_MODULE_NAME    ("asltree")
51 
52 /* Local prototypes */
53 
54 static ACPI_PARSE_OBJECT *
55 TrGetNextNode (
56     void);
57 
58 
59 /*******************************************************************************
60  *
61  * FUNCTION:    TrGetNextNode
62  *
63  * PARAMETERS:  None
64  *
65  * RETURN:      New parse node. Aborts on allocation failure
66  *
67  * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local
68  *              dynamic memory manager for performance reasons (This has a
69  *              major impact on the speed of the compiler.)
70  *
71  ******************************************************************************/
72 
73 static ACPI_PARSE_OBJECT *
74 TrGetNextNode (
75     void)
76 {
77     ASL_CACHE_INFO          *Cache;
78 
79 
80     if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast)
81     {
82         /* Allocate a new buffer */
83 
84         Cache = UtLocalCalloc (sizeof (Cache->Next) +
85             (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE));
86 
87         /* Link new cache buffer to head of list */
88 
89         Cache->Next = Gbl_ParseOpCacheList;
90         Gbl_ParseOpCacheList = Cache;
91 
92         /* Setup cache management pointers */
93 
94         Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer);
95         Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE;
96     }
97 
98     Gbl_ParseOpCount++;
99     return (Gbl_ParseOpCacheNext++);
100 }
101 
102 
103 /*******************************************************************************
104  *
105  * FUNCTION:    TrAllocateNode
106  *
107  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
108  *
109  * RETURN:      New parse node. Aborts on allocation failure
110  *
111  * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
112  *
113  ******************************************************************************/
114 
115 ACPI_PARSE_OBJECT *
116 TrAllocateNode (
117     UINT32                  ParseOpcode)
118 {
119     ACPI_PARSE_OBJECT       *Op;
120 
121 
122     Op = TrGetNextNode ();
123 
124     Op->Asl.ParseOpcode       = (UINT16) ParseOpcode;
125     Op->Asl.Filename          = Gbl_Files[ASL_FILE_INPUT].Filename;
126     Op->Asl.LineNumber        = Gbl_CurrentLineNumber;
127     Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
128     Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
129     Op->Asl.Column            = Gbl_CurrentColumn;
130 
131     UtSetParseOpName (Op);
132     return (Op);
133 }
134 
135 
136 /*******************************************************************************
137  *
138  * FUNCTION:    TrReleaseNode
139  *
140  * PARAMETERS:  Op            - Op to be released
141  *
142  * RETURN:      None
143  *
144  * DESCRIPTION: "release" a node. In truth, nothing is done since the node
145  *              is part of a larger buffer
146  *
147  ******************************************************************************/
148 
149 void
150 TrReleaseNode (
151     ACPI_PARSE_OBJECT       *Op)
152 {
153 
154     return;
155 }
156 
157 
158 /*******************************************************************************
159  *
160  * FUNCTION:    TrSetCurrentFilename
161  *
162  * PARAMETERS:  Op                  - An existing parse node
163  *
164  * RETURN:      None
165  *
166  * DESCRIPTION: Save the include file filename. Used for debug output only.
167  *
168  ******************************************************************************/
169 
170 void
171 TrSetCurrentFilename (
172     ACPI_PARSE_OBJECT       *Op)
173 {
174     Op->Asl.Filename = Gbl_PreviousIncludeFilename;
175 }
176 
177 
178 /*******************************************************************************
179  *
180  * FUNCTION:    TrUpdateNode
181  *
182  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
183  *              Op                  - An existing parse node
184  *
185  * RETURN:      The updated node
186  *
187  * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to
188  *              change an opcode to DEFAULT_ARG so that the node is ignored
189  *              during the code generation. Also used to set generic integers
190  *              to a specific size (8, 16, 32, or 64 bits)
191  *
192  ******************************************************************************/
193 
194 ACPI_PARSE_OBJECT *
195 TrUpdateNode (
196     UINT32                  ParseOpcode,
197     ACPI_PARSE_OBJECT       *Op)
198 {
199 
200     if (!Op)
201     {
202         return (NULL);
203     }
204 
205     DbgPrint (ASL_PARSE_OUTPUT,
206         "\nUpdateNode: Old - %s, New - %s\n",
207         UtGetOpName (Op->Asl.ParseOpcode),
208         UtGetOpName (ParseOpcode));
209 
210     /* Assign new opcode and name */
211 
212     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
213     {
214         switch (ParseOpcode)
215         {
216         case PARSEOP_BYTECONST:
217 
218             Op->Asl.Value.Integer = ACPI_UINT8_MAX;
219             break;
220 
221         case PARSEOP_WORDCONST:
222 
223             Op->Asl.Value.Integer = ACPI_UINT16_MAX;
224             break;
225 
226         case PARSEOP_DWORDCONST:
227 
228             Op->Asl.Value.Integer = ACPI_UINT32_MAX;
229             break;
230 
231         /* Don't need to do the QWORD case */
232 
233         default:
234 
235             /* Don't care about others */
236             break;
237         }
238     }
239 
240     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
241     UtSetParseOpName (Op);
242 
243     /*
244      * For the BYTE, WORD, and DWORD constants, make sure that the integer
245      * that was passed in will actually fit into the data type
246      */
247     switch (ParseOpcode)
248     {
249     case PARSEOP_BYTECONST:
250 
251         UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
252         Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
253         break;
254 
255     case PARSEOP_WORDCONST:
256 
257         UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
258         Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
259         break;
260 
261     case PARSEOP_DWORDCONST:
262 
263         UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
264         Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
265         break;
266 
267     default:
268 
269         /* Don't care about others, don't need to check QWORD */
270 
271         break;
272     }
273 
274     return (Op);
275 }
276 
277 
278 /*******************************************************************************
279  *
280  * FUNCTION:    TrPrintNodeCompileFlags
281  *
282  * PARAMETERS:  Flags               - Flags word to be decoded
283  *
284  * RETURN:      None
285  *
286  * DESCRIPTION: Decode a flags word to text. Displays all flags that are set.
287  *
288  ******************************************************************************/
289 
290 void
291 TrPrintNodeCompileFlags (
292     UINT32                  Flags)
293 {
294     UINT32                  i;
295     UINT32                  FlagBit = 1;
296     char                    *FlagName = NULL;
297 
298 
299     for (i = 0; i < 32; i++)
300     {
301         switch (Flags & FlagBit)
302         {
303         case NODE_VISITED:
304 
305             FlagName = "NODE_VISITED";
306             break;
307 
308         case NODE_AML_PACKAGE:
309 
310             FlagName = "NODE_AML_PACKAGE";
311             break;
312 
313         case NODE_IS_TARGET:
314 
315             FlagName = "NODE_IS_TARGET";
316             break;
317 
318         case NODE_IS_RESOURCE_DESC:
319 
320             FlagName = "NODE_IS_RESOURCE_DESC";
321             break;
322 
323         case NODE_IS_RESOURCE_FIELD:
324 
325             FlagName = "NODE_IS_RESOURCE_FIELD";
326             break;
327 
328         case NODE_HAS_NO_EXIT:
329 
330             FlagName = "NODE_HAS_NO_EXIT";
331             break;
332 
333         case NODE_IF_HAS_NO_EXIT:
334 
335             FlagName = "NODE_IF_HAS_NO_EXIT";
336             break;
337 
338         case NODE_NAME_INTERNALIZED:
339 
340             FlagName = "NODE_NAME_INTERNALIZED";
341             break;
342 
343         case NODE_METHOD_NO_RETVAL:
344 
345             FlagName = "NODE_METHOD_NO_RETVAL";
346             break;
347 
348         case NODE_METHOD_SOME_NO_RETVAL:
349 
350             FlagName = "NODE_METHOD_SOME_NO_RETVAL";
351             break;
352 
353         case NODE_RESULT_NOT_USED:
354 
355             FlagName = "NODE_RESULT_NOT_USED";
356             break;
357 
358         case NODE_METHOD_TYPED:
359 
360             FlagName = "NODE_METHOD_TYPED";
361             break;
362 
363         case NODE_COULD_NOT_REDUCE:
364 
365             FlagName = "NODE_COULD_NOT_REDUCE";
366             break;
367 
368         case NODE_COMPILE_TIME_CONST:
369 
370             FlagName = "NODE_COMPILE_TIME_CONST";
371             break;
372 
373         case NODE_IS_TERM_ARG:
374 
375             FlagName = "NODE_IS_TERM_ARG";
376             break;
377 
378         case NODE_WAS_ONES_OP:
379 
380             FlagName = "NODE_WAS_ONES_OP";
381             break;
382 
383         case NODE_IS_NAME_DECLARATION:
384 
385             FlagName = "NODE_IS_NAME_DECLARATION";
386             break;
387 
388         case NODE_COMPILER_EMITTED:
389 
390             FlagName = "NODE_COMPILER_EMITTED";
391             break;
392 
393         case NODE_IS_DUPLICATE:
394 
395             FlagName = "NODE_IS_DUPLICATE";
396             break;
397 
398         case NODE_IS_RESOURCE_DATA:
399 
400             FlagName = "NODE_IS_RESOURCE_DATA";
401             break;
402 
403         case NODE_IS_NULL_RETURN:
404 
405             FlagName = "NODE_IS_NULL_RETURN";
406             break;
407 
408         default:
409             break;
410         }
411 
412         if (FlagName)
413         {
414             DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName);
415             FlagName = NULL;
416         }
417 
418         FlagBit <<= 1;
419     }
420 }
421 
422 
423 /*******************************************************************************
424  *
425  * FUNCTION:    TrSetNodeFlags
426  *
427  * PARAMETERS:  Op                  - An existing parse node
428  *              Flags               - New flags word
429  *
430  * RETURN:      The updated parser op
431  *
432  * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set
433  *
434  ******************************************************************************/
435 
436 ACPI_PARSE_OBJECT *
437 TrSetNodeFlags (
438     ACPI_PARSE_OBJECT       *Op,
439     UINT32                  Flags)
440 {
441 
442     if (!Op)
443     {
444         return (NULL);
445     }
446 
447     DbgPrint (ASL_PARSE_OUTPUT,
448         "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
449 
450     TrPrintNodeCompileFlags (Flags);
451     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
452 
453     Op->Asl.CompileFlags |= Flags;
454     return (Op);
455 }
456 
457 
458 /*******************************************************************************
459  *
460  * FUNCTION:    TrSetNodeAmlLength
461  *
462  * PARAMETERS:  Op                  - An existing parse node
463  *              Length              - AML Length
464  *
465  * RETURN:      The updated parser op
466  *
467  * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate
468  *              the presence of a node that must be reduced to a fixed length
469  *              constant.
470  *
471  ******************************************************************************/
472 
473 ACPI_PARSE_OBJECT *
474 TrSetNodeAmlLength (
475     ACPI_PARSE_OBJECT       *Op,
476     UINT32                  Length)
477 {
478 
479     DbgPrint (ASL_PARSE_OUTPUT,
480         "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length);
481 
482     if (!Op)
483     {
484         return (NULL);
485     }
486 
487     Op->Asl.AmlLength = Length;
488     return (Op);
489 }
490 
491 
492 /*******************************************************************************
493  *
494  * FUNCTION:    TrSetEndLineNumber
495  *
496  * PARAMETERS:  Op                - An existing parse node
497  *
498  * RETURN:      None.
499  *
500  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
501  *              parse node to the current line numbers.
502  *
503  ******************************************************************************/
504 
505 void
506 TrSetEndLineNumber (
507     ACPI_PARSE_OBJECT       *Op)
508 {
509 
510     /* If the end line # is already set, just return */
511 
512     if (Op->Asl.EndLine)
513     {
514         return;
515     }
516 
517     Op->Asl.EndLine = Gbl_CurrentLineNumber;
518     Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
519 }
520 
521 
522 /*******************************************************************************
523  *
524  * FUNCTION:    TrCreateAssignmentNode
525  *
526  * PARAMETERS:  Target              - Assignment target
527  *              Source              - Assignment source
528  *
529  * RETURN:      Pointer to the new node. Aborts on allocation failure
530  *
531  * DESCRIPTION: Implements the C-style '=' operator. It changes the parse
532  *              tree if possible to utilize the last argument of the math
533  *              operators which is a target operand -- thus saving invocation
534  *              of and additional Store() operator. An optimization.
535  *
536  ******************************************************************************/
537 
538 ACPI_PARSE_OBJECT *
539 TrCreateAssignmentNode (
540     ACPI_PARSE_OBJECT       *Target,
541     ACPI_PARSE_OBJECT       *Source)
542 {
543     ACPI_PARSE_OBJECT       *TargetOp;
544     ACPI_PARSE_OBJECT       *SourceOp1;
545     ACPI_PARSE_OBJECT       *SourceOp2;
546     ACPI_PARSE_OBJECT       *Operator;
547 
548 
549     DbgPrint (ASL_PARSE_OUTPUT,
550         "\nTrCreateAssignmentNode  Line [%u to %u] Source %s Target %s\n",
551         Source->Asl.LineNumber, Source->Asl.EndLine,
552         UtGetOpName (Source->Asl.ParseOpcode),
553         UtGetOpName (Target->Asl.ParseOpcode));
554 
555     TrSetNodeFlags (Target, NODE_IS_TARGET);
556 
557     switch (Source->Asl.ParseOpcode)
558     {
559     /*
560      * Only these operators can be optimized because they have
561      * a target operand
562      */
563     case PARSEOP_ADD:
564     case PARSEOP_AND:
565     case PARSEOP_DIVIDE:
566     case PARSEOP_INDEX:
567     case PARSEOP_MOD:
568     case PARSEOP_MULTIPLY:
569     case PARSEOP_NOT:
570     case PARSEOP_OR:
571     case PARSEOP_SHIFTLEFT:
572     case PARSEOP_SHIFTRIGHT:
573     case PARSEOP_SUBTRACT:
574     case PARSEOP_XOR:
575 
576         break;
577 
578     /* Otherwise, just create a normal Store operator */
579 
580     default:
581 
582         goto CannotOptimize;
583     }
584 
585     /*
586      * Transform the parse tree such that the target is moved to the
587      * last operand of the operator
588      */
589     SourceOp1 = Source->Asl.Child;
590     SourceOp2 = SourceOp1->Asl.Next;
591 
592     /* NOT only has one operand, but has a target */
593 
594     if (Source->Asl.ParseOpcode == PARSEOP_NOT)
595     {
596         SourceOp2 = SourceOp1;
597     }
598 
599     /* DIVIDE has an extra target operand (remainder) */
600 
601     if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE)
602     {
603         SourceOp2 = SourceOp2->Asl.Next;
604     }
605 
606     TargetOp = SourceOp2->Asl.Next;
607 
608     /*
609      * Can't perform this optimization if there already is a target
610      * for the operator (ZERO is a "no target" placeholder).
611      */
612     if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO)
613     {
614         goto CannotOptimize;
615     }
616 
617     /* Link in the target as the final operand */
618 
619     SourceOp2->Asl.Next = Target;
620     Target->Asl.Parent = Source;
621 
622     return (Source);
623 
624 
625 CannotOptimize:
626 
627     Operator = TrAllocateNode (PARSEOP_STORE);
628     TrLinkChildren (Operator, 2, Source, Target);
629 
630     /* Set the appropriate line numbers for the new node */
631 
632     Operator->Asl.LineNumber        = Target->Asl.LineNumber;
633     Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber;
634     Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset;
635     Operator->Asl.Column            = Target->Asl.Column;
636 
637     return (Operator);
638 }
639 
640 
641 /*******************************************************************************
642  *
643  * FUNCTION:    TrCreateLeafNode
644  *
645  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
646  *
647  * RETURN:      Pointer to the new node. Aborts on allocation failure
648  *
649  * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
650  *              assigned to the node)
651  *
652  ******************************************************************************/
653 
654 ACPI_PARSE_OBJECT *
655 TrCreateLeafNode (
656     UINT32                  ParseOpcode)
657 {
658     ACPI_PARSE_OBJECT       *Op;
659 
660 
661     Op = TrAllocateNode (ParseOpcode);
662 
663     DbgPrint (ASL_PARSE_OUTPUT,
664         "\nCreateLeafNode  Ln/Col %u/%u NewNode %p  Op %s\n\n",
665         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode));
666 
667     return (Op);
668 }
669 
670 
671 /*******************************************************************************
672  *
673  * FUNCTION:    TrCreateNullTarget
674  *
675  * PARAMETERS:  None
676  *
677  * RETURN:      Pointer to the new node. Aborts on allocation failure
678  *
679  * DESCRIPTION: Create a "null" target node. This is defined by the ACPI
680  *              specification to be a zero AML opcode, and indicates that
681  *              no target has been specified for the parent operation
682  *
683  ******************************************************************************/
684 
685 ACPI_PARSE_OBJECT *
686 TrCreateNullTarget (
687     void)
688 {
689     ACPI_PARSE_OBJECT       *Op;
690 
691 
692     Op = TrAllocateNode (PARSEOP_ZERO);
693     Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);
694 
695     DbgPrint (ASL_PARSE_OUTPUT,
696         "\nCreateNullTarget  Ln/Col %u/%u NewNode %p  Op %s\n",
697         Op->Asl.LineNumber, Op->Asl.Column, Op,
698         UtGetOpName (Op->Asl.ParseOpcode));
699 
700     return (Op);
701 }
702 
703 
704 /*******************************************************************************
705  *
706  * FUNCTION:    TrCreateConstantLeafNode
707  *
708  * PARAMETERS:  ParseOpcode         - The constant opcode
709  *
710  * RETURN:      Pointer to the new node. Aborts on allocation failure
711  *
712  * DESCRIPTION: Create a leaf node (no children or peers) for one of the
713  *              special constants - __LINE__, __FILE__, and __DATE__.
714  *
715  * Note: An implemenation of __FUNC__ cannot happen here because we don't
716  * have a full parse tree at this time and cannot find the parent control
717  * method. If it is ever needed, __FUNC__ must be implemented later, after
718  * the parse tree has been fully constructed.
719  *
720  ******************************************************************************/
721 
722 ACPI_PARSE_OBJECT *
723 TrCreateConstantLeafNode (
724     UINT32                  ParseOpcode)
725 {
726     ACPI_PARSE_OBJECT       *Op = NULL;
727     time_t                  CurrentTime;
728     char                    *StaticTimeString;
729     char                    *TimeString;
730     char                    *Filename;
731 
732 
733     switch (ParseOpcode)
734     {
735     case PARSEOP___LINE__:
736 
737         Op = TrAllocateNode (PARSEOP_INTEGER);
738         Op->Asl.Value.Integer = Op->Asl.LineNumber;
739         break;
740 
741     case PARSEOP___PATH__:
742 
743         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
744 
745         /* Op.Asl.Filename contains the full pathname to the file */
746 
747         Op->Asl.Value.String = Op->Asl.Filename;
748         break;
749 
750     case PARSEOP___FILE__:
751 
752         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
753 
754         /* Get the simple filename from the full path */
755 
756         FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename);
757         Op->Asl.Value.String = Filename;
758         break;
759 
760     case PARSEOP___DATE__:
761 
762         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
763 
764         /* Get a copy of the current time */
765 
766         CurrentTime = time (NULL);
767         StaticTimeString = ctime (&CurrentTime);
768         TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
769         strcpy (TimeString, StaticTimeString);
770 
771         TimeString[strlen(TimeString) -1] = 0;  /* Remove trailing newline */
772         Op->Asl.Value.String = TimeString;
773         break;
774 
775     default: /* This would be an internal error */
776 
777         return (NULL);
778     }
779 
780     DbgPrint (ASL_PARSE_OUTPUT,
781         "\nCreateConstantLeafNode  Ln/Col %u/%u NewNode %p  "
782         "Op %s  Value %8.8X%8.8X  \n",
783         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
784         ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
785     return (Op);
786 }
787 
788 
789 /*******************************************************************************
790  *
791  * FUNCTION:    TrCreateTargetOperand
792  *
793  * PARAMETERS:  OriginalOp          - Op to be copied
794  *
795  * RETURN:      Pointer to the new node. Aborts on allocation failure
796  *
797  * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style)
798  *              expressions where the target is the same as one of the
799  *              operands. A new node and subtree must be created from the
800  *              original so that the parse tree can be linked properly.
801  *
802  * NOTE:        This code is specific to target operands that are the last
803  *              operand in an ASL/AML operator. Meaning that the top-level
804  *              parse Op in a possible subtree has a NULL Next pointer.
805  *              This simplifies the recursion.
806  *
807  *              Subtree example:
808  *                  DeRefOf (Local1) += 32
809  *
810  *              This gets converted to:
811  *                  Add (DeRefOf (Local1), 32, DeRefOf (Local1))
812  *
813  *              Each DeRefOf has a single child, Local1. Even more complex
814  *              subtrees can be created via the Index and DeRefOf operators.
815  *
816  ******************************************************************************/
817 
818 ACPI_PARSE_OBJECT *
819 TrCreateTargetOperand (
820     ACPI_PARSE_OBJECT       *OriginalOp,
821     ACPI_PARSE_OBJECT       *ParentOp)
822 {
823     ACPI_PARSE_OBJECT       *Op;
824 
825 
826     if (!OriginalOp)
827     {
828         return (NULL);
829     }
830 
831     Op = TrGetNextNode ();
832 
833     /* Copy the pertinent values (omit link pointer fields) */
834 
835     Op->Asl.Value               = OriginalOp->Asl.Value;
836     Op->Asl.Filename            = OriginalOp->Asl.Filename;
837     Op->Asl.LineNumber          = OriginalOp->Asl.LineNumber;
838     Op->Asl.LogicalLineNumber   = OriginalOp->Asl.LogicalLineNumber;
839     Op->Asl.LogicalByteOffset   = OriginalOp->Asl.LogicalByteOffset;
840     Op->Asl.Column              = OriginalOp->Asl.Column;
841     Op->Asl.Flags               = OriginalOp->Asl.Flags;
842     Op->Asl.CompileFlags        = OriginalOp->Asl.CompileFlags;
843     Op->Asl.AmlOpcode           = OriginalOp->Asl.AmlOpcode;
844     Op->Asl.ParseOpcode         = OriginalOp->Asl.ParseOpcode;
845     Op->Asl.Parent              = ParentOp;
846     UtSetParseOpName (Op);
847 
848     /* Copy a possible subtree below this node */
849 
850     if (OriginalOp->Asl.Child)
851     {
852         Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op);
853     }
854 
855     if (OriginalOp->Asl.Next) /* Null for top-level node */
856     {
857         Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp);
858     }
859 
860     return (Op);
861 }
862 
863 
864 /*******************************************************************************
865  *
866  * FUNCTION:    TrCreateValuedLeafNode
867  *
868  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
869  *              Value               - Value to be assigned to the node
870  *
871  * RETURN:      Pointer to the new node. Aborts on allocation failure
872  *
873  * DESCRIPTION: Create a leaf node (no children or peers) with a value
874  *              assigned to it
875  *
876  ******************************************************************************/
877 
878 ACPI_PARSE_OBJECT *
879 TrCreateValuedLeafNode (
880     UINT32                  ParseOpcode,
881     UINT64                  Value)
882 {
883     ACPI_PARSE_OBJECT       *Op;
884 
885 
886     Op = TrAllocateNode (ParseOpcode);
887 
888     DbgPrint (ASL_PARSE_OUTPUT,
889         "\nCreateValuedLeafNode  Ln/Col %u/%u NewNode %p  "
890         "Op %s  Value %8.8X%8.8X  ",
891         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
892         ACPI_FORMAT_UINT64 (Value));
893     Op->Asl.Value.Integer = Value;
894 
895     switch (ParseOpcode)
896     {
897     case PARSEOP_STRING_LITERAL:
898 
899         DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
900         break;
901 
902     case PARSEOP_NAMESEG:
903 
904         DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
905         break;
906 
907     case PARSEOP_NAMESTRING:
908 
909         DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
910         break;
911 
912     case PARSEOP_EISAID:
913 
914         DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
915         break;
916 
917     case PARSEOP_METHOD:
918 
919         DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
920         break;
921 
922     case PARSEOP_INTEGER:
923 
924         DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X",
925             ACPI_FORMAT_UINT64 (Value));
926         break;
927 
928     default:
929 
930         break;
931     }
932 
933     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
934     return (Op);
935 }
936 
937 
938 /*******************************************************************************
939  *
940  * FUNCTION:    TrCreateNode
941  *
942  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
943  *              NumChildren         - Number of children to follow
944  *              ...                 - A list of child nodes to link to the new
945  *                                    node. NumChildren long.
946  *
947  * RETURN:      Pointer to the new node. Aborts on allocation failure
948  *
949  * DESCRIPTION: Create a new parse node and link together a list of child
950  *              nodes underneath the new node.
951  *
952  ******************************************************************************/
953 
954 ACPI_PARSE_OBJECT *
955 TrCreateNode (
956     UINT32                  ParseOpcode,
957     UINT32                  NumChildren,
958     ...)
959 {
960     ACPI_PARSE_OBJECT       *Op;
961     ACPI_PARSE_OBJECT       *Child;
962     ACPI_PARSE_OBJECT       *PrevChild;
963     va_list                 ap;
964     UINT32                  i;
965     BOOLEAN                 FirstChild;
966 
967 
968     va_start (ap, NumChildren);
969 
970     /* Allocate one new node */
971 
972     Op = TrAllocateNode (ParseOpcode);
973 
974     DbgPrint (ASL_PARSE_OUTPUT,
975         "\nCreateNode  Ln/Col %u/%u NewParent %p Child %u Op %s  ",
976         Op->Asl.LineNumber, Op->Asl.Column, Op,
977         NumChildren, UtGetOpName(ParseOpcode));
978 
979     /* Some extra debug output based on the parse opcode */
980 
981     switch (ParseOpcode)
982     {
983     case PARSEOP_ASL_CODE:
984 
985         RootNode = Op;
986         Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
987         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
988         break;
989 
990     case PARSEOP_DEFINITION_BLOCK:
991 
992         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
993         break;
994 
995     case PARSEOP_OPERATIONREGION:
996 
997         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
998         break;
999 
1000     case PARSEOP_OR:
1001 
1002         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1003         break;
1004 
1005     default:
1006 
1007         /* Nothing to do for other opcodes */
1008 
1009         break;
1010     }
1011 
1012     /* Link the new node to its children */
1013 
1014     PrevChild = NULL;
1015     FirstChild = TRUE;
1016     for (i = 0; i < NumChildren; i++)
1017     {
1018         /* Get the next child */
1019 
1020         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1021         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1022 
1023         /*
1024          * If child is NULL, this means that an optional argument
1025          * was omitted. We must create a placeholder with a special
1026          * opcode (DEFAULT_ARG) so that the code generator will know
1027          * that it must emit the correct default for this argument
1028          */
1029         if (!Child)
1030         {
1031             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1032         }
1033 
1034         /* Link first child to parent */
1035 
1036         if (FirstChild)
1037         {
1038             FirstChild = FALSE;
1039             Op->Asl.Child = Child;
1040         }
1041 
1042         /* Point all children to parent */
1043 
1044         Child->Asl.Parent = Op;
1045 
1046         /* Link children in a peer list */
1047 
1048         if (PrevChild)
1049         {
1050             PrevChild->Asl.Next = Child;
1051         };
1052 
1053         /*
1054          * This child might be a list, point all nodes in the list
1055          * to the same parent
1056          */
1057         while (Child->Asl.Next)
1058         {
1059             Child = Child->Asl.Next;
1060             Child->Asl.Parent = Op;
1061         }
1062 
1063         PrevChild = Child;
1064     }
1065     va_end(ap);
1066 
1067     DbgPrint (ASL_PARSE_OUTPUT, "\n");
1068     return (Op);
1069 }
1070 
1071 
1072 /*******************************************************************************
1073  *
1074  * FUNCTION:    TrLinkChildren
1075  *
1076  * PARAMETERS:  Op                - An existing parse node
1077  *              NumChildren         - Number of children to follow
1078  *              ...                 - A list of child nodes to link to the new
1079  *                                    node. NumChildren long.
1080  *
1081  * RETURN:      The updated (linked) node
1082  *
1083  * DESCRIPTION: Link a group of nodes to an existing parse node
1084  *
1085  ******************************************************************************/
1086 
1087 ACPI_PARSE_OBJECT *
1088 TrLinkChildren (
1089     ACPI_PARSE_OBJECT       *Op,
1090     UINT32                  NumChildren,
1091     ...)
1092 {
1093     ACPI_PARSE_OBJECT       *Child;
1094     ACPI_PARSE_OBJECT       *PrevChild;
1095     va_list                 ap;
1096     UINT32                  i;
1097     BOOLEAN                 FirstChild;
1098 
1099 
1100     va_start (ap, NumChildren);
1101 
1102 
1103     TrSetEndLineNumber (Op);
1104 
1105     DbgPrint (ASL_PARSE_OUTPUT,
1106         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
1107         Op->Asl.LineNumber, Op->Asl.EndLine,
1108         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
1109 
1110     switch (Op->Asl.ParseOpcode)
1111     {
1112     case PARSEOP_ASL_CODE:
1113 
1114         RootNode = Op;
1115         Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1116         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
1117         break;
1118 
1119     case PARSEOP_DEFINITION_BLOCK:
1120 
1121         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
1122         break;
1123 
1124     case PARSEOP_OPERATIONREGION:
1125 
1126         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
1127         break;
1128 
1129     case PARSEOP_OR:
1130 
1131         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
1132         break;
1133 
1134     default:
1135 
1136         /* Nothing to do for other opcodes */
1137 
1138         break;
1139     }
1140 
1141     /* Link the new node to it's children */
1142 
1143     PrevChild = NULL;
1144     FirstChild = TRUE;
1145     for (i = 0; i < NumChildren; i++)
1146     {
1147         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
1148 
1149         if ((Child == PrevChild) && (Child != NULL))
1150         {
1151             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
1152                 "Child node list invalid");
1153             va_end(ap);
1154             return (Op);
1155         }
1156 
1157         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
1158 
1159         /*
1160          * If child is NULL, this means that an optional argument
1161          * was omitted. We must create a placeholder with a special
1162          * opcode (DEFAULT_ARG) so that the code generator will know
1163          * that it must emit the correct default for this argument
1164          */
1165         if (!Child)
1166         {
1167             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1168         }
1169 
1170         /* Link first child to parent */
1171 
1172         if (FirstChild)
1173         {
1174             FirstChild = FALSE;
1175             Op->Asl.Child = Child;
1176         }
1177 
1178         /* Point all children to parent */
1179 
1180         Child->Asl.Parent = Op;
1181 
1182         /* Link children in a peer list */
1183 
1184         if (PrevChild)
1185         {
1186             PrevChild->Asl.Next = Child;
1187         };
1188 
1189         /*
1190          * This child might be a list, point all nodes in the list
1191          * to the same parent
1192          */
1193         while (Child->Asl.Next)
1194         {
1195             Child = Child->Asl.Next;
1196             Child->Asl.Parent = Op;
1197         }
1198 
1199         PrevChild = Child;
1200     }
1201 
1202     va_end(ap);
1203     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
1204     return (Op);
1205 }
1206 
1207 
1208 /*******************************************************************************
1209  *
1210  * FUNCTION:    TrLinkPeerNode
1211  *
1212  * PARAMETERS:  Op1           - First peer
1213  *              Op2           - Second peer
1214  *
1215  * RETURN:      Op1 or the non-null node.
1216  *
1217  * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null.
1218  *
1219  ******************************************************************************/
1220 
1221 ACPI_PARSE_OBJECT *
1222 TrLinkPeerNode (
1223     ACPI_PARSE_OBJECT       *Op1,
1224     ACPI_PARSE_OBJECT       *Op2)
1225 {
1226     ACPI_PARSE_OBJECT       *Next;
1227 
1228 
1229     DbgPrint (ASL_PARSE_OUTPUT,
1230         "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n",
1231         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
1232         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
1233 
1234 
1235     if ((!Op1) && (!Op2))
1236     {
1237         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
1238         return (Op1);
1239     }
1240 
1241     /* If one of the nodes is null, just return the non-null node */
1242 
1243     if (!Op2)
1244     {
1245         return (Op1);
1246     }
1247 
1248     if (!Op1)
1249     {
1250         return (Op2);
1251     }
1252 
1253     if (Op1 == Op2)
1254     {
1255         DbgPrint (ASL_DEBUG_OUTPUT,
1256             "\n************* Internal error, linking node to itself %p\n",
1257             Op1);
1258         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
1259             "Linking node to itself");
1260         return (Op1);
1261     }
1262 
1263     Op1->Asl.Parent = Op2->Asl.Parent;
1264 
1265     /*
1266      * Op 1 may already have a peer list (such as an IF/ELSE pair),
1267      * so we must walk to the end of the list and attach the new
1268      * peer at the end
1269      */
1270     Next = Op1;
1271     while (Next->Asl.Next)
1272     {
1273         Next = Next->Asl.Next;
1274     }
1275 
1276     Next->Asl.Next = Op2;
1277     return (Op1);
1278 }
1279 
1280 
1281 /*******************************************************************************
1282  *
1283  * FUNCTION:    TrLinkPeerNodes
1284  *
1285  * PARAMETERS:  NumPeers            - The number of nodes in the list to follow
1286  *              ...                 - A list of nodes to link together as peers
1287  *
1288  * RETURN:      The first node in the list (head of the peer list)
1289  *
1290  * DESCRIPTION: Link together an arbitrary number of peer nodes.
1291  *
1292  ******************************************************************************/
1293 
1294 ACPI_PARSE_OBJECT *
1295 TrLinkPeerNodes (
1296     UINT32                  NumPeers,
1297     ...)
1298 {
1299     ACPI_PARSE_OBJECT       *This;
1300     ACPI_PARSE_OBJECT       *Next;
1301     va_list                 ap;
1302     UINT32                  i;
1303     ACPI_PARSE_OBJECT       *Start;
1304 
1305 
1306     DbgPrint (ASL_PARSE_OUTPUT,
1307         "\nLinkPeerNodes: (%u) ", NumPeers);
1308 
1309     va_start (ap, NumPeers);
1310     This = va_arg (ap, ACPI_PARSE_OBJECT *);
1311     Start = This;
1312 
1313     /*
1314      * Link all peers
1315      */
1316     for (i = 0; i < (NumPeers -1); i++)
1317     {
1318         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
1319 
1320         while (This->Asl.Next)
1321         {
1322             This = This->Asl.Next;
1323         }
1324 
1325         /* Get another peer node */
1326 
1327         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
1328         if (!Next)
1329         {
1330             Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
1331         }
1332 
1333         /* link new node to the current node */
1334 
1335         This->Asl.Next = Next;
1336         This = Next;
1337     }
1338     va_end (ap);
1339 
1340     DbgPrint (ASL_PARSE_OUTPUT,"\n");
1341     return (Start);
1342 }
1343 
1344 
1345 /*******************************************************************************
1346  *
1347  * FUNCTION:    TrLinkChildNode
1348  *
1349  * PARAMETERS:  Op1           - Parent node
1350  *              Op2           - Op to become a child
1351  *
1352  * RETURN:      The parent node
1353  *
1354  * DESCRIPTION: Link two nodes together as a parent and child
1355  *
1356  ******************************************************************************/
1357 
1358 ACPI_PARSE_OBJECT *
1359 TrLinkChildNode (
1360     ACPI_PARSE_OBJECT       *Op1,
1361     ACPI_PARSE_OBJECT       *Op2)
1362 {
1363     ACPI_PARSE_OBJECT       *Next;
1364 
1365 
1366     DbgPrint (ASL_PARSE_OUTPUT,
1367         "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n",
1368         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
1369         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
1370 
1371     if (!Op1 || !Op2)
1372     {
1373         return (Op1);
1374     }
1375 
1376     Op1->Asl.Child = Op2;
1377 
1378     /* Set the child and all peers of the child to point to the parent */
1379 
1380     Next = Op2;
1381     while (Next)
1382     {
1383         Next->Asl.Parent = Op1;
1384         Next = Next->Asl.Next;
1385     }
1386 
1387     return (Op1);
1388 }
1389 
1390 
1391 /*******************************************************************************
1392  *
1393  * FUNCTION:    TrWalkParseTree
1394  *
1395  * PARAMETERS:  Visitation              - Type of walk
1396  *              DescendingCallback      - Called during tree descent
1397  *              AscendingCallback       - Called during tree ascent
1398  *              Context                 - To be passed to the callbacks
1399  *
1400  * RETURN:      Status from callback(s)
1401  *
1402  * DESCRIPTION: Walk the entire parse tree.
1403  *
1404  ******************************************************************************/
1405 
1406 ACPI_STATUS
1407 TrWalkParseTree (
1408     ACPI_PARSE_OBJECT       *Op,
1409     UINT32                  Visitation,
1410     ASL_WALK_CALLBACK       DescendingCallback,
1411     ASL_WALK_CALLBACK       AscendingCallback,
1412     void                    *Context)
1413 {
1414     UINT32                  Level;
1415     BOOLEAN                 NodePreviouslyVisited;
1416     ACPI_PARSE_OBJECT       *StartOp = Op;
1417     ACPI_STATUS             Status;
1418 
1419 
1420     if (!RootNode)
1421     {
1422         return (AE_OK);
1423     }
1424 
1425     Level = 0;
1426     NodePreviouslyVisited = FALSE;
1427 
1428     switch (Visitation)
1429     {
1430     case ASL_WALK_VISIT_DOWNWARD:
1431 
1432         while (Op)
1433         {
1434             if (!NodePreviouslyVisited)
1435             {
1436                 /* Let the callback process the node. */
1437 
1438                 Status = DescendingCallback (Op, Level, Context);
1439                 if (ACPI_SUCCESS (Status))
1440                 {
1441                     /* Visit children first, once */
1442 
1443                     if (Op->Asl.Child)
1444                     {
1445                         Level++;
1446                         Op = Op->Asl.Child;
1447                         continue;
1448                     }
1449                 }
1450                 else if (Status != AE_CTRL_DEPTH)
1451                 {
1452                     /* Exit immediately on any error */
1453 
1454                     return (Status);
1455                 }
1456             }
1457 
1458             /* Terminate walk at start op */
1459 
1460             if (Op == StartOp)
1461             {
1462                 break;
1463             }
1464 
1465             /* No more children, visit peers */
1466 
1467             if (Op->Asl.Next)
1468             {
1469                 Op = Op->Asl.Next;
1470                 NodePreviouslyVisited = FALSE;
1471             }
1472             else
1473             {
1474                 /* No children or peers, re-visit parent */
1475 
1476                 if (Level != 0 )
1477                 {
1478                     Level--;
1479                 }
1480                 Op = Op->Asl.Parent;
1481                 NodePreviouslyVisited = TRUE;
1482             }
1483         }
1484         break;
1485 
1486     case ASL_WALK_VISIT_UPWARD:
1487 
1488         while (Op)
1489         {
1490             /* Visit leaf node (no children) or parent node on return trip */
1491 
1492             if ((!Op->Asl.Child) ||
1493                 (NodePreviouslyVisited))
1494             {
1495                 /* Let the callback process the node. */
1496 
1497                 Status = AscendingCallback (Op, Level, Context);
1498                 if (ACPI_FAILURE (Status))
1499                 {
1500                     return (Status);
1501                 }
1502             }
1503             else
1504             {
1505                 /* Visit children first, once */
1506 
1507                 Level++;
1508                 Op = Op->Asl.Child;
1509                 continue;
1510             }
1511 
1512             /* Terminate walk at start op */
1513 
1514             if (Op == StartOp)
1515             {
1516                 break;
1517             }
1518 
1519             /* No more children, visit peers */
1520 
1521             if (Op->Asl.Next)
1522             {
1523                 Op = Op->Asl.Next;
1524                 NodePreviouslyVisited = FALSE;
1525             }
1526             else
1527             {
1528                 /* No children or peers, re-visit parent */
1529 
1530                 if (Level != 0 )
1531                 {
1532                     Level--;
1533                 }
1534                 Op = Op->Asl.Parent;
1535                 NodePreviouslyVisited = TRUE;
1536             }
1537         }
1538         break;
1539 
1540      case ASL_WALK_VISIT_TWICE:
1541 
1542         while (Op)
1543         {
1544             if (NodePreviouslyVisited)
1545             {
1546                 Status = AscendingCallback (Op, Level, Context);
1547                 if (ACPI_FAILURE (Status))
1548                 {
1549                     return (Status);
1550                 }
1551             }
1552             else
1553             {
1554                 /* Let the callback process the node. */
1555 
1556                 Status = DescendingCallback (Op, Level, Context);
1557                 if (ACPI_SUCCESS (Status))
1558                 {
1559                     /* Visit children first, once */
1560 
1561                     if (Op->Asl.Child)
1562                     {
1563                         Level++;
1564                         Op = Op->Asl.Child;
1565                         continue;
1566                     }
1567                 }
1568                 else if (Status != AE_CTRL_DEPTH)
1569                 {
1570                     /* Exit immediately on any error */
1571 
1572                     return (Status);
1573                 }
1574             }
1575 
1576             /* Terminate walk at start op */
1577 
1578             if (Op == StartOp)
1579             {
1580                 break;
1581             }
1582 
1583             /* No more children, visit peers */
1584 
1585             if (Op->Asl.Next)
1586             {
1587                 Op = Op->Asl.Next;
1588                 NodePreviouslyVisited = FALSE;
1589             }
1590             else
1591             {
1592                 /* No children or peers, re-visit parent */
1593 
1594                 if (Level != 0 )
1595                 {
1596                     Level--;
1597                 }
1598                 Op = Op->Asl.Parent;
1599                 NodePreviouslyVisited = TRUE;
1600             }
1601         }
1602         break;
1603 
1604     default:
1605         /* No other types supported */
1606         break;
1607     }
1608 
1609     /* If we get here, the walk completed with no errors */
1610 
1611     return (AE_OK);
1612 }
1613