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