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