xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/asltree.c (revision 2c7d7e3ca2e4f0b675c6c58e614f6aede66c678e)
1 /******************************************************************************
2  *
3  * Module Name: asltree - Parse tree management
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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     ACPI_FUNCTION_NAME (TrLinkOpChildren);
363 
364     va_start (ap, NumChildren);
365 
366     TrSetOpEndLineNumber (Op);
367 
368     DbgPrint (ASL_PARSE_OUTPUT,
369         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
370         Op->Asl.LineNumber, Op->Asl.EndLine,
371         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
372 
373     switch (Op->Asl.ParseOpcode)
374     {
375     case PARSEOP_ASL_CODE:
376 
377         if (!AslGbl_ParseTreeRoot)
378         {
379             DbgPrint (ASL_PARSE_OUTPUT, "Creating first Definition Block\n");
380             AslGbl_ParseTreeRoot = Op;
381             Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
382         }
383         else
384         {
385             DbgPrint (ASL_PARSE_OUTPUT, "Creating subsequent Definition Block\n");
386             Op = AslGbl_ParseTreeRoot;
387         }
388 
389         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
390         break;
391 
392     case PARSEOP_DEFINITION_BLOCK:
393 
394         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
395         break;
396 
397     case PARSEOP_OPERATIONREGION:
398 
399         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
400         break;
401 
402     case PARSEOP_OR:
403 
404         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
405         break;
406 
407     default:
408 
409         /* Nothing to do for other opcodes */
410 
411         break;
412     }
413 
414     /* The following is for capturing comments */
415 
416     if (AcpiGbl_CaptureComments)
417     {
418         /*
419          * If there are "regular comments" detected at this point,
420          * then is an endBlk comment. Categorize it as so and distribute
421          * all regular comments to this parse op.
422          */
423         if (AslGbl_CommentListHead)
424         {
425             Op->Asl.EndBlkComment = AslGbl_CommentListHead;
426             CvDbgPrint ("EndBlk Comment for %s: %s",
427                 Op->Asl.ParseOpName, AslGbl_CommentListHead->Comment);
428             AslGbl_CommentListHead = NULL;
429             AslGbl_CommentListTail = NULL;
430         }
431     }
432 
433     /* Link the new op to it's children */
434 
435     PrevChild = NULL;
436     FirstChild = TRUE;
437     for (i = 0; i < NumChildren; i++)
438     {
439         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
440 
441         if ((Child == PrevChild) && (Child != NULL))
442         {
443             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
444                 "Child op list invalid");
445             va_end(ap);
446             return (Op);
447         }
448 
449         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
450 
451         /*
452          * If child is NULL, this means that an optional argument
453          * was omitted. We must create a placeholder with a special
454          * opcode (DEFAULT_ARG) so that the code generator will know
455          * that it must emit the correct default for this argument
456          */
457         if (!Child)
458         {
459             Child = TrAllocateOp (PARSEOP_DEFAULT_ARG);
460         }
461 
462         /* Link first child to parent */
463 
464         if (FirstChild)
465         {
466             FirstChild = FALSE;
467 
468             /*
469              * In the case that multiple definition blocks are being compiled,
470              * append the definition block to the end of the child list as the
471              * last sibling. This is done to facilitate namespace cross-
472              * reference between multiple definition blocks.
473              */
474             if (Op->Asl.Child &&
475                 (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK))
476             {
477                 LastSibling = Op->Asl.Child;
478                 while (LastSibling->Asl.Next)
479                 {
480                     LastSibling = LastSibling->Asl.Next;
481                 }
482                 LastSibling->Asl.Next = Child;
483             }
484             else
485             {
486                 Op->Asl.Child = Child;
487             }
488         }
489 
490         /* Point all children to parent */
491 
492         Child->Asl.Parent = Op;
493 
494         /* Link children in a peer list */
495 
496         if (PrevChild)
497         {
498             PrevChild->Asl.Next = Child;
499         }
500 
501         /*
502          * This child might be a list, point all ops in the list
503          * to the same parent
504          */
505         while (Child->Asl.Next)
506         {
507             Child = Child->Asl.Next;
508             Child->Asl.Parent = Op;
509         }
510 
511         PrevChild = Child;
512     }
513 
514     va_end(ap);
515     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
516 
517     if (AcpiGbl_CaptureComments)
518     {
519         AslGbl_CommentState.LatestParseOp = Op;
520         CvDbgPrint ("%s=====Set latest parse op to this op.\n",  ACPI_GET_FUNCTION_NAME);
521     }
522 
523     return (Op);
524 }
525 
526 
527 /*******************************************************************************
528  *
529  * FUNCTION:    TrLinkPeerOp
530  *
531  * PARAMETERS:  Op1           - First peer
532  *              Op2           - Second peer
533  *
534  * RETURN:      Op1 or the non-null op.
535  *
536  * DESCRIPTION: Link two ops as peers. Handles cases where one peer is null.
537  *
538  ******************************************************************************/
539 
540 ACPI_PARSE_OBJECT *
TrLinkPeerOp(ACPI_PARSE_OBJECT * Op1,ACPI_PARSE_OBJECT * Op2)541 TrLinkPeerOp (
542     ACPI_PARSE_OBJECT       *Op1,
543     ACPI_PARSE_OBJECT       *Op2)
544 {
545     ACPI_PARSE_OBJECT       *Next;
546 
547 
548     DbgPrint (ASL_PARSE_OUTPUT,
549         "\nLinkPeerOp: 1=%p (%s), 2=%p (%s)\n",
550         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
551         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
552 
553 
554     if ((!Op1) && (!Op2))
555     {
556         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null ops!\n");
557         return (Op1);
558     }
559 
560     /* If one of the ops is null, just return the non-null op */
561 
562     if (!Op2)
563     {
564         return (Op1);
565     }
566 
567     if (!Op1)
568     {
569         return (Op2);
570     }
571 
572     if (Op1 == Op2)
573     {
574         DbgPrint (ASL_DEBUG_OUTPUT,
575             "\n************* Internal error, linking op to itself %p\n",
576             Op1);
577         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
578             "Linking op to itself");
579         return (Op1);
580     }
581 
582     Op1->Asl.Parent = Op2->Asl.Parent;
583 
584     /*
585      * Op 1 may already have a peer list (such as an IF/ELSE pair),
586      * so we must walk to the end of the list and attach the new
587      * peer at the end
588      */
589     Next = Op1;
590     while (Next->Asl.Next)
591     {
592         Next = Next->Asl.Next;
593     }
594 
595     Next->Asl.Next = Op2;
596     return (Op1);
597 }
598 
599 
600 /*******************************************************************************
601  *
602  * FUNCTION:    TrLinkPeerOps
603  *
604  * PARAMETERS:  NumPeers            - The number of ops in the list to follow
605  *              ...                 - A list of ops to link together as peers
606  *
607  * RETURN:      The first op in the list (head of the peer list)
608  *
609  * DESCRIPTION: Link together an arbitrary number of peer ops.
610  *
611  ******************************************************************************/
612 
613 ACPI_PARSE_OBJECT *
TrLinkPeerOps(UINT32 NumPeers,...)614 TrLinkPeerOps (
615     UINT32                  NumPeers,
616     ...)
617 {
618     ACPI_PARSE_OBJECT       *This;
619     ACPI_PARSE_OBJECT       *Next;
620     va_list                 ap;
621     UINT32                  i;
622     ACPI_PARSE_OBJECT       *Start;
623 
624 
625     DbgPrint (ASL_PARSE_OUTPUT,
626         "\nLinkPeerOps: (%u) ", NumPeers);
627 
628     va_start (ap, NumPeers);
629     This = va_arg (ap, ACPI_PARSE_OBJECT *);
630     Start = This;
631 
632     /*
633      * Link all peers
634      */
635     for (i = 0; i < (NumPeers -1); i++)
636     {
637         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
638 
639         while (This->Asl.Next)
640         {
641             This = This->Asl.Next;
642         }
643 
644         /* Get another peer op */
645 
646         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
647         if (!Next)
648         {
649             Next = TrAllocateOp (PARSEOP_DEFAULT_ARG);
650         }
651 
652         /* link new op to the current op */
653 
654         This->Asl.Next = Next;
655         This = Next;
656     }
657 
658     va_end (ap);
659     DbgPrint (ASL_PARSE_OUTPUT,"\n");
660     return (Start);
661 }
662 
663 
664 /*******************************************************************************
665  *
666  * FUNCTION:    TrLinkChildOp
667  *
668  * PARAMETERS:  Op1           - Parent op
669  *              Op2           - Op to become a child
670  *
671  * RETURN:      The parent op
672  *
673  * DESCRIPTION: Link two ops together as a parent and child
674  *
675  ******************************************************************************/
676 
677 ACPI_PARSE_OBJECT *
TrLinkChildOp(ACPI_PARSE_OBJECT * Op1,ACPI_PARSE_OBJECT * Op2)678 TrLinkChildOp (
679     ACPI_PARSE_OBJECT       *Op1,
680     ACPI_PARSE_OBJECT       *Op2)
681 {
682     ACPI_PARSE_OBJECT       *Next;
683 
684 
685     DbgPrint (ASL_PARSE_OUTPUT,
686         "\nLinkChildOp: Parent=%p (%s), Child=%p (%s)\n",
687         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
688         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
689 
690     /*
691      * Converter: if TrLinkChildOp is called to link a method call,
692      * turn on capture comments as it signifies that we are done parsing
693      * a method call.
694      */
695     if (AcpiGbl_CaptureComments && Op1)
696     {
697         if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL)
698         {
699             AslGbl_CommentState.CaptureComments = TRUE;
700         }
701         AslGbl_CommentState.LatestParseOp = Op1;
702     }
703 
704     if (!Op1 || !Op2)
705     {
706         return (Op1);
707     }
708 
709     Op1->Asl.Child = Op2;
710 
711     /* Set the child and all peers of the child to point to the parent */
712 
713     Next = Op2;
714     while (Next)
715     {
716         Next->Asl.Parent = Op1;
717         Next = Next->Asl.Next;
718     }
719 
720     return (Op1);
721 }
722 
723 
724 /*******************************************************************************
725  *
726  * FUNCTION:    TrWalkParseTree
727  *
728  * PARAMETERS:  Op                      - Walk starting point
729  *              Visitation              - Type of walk
730  *              DescendingCallback      - Called during tree descent
731  *              AscendingCallback       - Called during tree ascent
732  *              Context                 - To be passed to the callbacks
733  *
734  * RETURN:      Status from callback(s)
735  *
736  * DESCRIPTION: Walk the entire parse tree.
737  *
738  ******************************************************************************/
739 
740 ACPI_STATUS
TrWalkParseTree(ACPI_PARSE_OBJECT * Op,UINT32 Visitation,ASL_WALK_CALLBACK DescendingCallback,ASL_WALK_CALLBACK AscendingCallback,void * Context)741 TrWalkParseTree (
742     ACPI_PARSE_OBJECT       *Op,
743     UINT32                  Visitation,
744     ASL_WALK_CALLBACK       DescendingCallback,
745     ASL_WALK_CALLBACK       AscendingCallback,
746     void                    *Context)
747 {
748     UINT32                  Level;
749     BOOLEAN                 OpPreviouslyVisited;
750     ACPI_PARSE_OBJECT       *StartOp = Op;
751     ACPI_STATUS             Status;
752     ACPI_PARSE_OBJECT       *Restore = NULL;
753     BOOLEAN                 WalkOneDefinitionBlock = Visitation & ASL_WALK_VISIT_DB_SEPARATELY;
754 
755 
756     if (!AslGbl_ParseTreeRoot)
757     {
758         return (AE_OK);
759     }
760 
761     Level = 0;
762     OpPreviouslyVisited = FALSE;
763 
764     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
765         WalkOneDefinitionBlock)
766     {
767         Restore = Op->Asl.Next;
768         Op->Asl.Next = NULL;
769     }
770     switch (Visitation & ~ASL_WALK_VISIT_DB_SEPARATELY)
771     {
772     case ASL_WALK_VISIT_DOWNWARD:
773 
774         while (Op)
775         {
776             if (!OpPreviouslyVisited)
777             {
778                 /* Let the callback process the op. */
779 
780                 Status = DescendingCallback (Op, Level, Context);
781                 if (ACPI_SUCCESS (Status))
782                 {
783                     /* Visit children first, once */
784 
785                     if (Op->Asl.Child)
786                     {
787                         Level++;
788                         Op = Op->Asl.Child;
789                         continue;
790                     }
791                 }
792                 else if (Status != AE_CTRL_DEPTH)
793                 {
794                     /* Exit immediately on any error */
795 
796                     goto ErrorExit;
797                 }
798             }
799 
800             /* Terminate walk at start op */
801 
802             if (Op == StartOp)
803             {
804                 break;
805             }
806 
807             /* No more children, visit peers */
808 
809             if (Op->Asl.Next)
810             {
811                 Op = Op->Asl.Next;
812                 OpPreviouslyVisited = FALSE;
813             }
814             else
815             {
816                 /* No children or peers, re-visit parent */
817 
818                 if (Level != 0 )
819                 {
820                     Level--;
821                 }
822                 Op = Op->Asl.Parent;
823                 OpPreviouslyVisited = TRUE;
824             }
825         }
826         break;
827 
828     case ASL_WALK_VISIT_UPWARD:
829 
830         while (Op)
831         {
832             /* Visit leaf op (no children) or parent op on return trip */
833 
834             if ((!Op->Asl.Child) ||
835                 (OpPreviouslyVisited))
836             {
837                 /* Let the callback process the op. */
838 
839                 Status = AscendingCallback (Op, Level, Context);
840                 if (ACPI_FAILURE (Status))
841                 {
842                     goto ErrorExit;
843                 }
844             }
845             else
846             {
847                 /* Visit children first, once */
848 
849                 Level++;
850                 Op = Op->Asl.Child;
851                 continue;
852             }
853 
854             /* Terminate walk at start op */
855 
856             if (Op == StartOp)
857             {
858                 break;
859             }
860 
861             /* No more children, visit peers */
862 
863             if (Op->Asl.Next)
864             {
865                 Op = Op->Asl.Next;
866                 OpPreviouslyVisited = FALSE;
867             }
868             else
869             {
870                 /* No children or peers, re-visit parent */
871 
872                 if (Level != 0 )
873                 {
874                     Level--;
875                 }
876                 Op = Op->Asl.Parent;
877                 OpPreviouslyVisited = TRUE;
878             }
879         }
880         break;
881 
882      case ASL_WALK_VISIT_TWICE:
883 
884         while (Op)
885         {
886             if (OpPreviouslyVisited)
887             {
888                 Status = AscendingCallback (Op, Level, Context);
889                 if (ACPI_FAILURE (Status))
890                 {
891                     goto ErrorExit;
892                 }
893             }
894             else
895             {
896                 /* Let the callback process the op. */
897 
898                 Status = DescendingCallback (Op, Level, Context);
899                 if (ACPI_SUCCESS (Status))
900                 {
901                     /* Visit children first, once */
902 
903                     if (Op->Asl.Child)
904                     {
905                         Level++;
906                         Op = Op->Asl.Child;
907                         continue;
908                     }
909                 }
910                 else if (Status != AE_CTRL_DEPTH)
911                 {
912                     /* Exit immediately on any error */
913 
914                     goto ErrorExit;
915                 }
916             }
917 
918             /* Terminate walk at start op */
919 
920             if (Op == StartOp)
921             {
922                 break;
923             }
924 
925             /* No more children, visit peers */
926 
927             if (Op->Asl.Next)
928             {
929                 Op = Op->Asl.Next;
930                 OpPreviouslyVisited = FALSE;
931             }
932             else
933             {
934                 /* No children or peers, re-visit parent */
935 
936                 if (Level != 0 )
937                 {
938                     Level--;
939                 }
940                 Op = Op->Asl.Parent;
941                 OpPreviouslyVisited = TRUE;
942             }
943         }
944         break;
945 
946     default:
947         /* No other types supported */
948         break;
949     }
950 
951     /* If we get here, the walk completed with no errors */
952 
953     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
954         WalkOneDefinitionBlock)
955     {
956         Op->Asl.Next = Restore;
957     }
958 
959     return (AE_OK);
960 
961 ErrorExit:
962 
963     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK &&
964         WalkOneDefinitionBlock)
965     {
966         Op->Asl.Next = Restore;
967     }
968     return (Status);
969 }
970