1 /******************************************************************************
2  *
3  * Module Name: asltree - Parse tree management
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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acapps.h"
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("asltree")
50 
51 
52 /*******************************************************************************
53  *
54  * FUNCTION:    TrSetOpIntegerValue
55  *
56  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the op
57  *              Op                  - An existing parse op
58  *
59  * RETURN:      The updated op
60  *
61  * DESCRIPTION: Used to set the integer value of a op,
62  *              usually to a specific size (8, 16, 32, or 64 bits)
63  *
64  ******************************************************************************/
65 
66 ACPI_PARSE_OBJECT *
TrSetOpIntegerValue(UINT32 ParseOpcode,ACPI_PARSE_OBJECT * Op)67 TrSetOpIntegerValue (
68     UINT32                  ParseOpcode,
69     ACPI_PARSE_OBJECT       *Op)
70 {
71 
72     if (!Op)
73     {
74         return (NULL);
75     }
76 
77     DbgPrint (ASL_PARSE_OUTPUT,
78         "\nUpdateOp: Old - %s, New - %s\n",
79         UtGetOpName (Op->Asl.ParseOpcode),
80         UtGetOpName (ParseOpcode));
81 
82     /* Assign new opcode and name */
83 
84     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
85     {
86         switch (ParseOpcode)
87         {
88         case PARSEOP_BYTECONST:
89 
90             Op->Asl.Value.Integer = ACPI_UINT8_MAX;
91             break;
92 
93         case PARSEOP_WORDCONST:
94 
95             Op->Asl.Value.Integer = ACPI_UINT16_MAX;
96             break;
97 
98         case PARSEOP_DWORDCONST:
99 
100             Op->Asl.Value.Integer = ACPI_UINT32_MAX;
101             break;
102 
103         /* Don't need to do the QWORD case */
104 
105         default:
106 
107             /* Don't care about others */
108             break;
109         }
110     }
111 
112     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
113     UtSetParseOpName (Op);
114 
115     /*
116      * For the BYTE, WORD, and DWORD constants, make sure that the integer
117      * that was passed in will actually fit into the data type
118      */
119     switch (ParseOpcode)
120     {
121     case PARSEOP_BYTECONST:
122 
123         UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
124         Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
125         break;
126 
127     case PARSEOP_WORDCONST:
128 
129         UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
130         Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
131         break;
132 
133     case PARSEOP_DWORDCONST:
134 
135         UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
136         Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
137         break;
138 
139     default:
140 
141         /* Don't care about others, don't need to check QWORD */
142 
143         break;
144     }
145 
146     /* Converter: if this is a method invocation, turn off capture comments */
147 
148     if (AcpiGbl_CaptureComments &&
149         (ParseOpcode == PARSEOP_METHODCALL))
150     {
151         AslGbl_CommentState.CaptureComments = FALSE;
152     }
153 
154     return (Op);
155 }
156 
157 
158 /*******************************************************************************
159  *
160  * FUNCTION:    TrSetOpFlags
161  *
162  * PARAMETERS:  Op                  - An existing parse op
163  *              Flags               - New flags word
164  *
165  * RETURN:      The updated parser op
166  *
167  * DESCRIPTION: Set bits in the op flags word. Will not clear bits, only set
168  *
169  ******************************************************************************/
170 
171 ACPI_PARSE_OBJECT *
TrSetOpFlags(ACPI_PARSE_OBJECT * Op,UINT32 Flags)172 TrSetOpFlags (
173     ACPI_PARSE_OBJECT       *Op,
174     UINT32                  Flags)
175 {
176 
177     if (!Op)
178     {
179         return (NULL);
180     }
181 
182     DbgPrint (ASL_PARSE_OUTPUT,
183         "\nSetOpFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
184 
185     TrPrintOpFlags (Flags, ASL_PARSE_OUTPUT);
186     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
187 
188     Op->Asl.CompileFlags |= Flags;
189     return (Op);
190 }
191 
192 
193 /*******************************************************************************
194  *
195  * FUNCTION:    TrSetOpAmlLength
196  *
197  * PARAMETERS:  Op                  - An existing parse op
198  *              Length              - AML Length
199  *
200  * RETURN:      The updated parser op
201  *
202  * DESCRIPTION: Set the AML Length in a op. Used by the parser to indicate
203  *              the presence of a op that must be reduced to a fixed length
204  *              constant.
205  *
206  ******************************************************************************/
207 
208 ACPI_PARSE_OBJECT *
TrSetOpAmlLength(ACPI_PARSE_OBJECT * Op,UINT32 Length)209 TrSetOpAmlLength (
210     ACPI_PARSE_OBJECT       *Op,
211     UINT32                  Length)
212 {
213 
214     DbgPrint (ASL_PARSE_OUTPUT,
215         "\nSetOpAmlLength: Op %p, %8.8X\n", Op, Length);
216 
217     if (!Op)
218     {
219         return (NULL);
220     }
221 
222     Op->Asl.AmlLength = Length;
223     return (Op);
224 }
225 
226 
227 /*******************************************************************************
228  *
229  * FUNCTION:    TrSetOpParent
230  *
231  * PARAMETERS:  Op                  - To be set to new parent
232  *              ParentOp            - The parent
233  *
234  * RETURN:      None, sets Op parent directly
235  *
236  * DESCRIPTION: Change the parent of a parse op.
237  *
238  ******************************************************************************/
239 
240 void
TrSetOpParent(ACPI_PARSE_OBJECT * Op,ACPI_PARSE_OBJECT * ParentOp)241 TrSetOpParent (
242     ACPI_PARSE_OBJECT       *Op,
243     ACPI_PARSE_OBJECT       *ParentOp)
244 {
245 
246     Op->Asl.Parent = ParentOp;
247 }
248 
249 
250 /*******************************************************************************
251  *
252  * FUNCTION:    TrSetOpCurrentFilename
253  *
254  * PARAMETERS:  Op                  - An existing parse op
255  *
256  * RETURN:      None
257  *
258  * DESCRIPTION: Save the include file filename. Used for debug output only.
259  *
260  ******************************************************************************/
261 
262 void
TrSetOpCurrentFilename(ACPI_PARSE_OBJECT * Op)263 TrSetOpCurrentFilename (
264     ACPI_PARSE_OBJECT       *Op)
265 {
266 
267     Op->Asl.Filename = AslGbl_PreviousIncludeFilename;
268 }
269 
270 
271 /*******************************************************************************
272  *
273  * FUNCTION:    TrSetOpIntegerWidth
274  *
275  * PARAMETERS:  Op                  - An existing parse op
276  *
277  * RETURN:      None
278  *
279  * DESCRIPTION:
280  *
281  ******************************************************************************/
282 
283 void
TrSetOpIntegerWidth(ACPI_PARSE_OBJECT * TableSignatureOp,ACPI_PARSE_OBJECT * RevisionOp)284 TrSetOpIntegerWidth (
285     ACPI_PARSE_OBJECT       *TableSignatureOp,
286     ACPI_PARSE_OBJECT       *RevisionOp)
287 {
288 
289     /* TBD: Check table sig? (DSDT vs. SSDT) */
290 
291     /* Handle command-line version override */
292 
293     if (AslGbl_RevisionOverride)
294     {
295         AcpiUtSetIntegerWidth (AslGbl_RevisionOverride);
296     }
297     else
298     {
299         AcpiUtSetIntegerWidth ((UINT8) RevisionOp->Asl.Value.Integer);
300     }
301 }
302 
303 
304 /*******************************************************************************
305  *
306  * FUNCTION:    TrSetOpEndLineNumber
307  *
308  * PARAMETERS:  Op                - An existing parse op
309  *
310  * RETURN:      None.
311  *
312  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
313  *              parse op to the current line numbers.
314  *
315  ******************************************************************************/
316 
317 void
TrSetOpEndLineNumber(ACPI_PARSE_OBJECT * Op)318 TrSetOpEndLineNumber (
319     ACPI_PARSE_OBJECT       *Op)
320 {
321 
322     /* If the end line # is already set, just return */
323 
324     if (Op->Asl.EndLine)
325     {
326         return;
327     }
328 
329     Op->Asl.EndLine = AslGbl_CurrentLineNumber;
330     Op->Asl.EndLogicalLine = AslGbl_LogicalLineNumber;
331 }
332 
333 
334 /*******************************************************************************
335  *
336  * FUNCTION:    TrLinkOpChildren
337  *
338  * PARAMETERS:  Op                - An existing parse op
339  *              NumChildren        - Number of children to follow
340  *              ...                - A list of child ops to link to the new
341  *                                   op. NumChildren long.
342  *
343  * RETURN:      The updated (linked) op
344  *
345  * DESCRIPTION: Link a group of ops to an existing parse op
346  *
347  ******************************************************************************/
348 
349 ACPI_PARSE_OBJECT *
TrLinkOpChildren(ACPI_PARSE_OBJECT * Op,UINT32 NumChildren,...)350 TrLinkOpChildren (
351     ACPI_PARSE_OBJECT       *Op,
352     UINT32                  NumChildren,
353     ...)
354 {
355     ACPI_PARSE_OBJECT       *Child;
356     ACPI_PARSE_OBJECT       *PrevChild;
357     ACPI_PARSE_OBJECT       *LastSibling;
358     va_list                 ap;
359     UINT32                  i;
360     BOOLEAN                 FirstChild;
361 
362 
363     va_start (ap, NumChildren);
364 
365     TrSetOpEndLineNumber (Op);
366 
367     DbgPrint (ASL_PARSE_OUTPUT,
368         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
369         Op->Asl.LineNumber, Op->Asl.EndLine,
370         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
371 
372     switch (Op->Asl.ParseOpcode)
373     {
374     case PARSEOP_ASL_CODE:
375 
376         if (!AslGbl_ParseTreeRoot)
377         {
378             DbgPrint (ASL_PARSE_OUTPUT, "Creating first Definition Block\n");
379             AslGbl_ParseTreeRoot = Op;
380             Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
381         }
382         else
383         {
384             DbgPrint (ASL_PARSE_OUTPUT, "Creating subsequent Definition Block\n");
385             Op = AslGbl_ParseTreeRoot;
386         }
387 
388         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
389         break;
390 
391     case PARSEOP_DEFINITION_BLOCK:
392 
393         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
394         break;
395 
396     case PARSEOP_OPERATIONREGION:
397 
398         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
399         break;
400 
401     case PARSEOP_OR:
402 
403         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
404         break;
405 
406     default:
407 
408         /* Nothing to do for other opcodes */
409 
410         break;
411     }
412 
413     /* The following is for capturing comments */
414 
415     if (AcpiGbl_CaptureComments)
416     {
417         /*
418          * If there are "regular comments" detected at this point,
419          * then is an endBlk comment. Categorize it as so and distribute
420          * all regular comments to this parse op.
421          */
422         if (AslGbl_CommentListHead)
423         {
424             Op->Asl.EndBlkComment = AslGbl_CommentListHead;
425             CvDbgPrint ("EndBlk Comment for %s: %s",
426                 Op->Asl.ParseOpName, AslGbl_CommentListHead->Comment);
427             AslGbl_CommentListHead = NULL;
428             AslGbl_CommentListTail = NULL;
429         }
430     }
431 
432     /* Link the new op to it's children */
433 
434     PrevChild = NULL;
435     FirstChild = TRUE;
436     for (i = 0; i < NumChildren; i++)
437     {
438         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
439 
440         if ((Child == PrevChild) && (Child != NULL))
441         {
442             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
443                 "Child op list invalid");
444             va_end(ap);
445             return (Op);
446         }
447 
448         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
449 
450         /*
451          * If child is NULL, this means that an optional argument
452          * was omitted. We must create a placeholder with a special
453          * opcode (DEFAULT_ARG) so that the code generator will know
454          * that it must emit the correct default for this argument
455          */
456         if (!Child)
457         {
458             Child = TrAllocateOp (PARSEOP_DEFAULT_ARG);
459         }
460 
461         /* Link first child to parent */
462 
463         if (FirstChild)
464         {
465             FirstChild = FALSE;
466 
467             /*
468              * In the case that multiple definition blocks are being compiled,
469              * append the definition block to the end of the child list as the
470              * last sibling. This is done to facilitate namespace cross-
471              * reference between multiple definition blocks.
472              */
473             if (Op->Asl.Child &&
474                 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK))
475             {
476                 LastSibling = Op->Asl.Child;
477                 while (LastSibling->Asl.Next)
478                 {
479                     LastSibling = LastSibling->Asl.Next;
480                 }
481                 LastSibling->Asl.Next = Child;
482             }
483             else
484             {
485                 Op->Asl.Child = Child;
486             }
487         }
488 
489         /* Point all children to parent */
490 
491         Child->Asl.Parent = Op;
492 
493         /* Link children in a peer list */
494 
495         if (PrevChild)
496         {
497             PrevChild->Asl.Next = Child;
498         }
499 
500         /*
501          * This child might be a list, point all ops in the list
502          * to the same parent
503          */
504         while (Child->Asl.Next)
505         {
506             Child = Child->Asl.Next;
507             Child->Asl.Parent = Op;
508         }
509 
510         PrevChild = Child;
511     }
512 
513     va_end(ap);
514     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
515 
516     if (AcpiGbl_CaptureComments)
517     {
518         AslGbl_CommentState.LatestParseOp = Op;
519         CvDbgPrint ("TrLinkOpChildren=====Set latest parse op to this op.\n");
520     }
521 
522     return (Op);
523 }
524 
525 
526 /*******************************************************************************
527  *
528  * FUNCTION:    TrLinkPeerOp
529  *
530  * PARAMETERS:  Op1           - First peer
531  *              Op2           - Second peer
532  *
533  * RETURN:      Op1 or the non-null op.
534  *
535  * DESCRIPTION: Link two ops as peers. Handles cases where one peer is null.
536  *
537  ******************************************************************************/
538 
539 ACPI_PARSE_OBJECT *
TrLinkPeerOp(ACPI_PARSE_OBJECT * Op1,ACPI_PARSE_OBJECT * Op2)540 TrLinkPeerOp (
541     ACPI_PARSE_OBJECT       *Op1,
542     ACPI_PARSE_OBJECT       *Op2)
543 {
544     ACPI_PARSE_OBJECT       *Next;
545 
546 
547     DbgPrint (ASL_PARSE_OUTPUT,
548         "\nLinkPeerOp: 1=%p (%s), 2=%p (%s)\n",
549         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
550         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
551 
552 
553     if ((!Op1) && (!Op2))
554     {
555         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null ops!\n");
556         return (Op1);
557     }
558 
559     /* If one of the ops is null, just return the non-null op */
560 
561     if (!Op2)
562     {
563         return (Op1);
564     }
565 
566     if (!Op1)
567     {
568         return (Op2);
569     }
570 
571     if (Op1 == Op2)
572     {
573         DbgPrint (ASL_DEBUG_OUTPUT,
574             "\n************* Internal error, linking op to itself %p\n",
575             Op1);
576         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
577             "Linking op to itself");
578         return (Op1);
579     }
580 
581     Op1->Asl.Parent = Op2->Asl.Parent;
582 
583     /*
584      * Op 1 may already have a peer list (such as an IF/ELSE pair),
585      * so we must walk to the end of the list and attach the new
586      * peer at the end
587      */
588     Next = Op1;
589     while (Next->Asl.Next)
590     {
591         Next = Next->Asl.Next;
592     }
593 
594     Next->Asl.Next = Op2;
595     return (Op1);
596 }
597 
598 
599 /*******************************************************************************
600  *
601  * FUNCTION:    TrLinkPeerOps
602  *
603  * PARAMETERS:  NumPeers            - The number of ops in the list to follow
604  *              ...                 - A list of ops to link together as peers
605  *
606  * RETURN:      The first op in the list (head of the peer list)
607  *
608  * DESCRIPTION: Link together an arbitrary number of peer ops.
609  *
610  ******************************************************************************/
611 
612 ACPI_PARSE_OBJECT *
TrLinkPeerOps(UINT32 NumPeers,...)613 TrLinkPeerOps (
614     UINT32                  NumPeers,
615     ...)
616 {
617     ACPI_PARSE_OBJECT       *This;
618     ACPI_PARSE_OBJECT       *Next;
619     va_list                 ap;
620     UINT32                  i;
621     ACPI_PARSE_OBJECT       *Start;
622 
623 
624     DbgPrint (ASL_PARSE_OUTPUT,
625         "\nLinkPeerOps: (%u) ", NumPeers);
626 
627     va_start (ap, NumPeers);
628     This = va_arg (ap, ACPI_PARSE_OBJECT *);
629     Start = This;
630 
631     /*
632      * Link all peers
633      */
634     for (i = 0; i < (NumPeers -1); i++)
635     {
636         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
637 
638         while (This->Asl.Next)
639         {
640             This = This->Asl.Next;
641         }
642 
643         /* Get another peer op */
644 
645         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
646         if (!Next)
647         {
648             Next = TrAllocateOp (PARSEOP_DEFAULT_ARG);
649         }
650 
651         /* link new op to the current op */
652 
653         This->Asl.Next = Next;
654         This = Next;
655     }
656 
657     va_end (ap);
658     DbgPrint (ASL_PARSE_OUTPUT,"\n");
659     return (Start);
660 }
661 
662 
663 /*******************************************************************************
664  *
665  * FUNCTION:    TrLinkChildOp
666  *
667  * PARAMETERS:  Op1           - Parent op
668  *              Op2           - Op to become a child
669  *
670  * RETURN:      The parent op
671  *
672  * DESCRIPTION: Link two ops together as a parent and child
673  *
674  ******************************************************************************/
675 
676 ACPI_PARSE_OBJECT *
TrLinkChildOp(ACPI_PARSE_OBJECT * Op1,ACPI_PARSE_OBJECT * Op2)677 TrLinkChildOp (
678     ACPI_PARSE_OBJECT       *Op1,
679     ACPI_PARSE_OBJECT       *Op2)
680 {
681     ACPI_PARSE_OBJECT       *Next;
682 
683 
684     DbgPrint (ASL_PARSE_OUTPUT,
685         "\nLinkChildOp: Parent=%p (%s), Child=%p (%s)\n",
686         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
687         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
688 
689     /*
690      * Converter: if TrLinkChildOp is called to link a method call,
691      * turn on capture comments as it signifies that we are done parsing
692      * a method call.
693      */
694     if (AcpiGbl_CaptureComments && Op1)
695     {
696         if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL)
697         {
698             AslGbl_CommentState.CaptureComments = TRUE;
699         }
700         AslGbl_CommentState.LatestParseOp = Op1;
701     }
702 
703     if (!Op1 || !Op2)
704     {
705         return (Op1);
706     }
707 
708     Op1->Asl.Child = Op2;
709 
710     /* Set the child and all peers of the child to point to the parent */
711 
712     Next = Op2;
713     while (Next)
714     {
715         Next->Asl.Parent = Op1;
716         Next = Next->Asl.Next;
717     }
718 
719     return (Op1);
720 }
721 
722 
723 /*******************************************************************************
724  *
725  * FUNCTION:    TrWalkParseTree
726  *
727  * PARAMETERS:  Op                      - Walk starting point
728  *              Visitation              - Type of walk
729  *              DescendingCallback      - Called during tree descent
730  *              AscendingCallback       - Called during tree ascent
731  *              Context                 - To be passed to the callbacks
732  *
733  * RETURN:      Status from callback(s)
734  *
735  * DESCRIPTION: Walk the entire parse tree.
736  *
737  ******************************************************************************/
738 
739 ACPI_STATUS
TrWalkParseTree(ACPI_PARSE_OBJECT * Op,UINT32 Visitation,ASL_WALK_CALLBACK DescendingCallback,ASL_WALK_CALLBACK AscendingCallback,void * Context)740 TrWalkParseTree (
741     ACPI_PARSE_OBJECT       *Op,
742     UINT32                  Visitation,
743     ASL_WALK_CALLBACK       DescendingCallback,
744     ASL_WALK_CALLBACK       AscendingCallback,
745     void                    *Context)
746 {
747     UINT32                  Level;
748     BOOLEAN                 OpPreviouslyVisited;
749     ACPI_PARSE_OBJECT       *StartOp = Op;
750     ACPI_STATUS             Status;
751     ACPI_PARSE_OBJECT       *Restore = NULL;
752     BOOLEAN                 WalkOneDefinitionBlock = Visitation & ASL_WALK_VISIT_DB_SEPARATELY;
753 
754 
755     if (!AslGbl_ParseTreeRoot)
756     {
757         return (AE_OK);
758     }
759 
760     Level = 0;
761     OpPreviouslyVisited = FALSE;
762 
763     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
764         WalkOneDefinitionBlock)
765     {
766         Restore = Op->Asl.Next;
767         Op->Asl.Next = NULL;
768     }
769     switch (Visitation & ~ASL_WALK_VISIT_DB_SEPARATELY)
770     {
771     case ASL_WALK_VISIT_DOWNWARD:
772 
773         while (Op)
774         {
775             if (!OpPreviouslyVisited)
776             {
777                 /* Let the callback process the op. */
778 
779                 Status = DescendingCallback (Op, Level, Context);
780                 if (ACPI_SUCCESS (Status))
781                 {
782                     /* Visit children first, once */
783 
784                     if (Op->Asl.Child)
785                     {
786                         Level++;
787                         Op = Op->Asl.Child;
788                         continue;
789                     }
790                 }
791                 else if (Status != AE_CTRL_DEPTH)
792                 {
793                     /* Exit immediately on any error */
794 
795                     goto ErrorExit;
796                 }
797             }
798 
799             /* Terminate walk at start op */
800 
801             if (Op == StartOp)
802             {
803                 break;
804             }
805 
806             /* No more children, visit peers */
807 
808             if (Op->Asl.Next)
809             {
810                 Op = Op->Asl.Next;
811                 OpPreviouslyVisited = FALSE;
812             }
813             else
814             {
815                 /* No children or peers, re-visit parent */
816 
817                 if (Level != 0 )
818                 {
819                     Level--;
820                 }
821                 Op = Op->Asl.Parent;
822                 OpPreviouslyVisited = TRUE;
823             }
824         }
825         break;
826 
827     case ASL_WALK_VISIT_UPWARD:
828 
829         while (Op)
830         {
831             /* Visit leaf op (no children) or parent op on return trip */
832 
833             if ((!Op->Asl.Child) ||
834                 (OpPreviouslyVisited))
835             {
836                 /* Let the callback process the op. */
837 
838                 Status = AscendingCallback (Op, Level, Context);
839                 if (ACPI_FAILURE (Status))
840                 {
841                     goto ErrorExit;
842                 }
843             }
844             else
845             {
846                 /* Visit children first, once */
847 
848                 Level++;
849                 Op = Op->Asl.Child;
850                 continue;
851             }
852 
853             /* Terminate walk at start op */
854 
855             if (Op == StartOp)
856             {
857                 break;
858             }
859 
860             /* No more children, visit peers */
861 
862             if (Op->Asl.Next)
863             {
864                 Op = Op->Asl.Next;
865                 OpPreviouslyVisited = FALSE;
866             }
867             else
868             {
869                 /* No children or peers, re-visit parent */
870 
871                 if (Level != 0 )
872                 {
873                     Level--;
874                 }
875                 Op = Op->Asl.Parent;
876                 OpPreviouslyVisited = TRUE;
877             }
878         }
879         break;
880 
881      case ASL_WALK_VISIT_TWICE:
882 
883         while (Op)
884         {
885             if (OpPreviouslyVisited)
886             {
887                 Status = AscendingCallback (Op, Level, Context);
888                 if (ACPI_FAILURE (Status))
889                 {
890                     goto ErrorExit;
891                 }
892             }
893             else
894             {
895                 /* Let the callback process the op. */
896 
897                 Status = DescendingCallback (Op, Level, Context);
898                 if (ACPI_SUCCESS (Status))
899                 {
900                     /* Visit children first, once */
901 
902                     if (Op->Asl.Child)
903                     {
904                         Level++;
905                         Op = Op->Asl.Child;
906                         continue;
907                     }
908                 }
909                 else if (Status != AE_CTRL_DEPTH)
910                 {
911                     /* Exit immediately on any error */
912 
913                     goto ErrorExit;
914                 }
915             }
916 
917             /* Terminate walk at start op */
918 
919             if (Op == StartOp)
920             {
921                 break;
922             }
923 
924             /* No more children, visit peers */
925 
926             if (Op->Asl.Next)
927             {
928                 Op = Op->Asl.Next;
929                 OpPreviouslyVisited = FALSE;
930             }
931             else
932             {
933                 /* No children or peers, re-visit parent */
934 
935                 if (Level != 0 )
936                 {
937                     Level--;
938                 }
939                 Op = Op->Asl.Parent;
940                 OpPreviouslyVisited = TRUE;
941             }
942         }
943         break;
944 
945     default:
946         /* No other types supported */
947         break;
948     }
949 
950     /* If we get here, the walk completed with no errors */
951 
952     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
953         WalkOneDefinitionBlock)
954     {
955         Op->Asl.Next = Restore;
956     }
957 
958     return (AE_OK);
959 
960 ErrorExit:
961 
962     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
963         WalkOneDefinitionBlock)
964     {
965         Op->Asl.Next = Restore;
966     }
967     return (Status);
968 }
969