Home | History | Annotate | Line # | Download | only in compiler
dtutils.c revision 1.12
      1 /******************************************************************************
      2  *
      3  * Module Name: dtutils.c - Utility routines for the data table compiler
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2018, 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 "actables.h"
     46 
     47 #define _COMPONENT          DT_COMPILER
     48         ACPI_MODULE_NAME    ("dtutils")
     49 
     50 /* Local prototypes */
     51 
     52 static void
     53 DtSum (
     54     DT_SUBTABLE             *Subtable,
     55     void                    *Context,
     56     void                    *ReturnValue);
     57 
     58 
     59 /******************************************************************************
     60  *
     61  * FUNCTION:    DtError
     62  *
     63  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
     64  *              MessageId           - Index into global message buffer
     65  *              Op                  - Parse node where error happened
     66  *              ExtraMessage        - additional error message
     67  *
     68  * RETURN:      None
     69  *
     70  * DESCRIPTION: Common error interface for data table compiler
     71  *
     72  *****************************************************************************/
     73 
     74 void
     75 DtError (
     76     UINT8                   Level,
     77     UINT16                  MessageId,
     78     DT_FIELD                *FieldObject,
     79     char                    *ExtraMessage)
     80 {
     81 
     82     /* Check if user wants to ignore this exception */
     83 
     84     if (AslIsExceptionIgnored (Level, MessageId))
     85     {
     86         return;
     87     }
     88 
     89     if (FieldObject)
     90     {
     91         AslCommonError (Level, MessageId,
     92             FieldObject->Line,
     93             FieldObject->Line,
     94             FieldObject->ByteOffset,
     95             FieldObject->Column,
     96             AslGbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
     97     }
     98     else
     99     {
    100         AslCommonError (Level, MessageId, 0,
    101             0, 0, 0, 0, ExtraMessage);
    102     }
    103 }
    104 
    105 
    106 /******************************************************************************
    107  *
    108  * FUNCTION:    DtNameError
    109  *
    110  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
    111  *              MessageId           - Index into global message buffer
    112  *              Op                  - Parse node where error happened
    113  *              ExtraMessage        - additional error message
    114  *
    115  * RETURN:      None
    116  *
    117  * DESCRIPTION: Error interface for named objects
    118  *
    119  *****************************************************************************/
    120 
    121 void
    122 DtNameError (
    123     UINT8                   Level,
    124     UINT16                  MessageId,
    125     DT_FIELD                *FieldObject,
    126     char                    *ExtraMessage)
    127 {
    128 
    129     switch (Level)
    130     {
    131     case ASL_WARNING2:
    132     case ASL_WARNING3:
    133 
    134         if (AslGbl_WarningLevel < Level)
    135         {
    136             return;
    137         }
    138         break;
    139 
    140     default:
    141 
    142         break;
    143     }
    144 
    145     if (FieldObject)
    146     {
    147         AslCommonError (Level, MessageId,
    148             FieldObject->Line,
    149             FieldObject->Line,
    150             FieldObject->ByteOffset,
    151             FieldObject->NameColumn,
    152             AslGbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
    153     }
    154     else
    155     {
    156         AslCommonError (Level, MessageId, 0,
    157             0, 0, 0, 0, ExtraMessage);
    158     }
    159 }
    160 
    161 
    162 /*******************************************************************************
    163  *
    164  * FUNCTION:    DtFatal
    165  *
    166  * PARAMETERS:  None
    167  *
    168  * RETURN:      None
    169  *
    170  * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
    171  *              compile or I/O errors
    172  *
    173  ******************************************************************************/
    174 
    175 void
    176 DtFatal (
    177     UINT16                  MessageId,
    178     DT_FIELD                *FieldObject,
    179     char                    *ExtraMessage)
    180 {
    181 
    182     DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
    183 
    184 /*
    185  * TBD: remove this entire function, DtFatal
    186  *
    187  * We cannot abort the compiler on error, because we may be compiling a
    188  * list of files. We must move on to the next file.
    189  */
    190 #ifdef __OBSOLETE
    191     CmCleanupAndExit ();
    192     exit (1);
    193 #endif
    194 }
    195 
    196 
    197 /*******************************************************************************
    198  *
    199  * FUNCTION:    DtDoConstant
    200  *
    201  * PARAMETERS:  String              - Only hex constants are supported,
    202  *                                    regardless of whether the 0x prefix
    203  *                                    is used
    204  *
    205  * RETURN:      Converted Integer
    206  *
    207  * DESCRIPTION: Convert a string to an integer, with overflow/error checking.
    208  *
    209  ******************************************************************************/
    210 
    211 UINT64
    212 DtDoConstant (
    213     char                    *String)
    214 {
    215     UINT64                  ConvertedInteger;
    216 
    217 
    218     /*
    219      * TBD: The ImplicitStrtoul64 function does not report overflow
    220      * conditions. The input string is simply truncated. If it is
    221      * desired to report overflow to the table compiler, this should
    222      * somehow be added here. Note: integers that are prefixed with 0x
    223      * or not are both hex integers.
    224      */
    225     ConvertedInteger = AcpiUtImplicitStrtoul64 (String);
    226     return (ConvertedInteger);
    227 }
    228 
    229 /******************************************************************************
    230  *
    231  * FUNCTION:    DtGetFieldValue
    232  *
    233  * PARAMETERS:  Field               - Current field list pointer
    234  *
    235  * RETURN:      Field value
    236  *
    237  * DESCRIPTION: Get field value
    238  *
    239  *****************************************************************************/
    240 
    241 char *
    242 DtGetFieldValue (
    243     DT_FIELD                *Field)
    244 {
    245     if (!Field)
    246     {
    247         return (NULL);
    248     }
    249 
    250     return (Field->Value);
    251 }
    252 
    253 
    254 /******************************************************************************
    255  *
    256  * FUNCTION:    DtGetFieldType
    257  *
    258  * PARAMETERS:  Info                - Data table info
    259  *
    260  * RETURN:      Field type
    261  *
    262  * DESCRIPTION: Get field type
    263  *
    264  *****************************************************************************/
    265 
    266 UINT8
    267 DtGetFieldType (
    268     ACPI_DMTABLE_INFO       *Info)
    269 {
    270     UINT8                   Type;
    271 
    272 
    273     /* DT_FLAG means that this is the start of a block of flag bits */
    274     /* TBD - we can make these a separate opcode later */
    275 
    276     if (Info->Flags & DT_FLAG)
    277     {
    278         return (DT_FIELD_TYPE_FLAGS_INTEGER);
    279     }
    280 
    281     /* Type is based upon the opcode for this field in the info table */
    282 
    283     switch (Info->Opcode)
    284     {
    285     case ACPI_DMT_FLAG0:
    286     case ACPI_DMT_FLAG1:
    287     case ACPI_DMT_FLAG2:
    288     case ACPI_DMT_FLAG3:
    289     case ACPI_DMT_FLAG4:
    290     case ACPI_DMT_FLAG5:
    291     case ACPI_DMT_FLAG6:
    292     case ACPI_DMT_FLAG7:
    293     case ACPI_DMT_FLAGS0:
    294     case ACPI_DMT_FLAGS1:
    295     case ACPI_DMT_FLAGS2:
    296     case ACPI_DMT_FLAGS4:
    297     case ACPI_DMT_FLAGS4_0:
    298     case ACPI_DMT_FLAGS4_4:
    299     case ACPI_DMT_FLAGS4_8:
    300     case ACPI_DMT_FLAGS4_12:
    301     case ACPI_DMT_FLAGS16_16:
    302 
    303         Type = DT_FIELD_TYPE_FLAG;
    304         break;
    305 
    306     case ACPI_DMT_NAME4:
    307     case ACPI_DMT_SIG:
    308     case ACPI_DMT_NAME6:
    309     case ACPI_DMT_NAME8:
    310     case ACPI_DMT_STRING:
    311 
    312         Type = DT_FIELD_TYPE_STRING;
    313         break;
    314 
    315     case ACPI_DMT_BUFFER:
    316     case ACPI_DMT_RAW_BUFFER:
    317     case ACPI_DMT_BUF7:
    318     case ACPI_DMT_BUF10:
    319     case ACPI_DMT_BUF12:
    320     case ACPI_DMT_BUF16:
    321     case ACPI_DMT_BUF128:
    322     case ACPI_DMT_PCI_PATH:
    323 
    324         Type = DT_FIELD_TYPE_BUFFER;
    325         break;
    326 
    327     case ACPI_DMT_GAS:
    328     case ACPI_DMT_HESTNTFY:
    329     case ACPI_DMT_IORTMEM:
    330 
    331         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
    332         break;
    333 
    334     case ACPI_DMT_UNICODE:
    335 
    336         Type = DT_FIELD_TYPE_UNICODE;
    337         break;
    338 
    339     case ACPI_DMT_UUID:
    340 
    341         Type = DT_FIELD_TYPE_UUID;
    342         break;
    343 
    344     case ACPI_DMT_DEVICE_PATH:
    345 
    346         Type = DT_FIELD_TYPE_DEVICE_PATH;
    347         break;
    348 
    349     case ACPI_DMT_LABEL:
    350 
    351         Type = DT_FIELD_TYPE_LABEL;
    352         break;
    353 
    354     default:
    355 
    356         Type = DT_FIELD_TYPE_INTEGER;
    357         break;
    358     }
    359 
    360     return (Type);
    361 }
    362 
    363 
    364 /******************************************************************************
    365  *
    366  * FUNCTION:    DtGetBufferLength
    367  *
    368  * PARAMETERS:  Buffer              - List of integers,
    369  *                                    for example "10 3A 4F 2E"
    370  *
    371  * RETURN:      Count of integer
    372  *
    373  * DESCRIPTION: Get length of bytes needed to store the integers
    374  *
    375  *****************************************************************************/
    376 
    377 UINT32
    378 DtGetBufferLength (
    379     char                    *Buffer)
    380 {
    381     UINT32                  ByteLength = 0;
    382 
    383 
    384     while (*Buffer)
    385     {
    386         if (*Buffer == ' ')
    387         {
    388             ByteLength++;
    389 
    390             while (*Buffer == ' ')
    391             {
    392                 Buffer++;
    393             }
    394         }
    395 
    396         Buffer++;
    397     }
    398 
    399     return (++ByteLength);
    400 }
    401 
    402 
    403 /******************************************************************************
    404  *
    405  * FUNCTION:    DtGetFieldLength
    406  *
    407  * PARAMETERS:  Field               - Current field
    408  *              Info                - Data table info
    409  *
    410  * RETURN:      Field length
    411  *
    412  * DESCRIPTION: Get length of bytes needed to compile the field
    413  *
    414  * Note: This function must remain in sync with AcpiDmDumpTable.
    415  *
    416  *****************************************************************************/
    417 
    418 UINT32
    419 DtGetFieldLength (
    420     DT_FIELD                *Field,
    421     ACPI_DMTABLE_INFO       *Info)
    422 {
    423     UINT32                  ByteLength = 0;
    424     char                    *Value;
    425 
    426 
    427     /* Length is based upon the opcode for this field in the info table */
    428 
    429     switch (Info->Opcode)
    430     {
    431     case ACPI_DMT_FLAG0:
    432     case ACPI_DMT_FLAG1:
    433     case ACPI_DMT_FLAG2:
    434     case ACPI_DMT_FLAG3:
    435     case ACPI_DMT_FLAG4:
    436     case ACPI_DMT_FLAG5:
    437     case ACPI_DMT_FLAG6:
    438     case ACPI_DMT_FLAG7:
    439     case ACPI_DMT_FLAGS0:
    440     case ACPI_DMT_FLAGS1:
    441     case ACPI_DMT_FLAGS2:
    442     case ACPI_DMT_FLAGS4:
    443     case ACPI_DMT_FLAGS4_0:
    444     case ACPI_DMT_FLAGS4_4:
    445     case ACPI_DMT_FLAGS4_8:
    446     case ACPI_DMT_FLAGS4_12:
    447     case ACPI_DMT_FLAGS16_16:
    448     case ACPI_DMT_LABEL:
    449     case ACPI_DMT_EXTRA_TEXT:
    450 
    451         ByteLength = 0;
    452         break;
    453 
    454     case ACPI_DMT_UINT8:
    455     case ACPI_DMT_CHKSUM:
    456     case ACPI_DMT_SPACEID:
    457     case ACPI_DMT_ACCWIDTH:
    458     case ACPI_DMT_IVRS:
    459     case ACPI_DMT_GTDT:
    460     case ACPI_DMT_MADT:
    461     case ACPI_DMT_PCCT:
    462     case ACPI_DMT_PMTT:
    463     case ACPI_DMT_PPTT:
    464     case ACPI_DMT_SDEV:
    465     case ACPI_DMT_SRAT:
    466     case ACPI_DMT_ASF:
    467     case ACPI_DMT_HESTNTYP:
    468     case ACPI_DMT_FADTPM:
    469     case ACPI_DMT_EINJACT:
    470     case ACPI_DMT_EINJINST:
    471     case ACPI_DMT_ERSTACT:
    472     case ACPI_DMT_ERSTINST:
    473     case ACPI_DMT_DMAR_SCOPE:
    474 
    475         ByteLength = 1;
    476         break;
    477 
    478     case ACPI_DMT_UINT16:
    479     case ACPI_DMT_DMAR:
    480     case ACPI_DMT_HEST:
    481     case ACPI_DMT_HMAT:
    482     case ACPI_DMT_NFIT:
    483     case ACPI_DMT_PCI_PATH:
    484 
    485         ByteLength = 2;
    486         break;
    487 
    488     case ACPI_DMT_UINT24:
    489 
    490         ByteLength = 3;
    491         break;
    492 
    493     case ACPI_DMT_UINT32:
    494     case ACPI_DMT_NAME4:
    495     case ACPI_DMT_SIG:
    496     case ACPI_DMT_LPIT:
    497     case ACPI_DMT_TPM2:
    498 
    499         ByteLength = 4;
    500         break;
    501 
    502     case ACPI_DMT_UINT40:
    503 
    504         ByteLength = 5;
    505         break;
    506 
    507     case ACPI_DMT_UINT48:
    508     case ACPI_DMT_NAME6:
    509 
    510         ByteLength = 6;
    511         break;
    512 
    513     case ACPI_DMT_UINT56:
    514     case ACPI_DMT_BUF7:
    515 
    516         ByteLength = 7;
    517         break;
    518 
    519     case ACPI_DMT_UINT64:
    520     case ACPI_DMT_NAME8:
    521 
    522         ByteLength = 8;
    523         break;
    524 
    525     case ACPI_DMT_STRING:
    526 
    527         Value = DtGetFieldValue (Field);
    528         if (Value)
    529         {
    530             ByteLength = strlen (Value) + 1;
    531         }
    532         else
    533         {   /* At this point, this is a fatal error */
    534 
    535             snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Expected \"%s\"", Info->Name);
    536             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, AslGbl_MsgBuffer);
    537             return (0);
    538         }
    539         break;
    540 
    541     case ACPI_DMT_GAS:
    542 
    543         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
    544         break;
    545 
    546     case ACPI_DMT_HESTNTFY:
    547 
    548         ByteLength = sizeof (ACPI_HEST_NOTIFY);
    549         break;
    550 
    551     case ACPI_DMT_IORTMEM:
    552 
    553         ByteLength = sizeof (ACPI_IORT_MEMORY_ACCESS);
    554         break;
    555 
    556     case ACPI_DMT_BUFFER:
    557     case ACPI_DMT_RAW_BUFFER:
    558 
    559         Value = DtGetFieldValue (Field);
    560         if (Value)
    561         {
    562             ByteLength = DtGetBufferLength (Value);
    563         }
    564         else
    565         {   /* At this point, this is a fatal error */
    566 
    567             snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Expected \"%s\"", Info->Name);
    568             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, AslGbl_MsgBuffer);
    569             return (0);
    570         }
    571         break;
    572 
    573     case ACPI_DMT_BUF10:
    574 
    575         ByteLength = 10;
    576         break;
    577 
    578     case ACPI_DMT_BUF12:
    579 
    580         ByteLength = 12;
    581         break;
    582 
    583     case ACPI_DMT_BUF16:
    584     case ACPI_DMT_UUID:
    585 
    586         ByteLength = 16;
    587         break;
    588 
    589     case ACPI_DMT_BUF128:
    590 
    591         ByteLength = 128;
    592         break;
    593 
    594     case ACPI_DMT_UNICODE:
    595 
    596         Value = DtGetFieldValue (Field);
    597 
    598         /* TBD: error if Value is NULL? (as below?) */
    599 
    600         ByteLength = (strlen (Value) + 1) * sizeof(UINT16);
    601         break;
    602 
    603     default:
    604 
    605         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
    606         return (0);
    607     }
    608 
    609     return (ByteLength);
    610 }
    611 
    612 
    613 /******************************************************************************
    614  *
    615  * FUNCTION:    DtSum
    616  *
    617  * PARAMETERS:  DT_WALK_CALLBACK:
    618  *              Subtable            - Subtable
    619  *              Context             - Unused
    620  *              ReturnValue         - Store the checksum of subtable
    621  *
    622  * RETURN:      Status
    623  *
    624  * DESCRIPTION: Get the checksum of subtable
    625  *
    626  *****************************************************************************/
    627 
    628 static void
    629 DtSum (
    630     DT_SUBTABLE             *Subtable,
    631     void                    *Context,
    632     void                    *ReturnValue)
    633 {
    634     UINT8                   Checksum;
    635     UINT8                   *Sum = ReturnValue;
    636 
    637 
    638     Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
    639     *Sum = (UINT8) (*Sum + Checksum);
    640 }
    641 
    642 
    643 /******************************************************************************
    644  *
    645  * FUNCTION:    DtSetTableChecksum
    646  *
    647  * PARAMETERS:  ChecksumPointer     - Where to return the checksum
    648  *
    649  * RETURN:      None
    650  *
    651  * DESCRIPTION: Set checksum of the whole data table into the checksum field
    652  *
    653  *****************************************************************************/
    654 
    655 void
    656 DtSetTableChecksum (
    657     UINT8                   *ChecksumPointer)
    658 {
    659     UINT8                   Checksum = 0;
    660     UINT8                   OldSum;
    661 
    662 
    663     DtWalkTableTree (AslGbl_RootTable, DtSum, NULL, &Checksum);
    664 
    665     OldSum = *ChecksumPointer;
    666     Checksum = (UINT8) (Checksum - OldSum);
    667 
    668     /* Compute the final checksum */
    669 
    670     Checksum = (UINT8) (0 - Checksum);
    671     *ChecksumPointer = Checksum;
    672 }
    673 
    674 
    675 /******************************************************************************
    676  *
    677  * FUNCTION:    DtSetTableLength
    678  *
    679  * PARAMETERS:  None
    680  *
    681  * RETURN:      None
    682  *
    683  * DESCRIPTION: Walk the subtables and set all the length fields
    684  *
    685  *****************************************************************************/
    686 
    687 void
    688 DtSetTableLength (
    689     void)
    690 {
    691     DT_SUBTABLE             *ParentTable;
    692     DT_SUBTABLE             *ChildTable;
    693 
    694 
    695     ParentTable = AslGbl_RootTable;
    696     ChildTable = NULL;
    697 
    698     if (!ParentTable)
    699     {
    700         return;
    701     }
    702 
    703     DtSetSubtableLength (ParentTable);
    704 
    705     while (1)
    706     {
    707         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    708         if (ChildTable)
    709         {
    710             if (ChildTable->LengthField)
    711             {
    712                 DtSetSubtableLength (ChildTable);
    713             }
    714 
    715             if (ChildTable->Child)
    716             {
    717                 ParentTable = ChildTable;
    718                 ChildTable = NULL;
    719             }
    720             else
    721             {
    722                 ParentTable->TotalLength += ChildTable->TotalLength;
    723                 if (ParentTable->LengthField)
    724                 {
    725                     DtSetSubtableLength (ParentTable);
    726                 }
    727             }
    728         }
    729         else
    730         {
    731             ChildTable = ParentTable;
    732 
    733             if (ChildTable == AslGbl_RootTable)
    734             {
    735                 break;
    736             }
    737 
    738             ParentTable = DtGetParentSubtable (ParentTable);
    739 
    740             ParentTable->TotalLength += ChildTable->TotalLength;
    741             if (ParentTable->LengthField)
    742             {
    743                 DtSetSubtableLength (ParentTable);
    744             }
    745         }
    746     }
    747 }
    748 
    749 
    750 /******************************************************************************
    751  *
    752  * FUNCTION:    DtWalkTableTree
    753  *
    754  * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
    755  *              UserFunction        - Called during the walk
    756  *              Context             - Passed to user function
    757  *              ReturnValue         - The return value of UserFunction
    758  *
    759  * RETURN:      None
    760  *
    761  * DESCRIPTION: Performs a depth-first walk of the subtable tree
    762  *
    763  *****************************************************************************/
    764 
    765 void
    766 DtWalkTableTree (
    767     DT_SUBTABLE             *StartTable,
    768     DT_WALK_CALLBACK        UserFunction,
    769     void                    *Context,
    770     void                    *ReturnValue)
    771 {
    772     DT_SUBTABLE             *ParentTable;
    773     DT_SUBTABLE             *ChildTable;
    774 
    775 
    776     ParentTable = StartTable;
    777     ChildTable = NULL;
    778 
    779     if (!ParentTable)
    780     {
    781         return;
    782     }
    783 
    784     UserFunction (ParentTable, Context, ReturnValue);
    785 
    786     while (1)
    787     {
    788         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    789         if (ChildTable)
    790         {
    791             UserFunction (ChildTable, Context, ReturnValue);
    792 
    793             if (ChildTable->Child)
    794             {
    795                 ParentTable = ChildTable;
    796                 ChildTable = NULL;
    797             }
    798         }
    799         else
    800         {
    801             ChildTable = ParentTable;
    802             if (ChildTable == AslGbl_RootTable)
    803             {
    804                 break;
    805             }
    806 
    807             ParentTable = DtGetParentSubtable (ParentTable);
    808 
    809             if (ChildTable->Peer == StartTable)
    810             {
    811                 break;
    812             }
    813         }
    814     }
    815 }
    816