xref: /freebsd/sys/contrib/dev/acpica/compiler/asltree.c (revision 9a41df2a0e6408e9b329bbd8b9e37c2b44461a1b)
1 
2 /******************************************************************************
3  *
4  * Module Name: asltree - parse tree management
5  *
6  *****************************************************************************/
7 
8 /*
9  * Copyright (C) 2000 - 2012, Intel Corp.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions, and the following disclaimer,
17  *    without modification.
18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19  *    substantially similar to the "NO WARRANTY" disclaimer below
20  *    ("Disclaimer") and any redistribution must be conditioned upon
21  *    including a substantially similar Disclaimer requirement for further
22  *    binary redistribution.
23  * 3. Neither the names of the above-listed copyright holders nor the names
24  *    of any contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * Alternatively, this software may be distributed under the terms of the
28  * GNU General Public License ("GPL") version 2 as published by the Free
29  * Software Foundation.
30  *
31  * NO WARRANTY
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42  * POSSIBILITY OF SUCH DAMAGES.
43  */
44 
45 
46 #include <contrib/dev/acpica/compiler/aslcompiler.h>
47 #include "aslcompiler.y.h"
48 #include <contrib/dev/acpica/include/acapps.h>
49 #include <time.h>
50 
51 #define _COMPONENT          ACPI_COMPILER
52         ACPI_MODULE_NAME    ("asltree")
53 
54 /* Local prototypes */
55 
56 static ACPI_PARSE_OBJECT *
57 TrGetNextNode (
58     void);
59 
60 static char *
61 TrGetNodeFlagName (
62     UINT32                  Flags);
63 
64 
65 /*******************************************************************************
66  *
67  * FUNCTION:    TrGetNextNode
68  *
69  * PARAMETERS:  None
70  *
71  * RETURN:      New parse node. Aborts on allocation failure
72  *
73  * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local
74  *              dynamic memory manager for performance reasons (This has a
75  *              major impact on the speed of the compiler.)
76  *
77  ******************************************************************************/
78 
79 static ACPI_PARSE_OBJECT *
80 TrGetNextNode (
81     void)
82 {
83 
84     if (Gbl_NodeCacheNext >= Gbl_NodeCacheLast)
85     {
86         Gbl_NodeCacheNext = UtLocalCalloc (sizeof (ACPI_PARSE_OBJECT) *
87                                 ASL_NODE_CACHE_SIZE);
88         Gbl_NodeCacheLast = Gbl_NodeCacheNext + ASL_NODE_CACHE_SIZE;
89     }
90 
91     return (Gbl_NodeCacheNext++);
92 }
93 
94 
95 /*******************************************************************************
96  *
97  * FUNCTION:    TrAllocateNode
98  *
99  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
100  *
101  * RETURN:      New parse node. Aborts on allocation failure
102  *
103  * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
104  *
105  ******************************************************************************/
106 
107 ACPI_PARSE_OBJECT *
108 TrAllocateNode (
109     UINT32                  ParseOpcode)
110 {
111     ACPI_PARSE_OBJECT       *Op;
112 
113 
114     Op = TrGetNextNode ();
115 
116     Op->Asl.ParseOpcode       = (UINT16) ParseOpcode;
117     Op->Asl.Filename          = Gbl_Files[ASL_FILE_INPUT].Filename;
118     Op->Asl.LineNumber        = Gbl_CurrentLineNumber;
119     Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
120     Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
121     Op->Asl.Column            = Gbl_CurrentColumn;
122 
123     UtSetParseOpName (Op);
124     return Op;
125 }
126 
127 
128 /*******************************************************************************
129  *
130  * FUNCTION:    TrReleaseNode
131  *
132  * PARAMETERS:  Op            - Op to be released
133  *
134  * RETURN:      None
135  *
136  * DESCRIPTION: "release" a node. In truth, nothing is done since the node
137  *              is part of a larger buffer
138  *
139  ******************************************************************************/
140 
141 void
142 TrReleaseNode (
143     ACPI_PARSE_OBJECT       *Op)
144 {
145 
146     return;
147 }
148 
149 
150 /*******************************************************************************
151  *
152  * FUNCTION:    TrUpdateNode
153  *
154  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
155  *              Op                - An existing parse node
156  *
157  * RETURN:      The updated node
158  *
159  * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to
160  *              change an opcode to DEFAULT_ARG so that the node is ignored
161  *              during the code generation. Also used to set generic integers
162  *              to a specific size (8, 16, 32, or 64 bits)
163  *
164  ******************************************************************************/
165 
166 ACPI_PARSE_OBJECT *
167 TrUpdateNode (
168     UINT32                  ParseOpcode,
169     ACPI_PARSE_OBJECT       *Op)
170 {
171 
172     if (!Op)
173     {
174         return NULL;
175     }
176 
177     DbgPrint (ASL_PARSE_OUTPUT,
178         "\nUpdateNode: Old - %s, New - %s\n\n",
179         UtGetOpName (Op->Asl.ParseOpcode),
180         UtGetOpName (ParseOpcode));
181 
182     /* Assign new opcode and name */
183 
184     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
185     {
186         switch (ParseOpcode)
187         {
188         case PARSEOP_BYTECONST:
189             Op->Asl.Value.Integer = ACPI_UINT8_MAX;
190             break;
191 
192         case PARSEOP_WORDCONST:
193             Op->Asl.Value.Integer = ACPI_UINT16_MAX;
194             break;
195 
196         case PARSEOP_DWORDCONST:
197             Op->Asl.Value.Integer = ACPI_UINT32_MAX;
198             break;
199 
200         /* Don't need to do the QWORD case */
201 
202         default:
203             /* Don't care about others */
204             break;
205         }
206     }
207 
208     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
209     UtSetParseOpName (Op);
210 
211     /*
212      * For the BYTE, WORD, and DWORD constants, make sure that the integer
213      * that was passed in will actually fit into the data type
214      */
215     switch (ParseOpcode)
216     {
217     case PARSEOP_BYTECONST:
218         UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
219         Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
220         break;
221 
222     case PARSEOP_WORDCONST:
223         UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
224         Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
225         break;
226 
227     case PARSEOP_DWORDCONST:
228         UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
229         Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
230         break;
231 
232     default:
233         /* Don't care about others, don't need to check QWORD */
234         break;
235     }
236 
237     return Op;
238 }
239 
240 
241 /*******************************************************************************
242  *
243  * FUNCTION:    TrGetNodeFlagName
244  *
245  * PARAMETERS:  Flags               - Flags word to be decoded
246  *
247  * RETURN:      Name string. Always returns a valid string pointer.
248  *
249  * DESCRIPTION: Decode a flags word
250  *
251  ******************************************************************************/
252 
253 static char *
254 TrGetNodeFlagName (
255     UINT32                  Flags)
256 {
257 
258     switch (Flags)
259     {
260     case NODE_VISITED:
261         return ("NODE_VISITED");
262 
263     case NODE_AML_PACKAGE:
264         return ("NODE_AML_PACKAGE");
265 
266     case NODE_IS_TARGET:
267         return ("NODE_IS_TARGET");
268 
269     case NODE_IS_RESOURCE_DESC:
270         return ("NODE_IS_RESOURCE_DESC");
271 
272     case NODE_IS_RESOURCE_FIELD:
273         return ("NODE_IS_RESOURCE_FIELD");
274 
275     case NODE_HAS_NO_EXIT:
276         return ("NODE_HAS_NO_EXIT");
277 
278     case NODE_IF_HAS_NO_EXIT:
279         return ("NODE_IF_HAS_NO_EXIT");
280 
281     case NODE_NAME_INTERNALIZED:
282         return ("NODE_NAME_INTERNALIZED");
283 
284     case NODE_METHOD_NO_RETVAL:
285         return ("NODE_METHOD_NO_RETVAL");
286 
287     case NODE_METHOD_SOME_NO_RETVAL:
288         return ("NODE_METHOD_SOME_NO_RETVAL");
289 
290     case NODE_RESULT_NOT_USED:
291         return ("NODE_RESULT_NOT_USED");
292 
293     case NODE_METHOD_TYPED:
294         return ("NODE_METHOD_TYPED");
295 
296     case NODE_COMPILE_TIME_CONST:
297         return ("NODE_COMPILE_TIME_CONST");
298 
299     case NODE_IS_TERM_ARG:
300         return ("NODE_IS_TERM_ARG");
301 
302     case NODE_WAS_ONES_OP:
303         return ("NODE_WAS_ONES_OP");
304 
305     case NODE_IS_NAME_DECLARATION:
306         return ("NODE_IS_NAME_DECLARATION");
307 
308     default:
309         return ("Multiple Flags (or unknown flag) set");
310     }
311 }
312 
313 
314 /*******************************************************************************
315  *
316  * FUNCTION:    TrSetNodeFlags
317  *
318  * PARAMETERS:  Op                  - An existing parse node
319  *              Flags               - New flags word
320  *
321  * RETURN:      The updated parser op
322  *
323  * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set
324  *
325  ******************************************************************************/
326 
327 ACPI_PARSE_OBJECT *
328 TrSetNodeFlags (
329     ACPI_PARSE_OBJECT       *Op,
330     UINT32                  Flags)
331 {
332 
333     DbgPrint (ASL_PARSE_OUTPUT,
334         "\nSetNodeFlags: Op %p, %8.8X %s\n\n", Op, Flags,
335         TrGetNodeFlagName (Flags));
336 
337     if (!Op)
338     {
339         return NULL;
340     }
341 
342     Op->Asl.CompileFlags |= Flags;
343     return (Op);
344 }
345 
346 
347 /*******************************************************************************
348  *
349  * FUNCTION:    TrSetNodeAmlLength
350  *
351  * PARAMETERS:  Op                  - An existing parse node
352  *              Length              - AML Length
353  *
354  * RETURN:      The updated parser op
355  *
356  * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate
357  *              the presence of a node that must be reduced to a fixed length
358  *              constant.
359  *
360  ******************************************************************************/
361 
362 ACPI_PARSE_OBJECT *
363 TrSetNodeAmlLength (
364     ACPI_PARSE_OBJECT       *Op,
365     UINT32                  Length)
366 {
367 
368     DbgPrint (ASL_PARSE_OUTPUT,
369         "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length);
370 
371     if (!Op)
372     {
373         return NULL;
374     }
375 
376     Op->Asl.AmlLength = Length;
377     return (Op);
378 }
379 
380 
381 /*******************************************************************************
382  *
383  * FUNCTION:    TrSetEndLineNumber
384  *
385  * PARAMETERS:  Op                - An existing parse node
386  *
387  * RETURN:      None.
388  *
389  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
390  *              parse node to the current line numbers.
391  *
392  ******************************************************************************/
393 
394 void
395 TrSetEndLineNumber (
396     ACPI_PARSE_OBJECT       *Op)
397 {
398 
399     /* If the end line # is already set, just return */
400 
401     if (Op->Asl.EndLine)
402     {
403         return;
404     }
405 
406     Op->Asl.EndLine        = Gbl_CurrentLineNumber;
407     Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
408 }
409 
410 
411 /*******************************************************************************
412  *
413  * FUNCTION:    TrCreateLeafNode
414  *
415  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
416  *
417  * RETURN:      Pointer to the new node. Aborts on allocation failure
418  *
419  * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
420  *              assigned to the node)
421  *
422  ******************************************************************************/
423 
424 ACPI_PARSE_OBJECT *
425 TrCreateLeafNode (
426     UINT32                  ParseOpcode)
427 {
428     ACPI_PARSE_OBJECT       *Op;
429 
430 
431     Op = TrAllocateNode (ParseOpcode);
432 
433     DbgPrint (ASL_PARSE_OUTPUT,
434         "\nCreateLeafNode  Ln/Col %u/%u NewNode %p  Op %s\n\n",
435         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode));
436 
437     return Op;
438 }
439 
440 
441 /*******************************************************************************
442  *
443  * FUNCTION:    TrCreateConstantLeafNode
444  *
445  * PARAMETERS:  ParseOpcode         - The constant opcode
446  *
447  * RETURN:      Pointer to the new node. Aborts on allocation failure
448  *
449  * DESCRIPTION: Create a leaf node (no children or peers) for one of the
450  *              special constants - __LINE__, __FILE__, and __DATE__.
451  *
452  * Note: An implemenation of __FUNC__ cannot happen here because we don't
453  * have a full parse tree at this time and cannot find the parent control
454  * method. If it is ever needed, __FUNC__ must be implemented later, after
455  * the parse tree has been fully constructed.
456  *
457  ******************************************************************************/
458 
459 ACPI_PARSE_OBJECT *
460 TrCreateConstantLeafNode (
461     UINT32                  ParseOpcode)
462 {
463     ACPI_PARSE_OBJECT       *Op = NULL;
464     time_t                  CurrentTime;
465     char                    *StaticTimeString;
466     char                    *TimeString;
467     char                    *Path;
468     char                    *Filename;
469 
470 
471     switch (ParseOpcode)
472     {
473     case PARSEOP___LINE__:
474         Op = TrAllocateNode (PARSEOP_INTEGER);
475         Op->Asl.Value.Integer = Op->Asl.LineNumber;
476         break;
477 
478     case PARSEOP___PATH__:
479         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
480 
481         /* Op.Asl.Filename contains the full pathname to the file */
482 
483         Op->Asl.Value.String = Op->Asl.Filename;
484         break;
485 
486     case PARSEOP___FILE__:
487         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
488 
489         /* Get the simple filename from the full path */
490 
491         FlSplitInputPathname (Op->Asl.Filename, &Path, &Filename);
492         ACPI_FREE (Path);
493         Op->Asl.Value.String = Filename;
494         break;
495 
496     case PARSEOP___DATE__:
497         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
498 
499         /* Get a copy of the current time */
500 
501         CurrentTime = time (NULL);
502         StaticTimeString = ctime (&CurrentTime);
503         TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
504         strcpy (TimeString, StaticTimeString);
505 
506         TimeString[strlen(TimeString) -1] = 0;  /* Remove trailing newline */
507         Op->Asl.Value.String = TimeString;
508         break;
509 
510     default: /* This would be an internal error */
511         return (NULL);
512     }
513 
514     DbgPrint (ASL_PARSE_OUTPUT,
515         "\nCreateConstantLeafNode  Ln/Col %u/%u NewNode %p  Op %s  Value %8.8X%8.8X  ",
516         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
517         ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
518     return (Op);
519 }
520 
521 
522 /*******************************************************************************
523  *
524  * FUNCTION:    TrCreateValuedLeafNode
525  *
526  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
527  *              Value               - Value to be assigned to the node
528  *
529  * RETURN:      Pointer to the new node. Aborts on allocation failure
530  *
531  * DESCRIPTION: Create a leaf node (no children or peers) with a value
532  *              assigned to it
533  *
534  ******************************************************************************/
535 
536 ACPI_PARSE_OBJECT *
537 TrCreateValuedLeafNode (
538     UINT32                  ParseOpcode,
539     UINT64                  Value)
540 {
541     ACPI_PARSE_OBJECT       *Op;
542 
543 
544     Op = TrAllocateNode (ParseOpcode);
545 
546     DbgPrint (ASL_PARSE_OUTPUT,
547         "\nCreateValuedLeafNode  Ln/Col %u/%u NewNode %p  Op %s  Value %8.8X%8.8X  ",
548         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
549         ACPI_FORMAT_UINT64 (Value));
550     Op->Asl.Value.Integer = Value;
551 
552     switch (ParseOpcode)
553     {
554     case PARSEOP_STRING_LITERAL:
555         DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
556         break;
557 
558     case PARSEOP_NAMESEG:
559         DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
560         break;
561 
562     case PARSEOP_NAMESTRING:
563         DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
564         break;
565 
566     case PARSEOP_EISAID:
567         DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
568         break;
569 
570     case PARSEOP_METHOD:
571         DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
572         break;
573 
574     case PARSEOP_INTEGER:
575         DbgPrint (ASL_PARSE_OUTPUT, "INTEGER");
576         break;
577 
578     default:
579         break;
580     }
581 
582     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
583     return Op;
584 }
585 
586 
587 /*******************************************************************************
588  *
589  * FUNCTION:    TrCreateNode
590  *
591  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
592  *              NumChildren         - Number of children to follow
593  *              ...                 - A list of child nodes to link to the new
594  *                                    node. NumChildren long.
595  *
596  * RETURN:      Pointer to the new node. Aborts on allocation failure
597  *
598  * DESCRIPTION: Create a new parse node and link together a list of child
599  *              nodes underneath the new node.
600  *
601  ******************************************************************************/
602 
603 ACPI_PARSE_OBJECT *
604 TrCreateNode (
605     UINT32                  ParseOpcode,
606     UINT32                  NumChildren,
607     ...)
608 {
609     ACPI_PARSE_OBJECT       *Op;
610     ACPI_PARSE_OBJECT       *Child;
611     ACPI_PARSE_OBJECT       *PrevChild;
612     va_list                 ap;
613     UINT32                  i;
614     BOOLEAN                 FirstChild;
615 
616 
617     va_start (ap, NumChildren);
618 
619     /* Allocate one new node */
620 
621     Op = TrAllocateNode (ParseOpcode);
622 
623     DbgPrint (ASL_PARSE_OUTPUT,
624         "\nCreateNode  Ln/Col %u/%u NewParent %p Child %u Op %s  ",
625         Op->Asl.LineNumber, Op->Asl.Column, Op, NumChildren, UtGetOpName(ParseOpcode));
626 
627     /* Some extra debug output based on the parse opcode */
628 
629     switch (ParseOpcode)
630     {
631     case PARSEOP_DEFINITIONBLOCK:
632         RootNode = Op;
633         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
634         break;
635 
636     case PARSEOP_OPERATIONREGION:
637         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
638         break;
639 
640     case PARSEOP_OR:
641         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
642         break;
643 
644     default:
645         /* Nothing to do for other opcodes */
646         break;
647     }
648 
649     /* Link the new node to its children */
650 
651     PrevChild = NULL;
652     FirstChild = TRUE;
653     for (i = 0; i < NumChildren; i++)
654     {
655         /* Get the next child */
656 
657         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
658         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
659 
660         /*
661          * If child is NULL, this means that an optional argument
662          * was omitted. We must create a placeholder with a special
663          * opcode (DEFAULT_ARG) so that the code generator will know
664          * that it must emit the correct default for this argument
665          */
666         if (!Child)
667         {
668             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
669         }
670 
671         /* Link first child to parent */
672 
673         if (FirstChild)
674         {
675             FirstChild = FALSE;
676             Op->Asl.Child = Child;
677         }
678 
679         /* Point all children to parent */
680 
681         Child->Asl.Parent = Op;
682 
683         /* Link children in a peer list */
684 
685         if (PrevChild)
686         {
687             PrevChild->Asl.Next = Child;
688         };
689 
690         /*
691          * This child might be a list, point all nodes in the list
692          * to the same parent
693          */
694         while (Child->Asl.Next)
695         {
696             Child = Child->Asl.Next;
697             Child->Asl.Parent = Op;
698         }
699 
700         PrevChild = Child;
701     }
702     va_end(ap);
703 
704     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
705     return Op;
706 }
707 
708 
709 /*******************************************************************************
710  *
711  * FUNCTION:    TrLinkChildren
712  *
713  * PARAMETERS:  Op                - An existing parse node
714  *              NumChildren         - Number of children to follow
715  *              ...                 - A list of child nodes to link to the new
716  *                                    node. NumChildren long.
717  *
718  * RETURN:      The updated (linked) node
719  *
720  * DESCRIPTION: Link a group of nodes to an existing parse node
721  *
722  ******************************************************************************/
723 
724 ACPI_PARSE_OBJECT *
725 TrLinkChildren (
726     ACPI_PARSE_OBJECT       *Op,
727     UINT32                  NumChildren,
728     ...)
729 {
730     ACPI_PARSE_OBJECT       *Child;
731     ACPI_PARSE_OBJECT       *PrevChild;
732     va_list                 ap;
733     UINT32                  i;
734     BOOLEAN                 FirstChild;
735 
736 
737     va_start (ap, NumChildren);
738 
739 
740     TrSetEndLineNumber (Op);
741 
742     DbgPrint (ASL_PARSE_OUTPUT,
743         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
744         Op->Asl.LineNumber, Op->Asl.EndLine,
745         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
746 
747     switch (Op->Asl.ParseOpcode)
748     {
749     case PARSEOP_DEFINITIONBLOCK:
750         RootNode = Op;
751         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
752         break;
753 
754     case PARSEOP_OPERATIONREGION:
755         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
756         break;
757 
758     case PARSEOP_OR:
759         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
760         break;
761 
762     default:
763         /* Nothing to do for other opcodes */
764         break;
765     }
766 
767     /* Link the new node to it's children */
768 
769     PrevChild = NULL;
770     FirstChild = TRUE;
771     for (i = 0; i < NumChildren; i++)
772     {
773         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
774 
775         if ((Child == PrevChild) && (Child != NULL))
776         {
777             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
778                 "Child node list invalid");
779             return Op;
780         }
781 
782         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
783 
784         /*
785          * If child is NULL, this means that an optional argument
786          * was omitted. We must create a placeholder with a special
787          * opcode (DEFAULT_ARG) so that the code generator will know
788          * that it must emit the correct default for this argument
789          */
790         if (!Child)
791         {
792             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
793         }
794 
795         /* Link first child to parent */
796 
797         if (FirstChild)
798         {
799             FirstChild = FALSE;
800             Op->Asl.Child = Child;
801         }
802 
803         /* Point all children to parent */
804 
805         Child->Asl.Parent = Op;
806 
807         /* Link children in a peer list */
808 
809         if (PrevChild)
810         {
811             PrevChild->Asl.Next = Child;
812         };
813 
814         /*
815          * This child might be a list, point all nodes in the list
816          * to the same parent
817          */
818         while (Child->Asl.Next)
819         {
820             Child = Child->Asl.Next;
821             Child->Asl.Parent = Op;
822         }
823         PrevChild = Child;
824     }
825     va_end(ap);
826 
827     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
828     return Op;
829 }
830 
831 
832 /*******************************************************************************
833  *
834  * FUNCTION:    TrLinkPeerNode
835  *
836  * PARAMETERS:  Op1           - First peer
837  *              Op2           - Second peer
838  *
839  * RETURN:      Op1 or the non-null node.
840  *
841  * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null.
842  *
843  ******************************************************************************/
844 
845 ACPI_PARSE_OBJECT *
846 TrLinkPeerNode (
847     ACPI_PARSE_OBJECT       *Op1,
848     ACPI_PARSE_OBJECT       *Op2)
849 {
850     ACPI_PARSE_OBJECT       *Next;
851 
852 
853     DbgPrint (ASL_PARSE_OUTPUT,
854         "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n\n",
855         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
856         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
857 
858 
859     if ((!Op1) && (!Op2))
860     {
861         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
862         return Op1;
863     }
864 
865     /* If one of the nodes is null, just return the non-null node */
866 
867     if (!Op2)
868     {
869         return Op1;
870     }
871 
872     if (!Op1)
873     {
874         return Op2;
875     }
876 
877     if (Op1 == Op2)
878     {
879         DbgPrint (ASL_DEBUG_OUTPUT,
880             "\n\n************* Internal error, linking node to itself %p\n\n\n",
881             Op1);
882         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
883             "Linking node to itself");
884         return Op1;
885     }
886 
887     Op1->Asl.Parent = Op2->Asl.Parent;
888 
889     /*
890      * Op 1 may already have a peer list (such as an IF/ELSE pair),
891      * so we must walk to the end of the list and attach the new
892      * peer at the end
893      */
894     Next = Op1;
895     while (Next->Asl.Next)
896     {
897         Next = Next->Asl.Next;
898     }
899 
900     Next->Asl.Next = Op2;
901     return Op1;
902 }
903 
904 
905 /*******************************************************************************
906  *
907  * FUNCTION:    TrLinkPeerNodes
908  *
909  * PARAMETERS:  NumPeers            - The number of nodes in the list to follow
910  *              ...                 - A list of nodes to link together as peers
911  *
912  * RETURN:      The first node in the list (head of the peer list)
913  *
914  * DESCRIPTION: Link together an arbitrary number of peer nodes.
915  *
916  ******************************************************************************/
917 
918 ACPI_PARSE_OBJECT *
919 TrLinkPeerNodes (
920     UINT32                  NumPeers,
921     ...)
922 {
923     ACPI_PARSE_OBJECT       *This;
924     ACPI_PARSE_OBJECT       *Next;
925     va_list                 ap;
926     UINT32                  i;
927     ACPI_PARSE_OBJECT       *Start;
928 
929 
930     DbgPrint (ASL_PARSE_OUTPUT,
931         "\nLinkPeerNodes: (%u) ", NumPeers);
932 
933     va_start (ap, NumPeers);
934     This = va_arg (ap, ACPI_PARSE_OBJECT *);
935     Start = This;
936 
937     /*
938      * Link all peers
939      */
940     for (i = 0; i < (NumPeers -1); i++)
941     {
942         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
943 
944         while (This->Asl.Next)
945         {
946             This = This->Asl.Next;
947         }
948 
949         /* Get another peer node */
950 
951         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
952         if (!Next)
953         {
954             Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
955         }
956 
957         /* link new node to the current node */
958 
959         This->Asl.Next = Next;
960         This = Next;
961     }
962     va_end (ap);
963 
964     DbgPrint (ASL_PARSE_OUTPUT,"\n\n");
965     return (Start);
966 }
967 
968 
969 /*******************************************************************************
970  *
971  * FUNCTION:    TrLinkChildNode
972  *
973  * PARAMETERS:  Op1           - Parent node
974  *              Op2           - Op to become a child
975  *
976  * RETURN:      The parent node
977  *
978  * DESCRIPTION: Link two nodes together as a parent and child
979  *
980  ******************************************************************************/
981 
982 ACPI_PARSE_OBJECT *
983 TrLinkChildNode (
984     ACPI_PARSE_OBJECT       *Op1,
985     ACPI_PARSE_OBJECT       *Op2)
986 {
987     ACPI_PARSE_OBJECT       *Next;
988 
989 
990     DbgPrint (ASL_PARSE_OUTPUT,
991         "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n\n",
992         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
993         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
994 
995     if (!Op1 || !Op2)
996     {
997         return Op1;
998     }
999 
1000     Op1->Asl.Child = Op2;
1001 
1002     /* Set the child and all peers of the child to point to the parent */
1003 
1004     Next = Op2;
1005     while (Next)
1006     {
1007         Next->Asl.Parent = Op1;
1008         Next = Next->Asl.Next;
1009     }
1010 
1011     return Op1;
1012 }
1013 
1014 
1015 /*******************************************************************************
1016  *
1017  * FUNCTION:    TrWalkParseTree
1018  *
1019  * PARAMETERS:  Visitation              - Type of walk
1020  *              DescendingCallback      - Called during tree descent
1021  *              AscendingCallback       - Called during tree ascent
1022  *              Context                 - To be passed to the callbacks
1023  *
1024  * RETURN:      Status from callback(s)
1025  *
1026  * DESCRIPTION: Walk the entire parse tree.
1027  *
1028  ******************************************************************************/
1029 
1030 ACPI_STATUS
1031 TrWalkParseTree (
1032     ACPI_PARSE_OBJECT       *Op,
1033     UINT32                  Visitation,
1034     ASL_WALK_CALLBACK       DescendingCallback,
1035     ASL_WALK_CALLBACK       AscendingCallback,
1036     void                    *Context)
1037 {
1038     UINT32                  Level;
1039     BOOLEAN                 NodePreviouslyVisited;
1040     ACPI_PARSE_OBJECT       *StartOp = Op;
1041     ACPI_STATUS             Status;
1042 
1043 
1044     if (!RootNode)
1045     {
1046         return (AE_OK);
1047     }
1048 
1049     Level = 0;
1050     NodePreviouslyVisited = FALSE;
1051 
1052     switch (Visitation)
1053     {
1054     case ASL_WALK_VISIT_DOWNWARD:
1055 
1056         while (Op)
1057         {
1058             if (!NodePreviouslyVisited)
1059             {
1060                 /* Let the callback process the node. */
1061 
1062                 Status = DescendingCallback (Op, Level, Context);
1063                 if (ACPI_SUCCESS (Status))
1064                 {
1065                     /* Visit children first, once */
1066 
1067                     if (Op->Asl.Child)
1068                     {
1069                         Level++;
1070                         Op = Op->Asl.Child;
1071                         continue;
1072                     }
1073                 }
1074                 else if (Status != AE_CTRL_DEPTH)
1075                 {
1076                     /* Exit immediately on any error */
1077 
1078                     return (Status);
1079                 }
1080             }
1081 
1082             /* Terminate walk at start op */
1083 
1084             if (Op == StartOp)
1085             {
1086                 break;
1087             }
1088 
1089             /* No more children, visit peers */
1090 
1091             if (Op->Asl.Next)
1092             {
1093                 Op = Op->Asl.Next;
1094                 NodePreviouslyVisited = FALSE;
1095             }
1096             else
1097             {
1098                 /* No children or peers, re-visit parent */
1099 
1100                 if (Level != 0 )
1101                 {
1102                     Level--;
1103                 }
1104                 Op = Op->Asl.Parent;
1105                 NodePreviouslyVisited = TRUE;
1106             }
1107         }
1108         break;
1109 
1110 
1111     case ASL_WALK_VISIT_UPWARD:
1112 
1113         while (Op)
1114         {
1115             /* Visit leaf node (no children) or parent node on return trip */
1116 
1117             if ((!Op->Asl.Child) ||
1118                 (NodePreviouslyVisited))
1119             {
1120                 /* Let the callback process the node. */
1121 
1122                 Status = AscendingCallback (Op, Level, Context);
1123                 if (ACPI_FAILURE (Status))
1124                 {
1125                     return (Status);
1126                 }
1127             }
1128             else
1129             {
1130                 /* Visit children first, once */
1131 
1132                 Level++;
1133                 Op = Op->Asl.Child;
1134                 continue;
1135             }
1136 
1137             /* Terminate walk at start op */
1138 
1139             if (Op == StartOp)
1140             {
1141                 break;
1142             }
1143 
1144             /* No more children, visit peers */
1145 
1146             if (Op->Asl.Next)
1147             {
1148                 Op = Op->Asl.Next;
1149                 NodePreviouslyVisited = FALSE;
1150             }
1151             else
1152             {
1153                 /* No children or peers, re-visit parent */
1154 
1155                 if (Level != 0 )
1156                 {
1157                     Level--;
1158                 }
1159                 Op = Op->Asl.Parent;
1160                 NodePreviouslyVisited = TRUE;
1161             }
1162         }
1163         break;
1164 
1165 
1166      case ASL_WALK_VISIT_TWICE:
1167 
1168         while (Op)
1169         {
1170             if (NodePreviouslyVisited)
1171             {
1172                 Status = AscendingCallback (Op, Level, Context);
1173                 if (ACPI_FAILURE (Status))
1174                 {
1175                     return (Status);
1176                 }
1177             }
1178             else
1179             {
1180                 /* Let the callback process the node. */
1181 
1182                 Status = DescendingCallback (Op, Level, Context);
1183                 if (ACPI_SUCCESS (Status))
1184                 {
1185                     /* Visit children first, once */
1186 
1187                     if (Op->Asl.Child)
1188                     {
1189                         Level++;
1190                         Op = Op->Asl.Child;
1191                         continue;
1192                     }
1193                 }
1194                 else if (Status != AE_CTRL_DEPTH)
1195                 {
1196                     /* Exit immediately on any error */
1197 
1198                     return (Status);
1199                 }
1200             }
1201 
1202             /* Terminate walk at start op */
1203 
1204             if (Op == StartOp)
1205             {
1206                 break;
1207             }
1208 
1209             /* No more children, visit peers */
1210 
1211             if (Op->Asl.Next)
1212             {
1213                 Op = Op->Asl.Next;
1214                 NodePreviouslyVisited = FALSE;
1215             }
1216             else
1217             {
1218                 /* No children or peers, re-visit parent */
1219 
1220                 if (Level != 0 )
1221                 {
1222                     Level--;
1223                 }
1224                 Op = Op->Asl.Parent;
1225                 NodePreviouslyVisited = TRUE;
1226             }
1227         }
1228         break;
1229 
1230     default:
1231         /* No other types supported */
1232         break;
1233     }
1234 
1235     /* If we get here, the walk completed with no errors */
1236 
1237     return (AE_OK);
1238 }
1239 
1240 
1241