1/******************************************************************************
2 *
3 * Module Name: dtsubtable.c - handling of subtables within ACPI tables
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
46#define _COMPONENT          DT_COMPILER
47        ACPI_MODULE_NAME    ("dtsubtable")
48
49
50/******************************************************************************
51 *
52 * FUNCTION:    DtCreateSubtable
53 *
54 * PARAMETERS:  Buffer              - Input buffer
55 *              Length              - Buffer length
56 *              RetSubtable         - Returned newly created subtable
57 *
58 * RETURN:      None
59 *
60 * DESCRIPTION: Create a subtable that is not listed with ACPI_DMTABLE_INFO
61 *              For example, FACS has 24 bytes reserved at the end
62 *              and it's not listed at AcpiDmTableInfoFacs
63 *
64 *****************************************************************************/
65
66void
67DtCreateSubtable (
68    UINT8                   *Buffer,
69    UINT32                  Length,
70    DT_SUBTABLE             **RetSubtable)
71{
72    DT_SUBTABLE             *Subtable;
73    char                    *String;
74
75
76    Subtable = UtSubtableCacheCalloc ();
77
78    /* Create a new buffer for the subtable data */
79
80    String = UtLocalCacheCalloc (Length);
81    Subtable->Buffer = ACPI_CAST_PTR (UINT8, String);
82    memcpy (Subtable->Buffer, Buffer, Length);
83
84    Subtable->Length = Length;
85    Subtable->TotalLength = Length;
86
87    *RetSubtable = Subtable;
88}
89
90
91/******************************************************************************
92 *
93 * FUNCTION:    DtInsertSubtable
94 *
95 * PARAMETERS:  ParentTable         - The Parent of the new subtable
96 *              Subtable            - The new subtable to insert
97 *
98 * RETURN:      None
99 *
100 * DESCRIPTION: Insert the new subtable to the parent table
101 *
102 *****************************************************************************/
103
104void
105DtInsertSubtable (
106    DT_SUBTABLE             *ParentTable,
107    DT_SUBTABLE             *Subtable)
108{
109    DT_SUBTABLE             *ChildTable;
110
111
112    Subtable->Peer = NULL;
113    Subtable->Parent = ParentTable;
114    Subtable->Depth = ParentTable->Depth + 1;
115
116    /* Link the new entry into the child list */
117
118    if (!ParentTable->Child)
119    {
120        ParentTable->Child = Subtable;
121    }
122    else
123    {
124        /* Walk to the end of the child list */
125
126        ChildTable = ParentTable->Child;
127        while (ChildTable->Peer)
128        {
129            ChildTable = ChildTable->Peer;
130        }
131
132        /* Add new subtable at the end of the child list */
133
134        ChildTable->Peer = Subtable;
135    }
136}
137
138
139/******************************************************************************
140 *
141 * FUNCTION:    DtPushSubtable
142 *
143 * PARAMETERS:  Subtable            - Subtable to push
144 *
145 * RETURN:      None
146 *
147 * DESCRIPTION: Push a subtable onto a subtable stack
148 *
149 *****************************************************************************/
150
151void
152DtPushSubtable (
153    DT_SUBTABLE             *Subtable)
154{
155
156    Subtable->StackTop = AslGbl_SubtableStack;
157    AslGbl_SubtableStack = Subtable;
158}
159
160
161/******************************************************************************
162 *
163 * FUNCTION:    DtPopSubtable
164 *
165 * PARAMETERS:  None
166 *
167 * RETURN:      None
168 *
169 * DESCRIPTION: Pop a subtable from a subtable stack. Uses global SubtableStack
170 *
171 *****************************************************************************/
172
173void
174DtPopSubtable (
175    void)
176{
177    DT_SUBTABLE             *Subtable;
178
179
180    Subtable = AslGbl_SubtableStack;
181
182    if (Subtable)
183    {
184        AslGbl_SubtableStack = Subtable->StackTop;
185    }
186}
187
188
189/******************************************************************************
190 *
191 * FUNCTION:    DtPeekSubtable
192 *
193 * PARAMETERS:  None
194 *
195 * RETURN:      The subtable on top of stack
196 *
197 * DESCRIPTION: Get the subtable on top of stack
198 *
199 *****************************************************************************/
200
201DT_SUBTABLE *
202DtPeekSubtable (
203    void)
204{
205
206    return (AslGbl_SubtableStack);
207}
208
209
210/******************************************************************************
211 *
212 * FUNCTION:    DtGetNextSubtable
213 *
214 * PARAMETERS:  ParentTable         - Parent table whose children we are
215 *                                    getting
216 *              ChildTable          - Previous child that was found.
217 *                                    The NEXT child will be returned
218 *
219 * RETURN:      Pointer to the NEXT child or NULL if none is found.
220 *
221 * DESCRIPTION: Return the next peer subtable within the tree.
222 *
223 *****************************************************************************/
224
225DT_SUBTABLE *
226DtGetNextSubtable (
227    DT_SUBTABLE             *ParentTable,
228    DT_SUBTABLE             *ChildTable)
229{
230    ACPI_FUNCTION_ENTRY ();
231
232
233    if (!ChildTable)
234    {
235        /* It's really the parent's _scope_ that we want */
236
237        return (ParentTable->Child);
238    }
239
240    /* Otherwise just return the next peer (NULL if at end-of-list) */
241
242    return (ChildTable->Peer);
243}
244
245
246/******************************************************************************
247 *
248 * FUNCTION:    DtGetParentSubtable
249 *
250 * PARAMETERS:  Subtable            - Current subtable
251 *
252 * RETURN:      Parent of the given subtable
253 *
254 * DESCRIPTION: Get the parent of the given subtable in the tree
255 *
256 *****************************************************************************/
257
258DT_SUBTABLE *
259DtGetParentSubtable (
260    DT_SUBTABLE             *Subtable)
261{
262
263    if (!Subtable)
264    {
265        return (NULL);
266    }
267
268    return (Subtable->Parent);
269}
270
271
272/******************************************************************************
273 *
274 * FUNCTION:    DtGetSubtableLength
275 *
276 * PARAMETERS:  Field               - Current field list pointer
277 *              Info                - Data table info
278 *
279 * RETURN:      Subtable length
280 *
281 * DESCRIPTION: Get length of bytes needed to compile the subtable
282 *
283 *****************************************************************************/
284
285UINT32
286DtGetSubtableLength (
287    DT_FIELD                *Field,
288    ACPI_DMTABLE_INFO       *Info)
289{
290    UINT32                  ByteLength = 0;
291    UINT8                   Step;
292    UINT8                   i;
293
294
295    /* Walk entire Info table; Null name terminates */
296
297    for (; Info->Name; Info++)
298    {
299        if (Info->Opcode == ACPI_DMT_EXTRA_TEXT)
300        {
301            continue;
302        }
303
304        if (!Field)
305        {
306            goto Error;
307        }
308
309        ByteLength += DtGetFieldLength (Field, Info);
310
311        switch (Info->Opcode)
312        {
313        case ACPI_DMT_GAS:
314
315            Step = 5;
316            break;
317
318        case ACPI_DMT_HESTNTFY:
319
320            Step = 9;
321            break;
322
323        case ACPI_DMT_IORTMEM:
324
325            Step = 10;
326            break;
327
328        default:
329
330            Step = 1;
331            break;
332        }
333
334        for (i = 0; i < Step; i++)
335        {
336            if (!Field)
337            {
338                goto Error;
339            }
340
341            Field = Field->Next;
342        }
343    }
344
345    return (ByteLength);
346
347Error:
348    if (!Field)
349    {
350        snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "Found NULL field - Field name \"%s\" needed",
351            Info->Name);
352        DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, AslGbl_MsgBuffer);
353    }
354
355    return (ASL_EOF);
356}
357
358
359/******************************************************************************
360 *
361 * FUNCTION:    DtSetSubtableLength
362 *
363 * PARAMETERS:  Subtable            - Subtable
364 *
365 * RETURN:      None
366 *
367 * DESCRIPTION: Set length of the subtable into its length field
368 *
369 *****************************************************************************/
370
371void
372DtSetSubtableLength (
373    DT_SUBTABLE             *Subtable)
374{
375
376    if (!Subtable->LengthField)
377    {
378        return;
379    }
380
381    memcpy (Subtable->LengthField, &Subtable->TotalLength,
382        Subtable->SizeOfLengthField);
383}
384