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