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