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