xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/dtcompile.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /******************************************************************************
2  *
3  * Module Name: dtcompile.c - Front-end for data table compiler
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, 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 #define __DTCOMPILE_C__
45 #define _DECLARE_DT_GLOBALS
46 
47 #include "aslcompiler.h"
48 #include "dtcompiler.h"
49 
50 #define _COMPONENT          DT_COMPILER
51         ACPI_MODULE_NAME    ("dtcompile")
52 
53 static char                 VersionString[9];
54 
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 DtInitialize (
60     void);
61 
62 static ACPI_STATUS
63 DtCompileDataTable (
64     DT_FIELD                **Field);
65 
66 static void
67 DtInsertCompilerIds (
68     DT_FIELD                *FieldList);
69 
70 
71 /******************************************************************************
72  *
73  * FUNCTION:    DtDoCompile
74  *
75  * PARAMETERS:  None
76  *
77  * RETURN:      Status
78  *
79  * DESCRIPTION: Main entry point for the data table compiler.
80  *
81  * Note: Assumes Gbl_Files[ASL_FILE_INPUT] is initialized and the file is
82  *          open at seek offset zero.
83  *
84  *****************************************************************************/
85 
86 ACPI_STATUS
87 DtDoCompile (
88     void)
89 {
90     ACPI_STATUS             Status;
91     UINT8                   Event;
92     DT_FIELD                *FieldList;
93 
94 
95     /* Initialize globals */
96 
97     Status = DtInitialize ();
98     if (ACPI_FAILURE (Status))
99     {
100         printf ("Error during compiler initialization, 0x%X\n", Status);
101         return (Status);
102     }
103 
104     /* Preprocessor */
105 
106     Event = UtBeginEvent ("Preprocess input file");
107     PrDoPreprocess ();
108     UtEndEvent (Event);
109 
110     if (Gbl_PreprocessOnly)
111     {
112         return (AE_OK);
113     }
114 
115     /*
116      * Scan the input file (file is already open) and
117      * build the parse tree
118      */
119     Event = UtBeginEvent ("Scan and parse input file");
120     FieldList = DtScanFile (Gbl_Files[ASL_FILE_INPUT].Handle);
121     UtEndEvent (Event);
122 
123     /* Did the parse tree get successfully constructed? */
124 
125     if (!FieldList)
126     {
127         /* TBD: temporary error message. Msgs should come from function above */
128 
129         DtError (ASL_ERROR, ASL_MSG_SYNTAX, NULL,
130             "Input file does not appear to be an ASL or data table source file");
131 
132         Status = AE_ERROR;
133         goto CleanupAndExit;
134     }
135 
136     Event = UtBeginEvent ("Compile parse tree");
137 
138     /*
139      * Compile the parse tree
140      */
141     Status = DtCompileDataTable (&FieldList);
142     UtEndEvent (Event);
143 
144     DtFreeFieldList ();
145 
146     if (ACPI_FAILURE (Status))
147     {
148         /* TBD: temporary error message. Msgs should come from function above */
149 
150         DtError (ASL_ERROR, ASL_MSG_SYNTAX, NULL,
151             "Could not compile input file");
152 
153         goto CleanupAndExit;
154     }
155 
156     /* Create/open the binary output file */
157 
158     Gbl_Files[ASL_FILE_AML_OUTPUT].Filename = NULL;
159     Status = FlOpenAmlOutputFile (Gbl_OutputFilenamePrefix);
160     if (ACPI_FAILURE (Status))
161     {
162         goto CleanupAndExit;
163     }
164 
165     /* Write the binary, then the optional hex file */
166 
167     DtOutputBinary (Gbl_RootTable);
168     HxDoHexOutput ();
169     DtWriteTableToListing ();
170 
171 CleanupAndExit:
172 
173     CmCleanupAndExit ();
174     return (Status);
175 }
176 
177 
178 /******************************************************************************
179  *
180  * FUNCTION:    DtInitialize
181  *
182  * PARAMETERS:  None
183  *
184  * RETURN:      Status
185  *
186  * DESCRIPTION: Initialize data table compiler globals. Enables multiple
187  *              compiles per invocation.
188  *
189  *****************************************************************************/
190 
191 static ACPI_STATUS
192 DtInitialize (
193     void)
194 {
195     ACPI_STATUS             Status;
196 
197 
198     Status = AcpiOsInitialize ();
199     if (ACPI_FAILURE (Status))
200     {
201         return (Status);
202     }
203 
204     Status = AcpiUtInitGlobals ();
205     if (ACPI_FAILURE (Status))
206     {
207         return (Status);
208     }
209 
210     Gbl_FieldList = NULL;
211     Gbl_RootTable = NULL;
212     Gbl_SubtableStack = NULL;
213 
214     snprintf (VersionString, sizeof(VersionString), "%X",
215 	(UINT32) ACPI_CA_VERSION);
216     return (AE_OK);
217 }
218 
219 
220 /******************************************************************************
221  *
222  * FUNCTION:    DtInsertCompilerIds
223  *
224  * PARAMETERS:  FieldList           - Current field list pointer
225  *
226  * RETURN:      None
227  *
228  * DESCRIPTION: Insert the IDs (Name, Version) of the current compiler into
229  *              the original ACPI table header.
230  *
231  *****************************************************************************/
232 
233 static void
234 DtInsertCompilerIds (
235     DT_FIELD                *FieldList)
236 {
237     DT_FIELD                *Next;
238     UINT32                  i;
239 
240 
241     /*
242      * Don't insert current compiler ID if requested. Used for compiler
243      * debug/validation only.
244      */
245     if (Gbl_UseOriginalCompilerId)
246     {
247         return;
248     }
249 
250     /* Walk to the Compiler fields at the end of the header */
251 
252     Next = FieldList;
253     for (i = 0; i < 7; i++)
254     {
255         Next = Next->Next;
256     }
257 
258     Next->Value = ASL_CREATOR_ID;
259     Next->Flags = DT_FIELD_NOT_ALLOCATED;
260 
261     Next = Next->Next;
262     Next->Value = VersionString;
263     Next->Flags = DT_FIELD_NOT_ALLOCATED;
264 }
265 
266 
267 /******************************************************************************
268  *
269  * FUNCTION:    DtCompileDataTable
270  *
271  * PARAMETERS:  FieldList           - Current field list pointer
272  *
273  * RETURN:      Status
274  *
275  * DESCRIPTION: Entry point to compile one data table
276  *
277  *****************************************************************************/
278 
279 static ACPI_STATUS
280 DtCompileDataTable (
281     DT_FIELD                **FieldList)
282 {
283     ACPI_DMTABLE_DATA       *TableData;
284     DT_SUBTABLE             *Subtable;
285     char                    *Signature;
286     ACPI_TABLE_HEADER       *AcpiTableHeader;
287     ACPI_STATUS             Status;
288     DT_FIELD                *RootField = *FieldList;
289 
290 
291     /* Verify that we at least have a table signature and save it */
292 
293     Signature = DtGetFieldValue (*FieldList);
294     if (!Signature)
295     {
296         snprintf (MsgBuffer, sizeof(MsgBuffer), "Expected \"%s\"", "Signature");
297         DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME,
298             *FieldList, MsgBuffer);
299         return (AE_ERROR);
300     }
301 
302     Gbl_Signature = UtLocalCalloc (ACPI_STRLEN (Signature) + 1);
303     strcpy (Gbl_Signature, Signature);
304 
305     /*
306      * Handle tables that don't use the common ACPI table header structure.
307      * Currently, these are the FACS and RSDP. Also check for an OEMx table,
308      * these tables have user-defined contents.
309      */
310     if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS))
311     {
312         Status = DtCompileFacs (FieldList);
313         if (ACPI_FAILURE (Status))
314         {
315             return (Status);
316         }
317 
318         DtSetTableLength ();
319         return (Status);
320     }
321     else if (ACPI_VALIDATE_RSDP_SIG (Signature))
322     {
323         Status = DtCompileRsdp (FieldList);
324         return (Status);
325     }
326     else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_S3PT))
327     {
328         Status = DtCompileS3pt (FieldList);
329         if (ACPI_FAILURE (Status))
330         {
331             return (Status);
332         }
333 
334         DtSetTableLength ();
335         return (Status);
336     }
337 
338     /*
339      * All other tables must use the common ACPI table header. Insert the
340      * current iASL IDs (name, version), and compile the header now.
341      */
342     DtInsertCompilerIds (*FieldList);
343 
344     Status = DtCompileTable (FieldList, AcpiDmTableInfoHeader,
345                 &Gbl_RootTable, TRUE);
346     if (ACPI_FAILURE (Status))
347     {
348         return (Status);
349     }
350 
351     DtPushSubtable (Gbl_RootTable);
352 
353     /* Validate the signature via the ACPI table list */
354 
355     TableData = AcpiDmGetTableData (Signature);
356     if (!TableData || Gbl_CompileGeneric)
357     {
358         DtCompileGeneric ((void **) FieldList);
359         goto FinishHeader;
360     }
361 
362     /* Dispatch to per-table compile */
363 
364     if (TableData->CmTableHandler)
365     {
366         /* Complex table, has a handler */
367 
368         Status = TableData->CmTableHandler ((void **) FieldList);
369         if (ACPI_FAILURE (Status))
370         {
371             return (Status);
372         }
373     }
374     else if (TableData->TableInfo)
375     {
376         /* Simple table, just walk the info table */
377 
378         Subtable = NULL;
379         Status = DtCompileTable (FieldList, TableData->TableInfo,
380                     &Subtable, TRUE);
381         if (ACPI_FAILURE (Status))
382         {
383             return (Status);
384         }
385 
386         DtInsertSubtable (Gbl_RootTable, Subtable);
387         DtPopSubtable ();
388     }
389     else
390     {
391         DtFatal (ASL_MSG_COMPILER_INTERNAL, *FieldList,
392             "Missing table dispatch info");
393         return (AE_ERROR);
394     }
395 
396 FinishHeader:
397 
398     /* Set the final table length and then the checksum */
399 
400     DtSetTableLength ();
401     AcpiTableHeader = ACPI_CAST_PTR (
402         ACPI_TABLE_HEADER, Gbl_RootTable->Buffer);
403     DtSetTableChecksum (&AcpiTableHeader->Checksum);
404 
405     DtDumpFieldList (RootField);
406     DtDumpSubtableList ();
407     return (AE_OK);
408 }
409 
410 
411 /******************************************************************************
412  *
413  * FUNCTION:    DtCompileTable
414  *
415  * PARAMETERS:  Field               - Current field list pointer
416  *              Info                - Info table for this ACPI table
417  *              RetSubtable         - Compile result of table
418  *              Required            - If this subtable must exist
419  *
420  * RETURN:      Status
421  *
422  * DESCRIPTION: Compile a subtable
423  *
424  *****************************************************************************/
425 
426 ACPI_STATUS
427 DtCompileTable (
428     DT_FIELD                **Field,
429     ACPI_DMTABLE_INFO       *Info,
430     DT_SUBTABLE             **RetSubtable,
431     BOOLEAN                 Required)
432 {
433     DT_FIELD                *LocalField;
434     UINT32                  Length;
435     DT_SUBTABLE             *Subtable;
436     DT_SUBTABLE             *InlineSubtable;
437     UINT32                  FieldLength = 0;
438     UINT8                   FieldType;
439     UINT8                   *Buffer;
440     UINT8                   *FlagBuffer = NULL;
441     UINT32                  CurrentFlagByteOffset = 0;
442     ACPI_STATUS             Status;
443 
444 
445     if (!Field || !*Field)
446     {
447         return (AE_BAD_PARAMETER);
448     }
449 
450     /* Ignore optional subtable if name does not match */
451 
452     if ((Info->Flags & DT_OPTIONAL) &&
453         ACPI_STRCMP ((*Field)->Name, Info->Name))
454     {
455         *RetSubtable = NULL;
456         return (AE_OK);
457     }
458 
459     Length = DtGetSubtableLength (*Field, Info);
460     if (Length == ASL_EOF)
461     {
462         return (AE_ERROR);
463     }
464 
465     Subtable = UtLocalCalloc (sizeof (DT_SUBTABLE));
466 
467     if (Length > 0)
468     {
469         Subtable->Buffer = UtLocalCalloc (Length);
470     }
471     Subtable->Length = Length;
472     Subtable->TotalLength = Length;
473     Buffer = Subtable->Buffer;
474 
475     LocalField = *Field;
476 
477     /*
478      * Main loop walks the info table for this ACPI table or subtable
479      */
480     for (; Info->Name; Info++)
481     {
482         if (Info->Opcode == ACPI_DMT_EXTRA_TEXT)
483         {
484             continue;
485         }
486 
487         if (!LocalField)
488         {
489             snprintf (MsgBuffer, sizeof(MsgBuffer), "Found NULL field - Field name \"%s\" needed",
490                 Info->Name);
491             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
492             Status = AE_BAD_DATA;
493             goto Error;
494         }
495 
496         /* Maintain table offsets */
497 
498         LocalField->TableOffset = Gbl_CurrentTableOffset;
499         FieldLength = DtGetFieldLength (LocalField, Info);
500         Gbl_CurrentTableOffset += FieldLength;
501 
502         FieldType = DtGetFieldType (Info);
503         Gbl_InputFieldCount++;
504 
505         switch (FieldType)
506         {
507         case DT_FIELD_TYPE_FLAGS_INTEGER:
508             /*
509              * Start of the definition of a flags field.
510              * This master flags integer starts at value zero, in preparation
511              * to compile and insert the flag fields from the individual bits
512              */
513             LocalField = LocalField->Next;
514             *Field = LocalField;
515 
516             FlagBuffer = Buffer;
517             CurrentFlagByteOffset = Info->Offset;
518             break;
519 
520         case DT_FIELD_TYPE_FLAG:
521 
522             /* Individual Flag field, can be multiple bits */
523 
524             if (FlagBuffer)
525             {
526                 /*
527                  * We must increment the FlagBuffer when we have crossed
528                  * into the next flags byte within the flags field
529                  * of type DT_FIELD_TYPE_FLAGS_INTEGER.
530                  */
531                 FlagBuffer += (Info->Offset - CurrentFlagByteOffset);
532                 CurrentFlagByteOffset = Info->Offset;
533 
534                 DtCompileFlag (FlagBuffer, LocalField, Info);
535             }
536             else
537             {
538                 /* TBD - this is an internal error */
539             }
540 
541             LocalField = LocalField->Next;
542             *Field = LocalField;
543             break;
544 
545         case DT_FIELD_TYPE_INLINE_SUBTABLE:
546             /*
547              * Recursion (one level max): compile GAS (Generic Address)
548              * or Notify in-line subtable
549              */
550             *Field = LocalField;
551 
552             if (Info->Opcode == ACPI_DMT_GAS)
553             {
554                 Status = DtCompileTable (Field, AcpiDmTableInfoGas,
555                     &InlineSubtable, TRUE);
556             }
557             else
558             {
559                 Status = DtCompileTable (Field, AcpiDmTableInfoHestNotify,
560                     &InlineSubtable, TRUE);
561             }
562 
563             if (ACPI_FAILURE (Status))
564             {
565                 goto Error;
566             }
567 
568             DtSetSubtableLength (InlineSubtable);
569 
570             ACPI_MEMCPY (Buffer, InlineSubtable->Buffer, FieldLength);
571             ACPI_FREE (InlineSubtable->Buffer);
572             ACPI_FREE (InlineSubtable);
573             LocalField = *Field;
574             break;
575 
576         case DT_FIELD_TYPE_LABEL:
577 
578             DtWriteFieldToListing (Buffer, LocalField, 0);
579             LocalField = LocalField->Next;
580             break;
581 
582         default:
583 
584             /* Normal case for most field types (Integer, String, etc.) */
585 
586             DtCompileOneField (Buffer, LocalField,
587                 FieldLength, FieldType, Info->Flags);
588 
589             DtWriteFieldToListing (Buffer, LocalField, FieldLength);
590             LocalField = LocalField->Next;
591 
592             if (Info->Flags & DT_LENGTH)
593             {
594                 /* Field is an Integer that will contain a subtable length */
595 
596                 Subtable->LengthField = Buffer;
597                 Subtable->SizeOfLengthField = FieldLength;
598             }
599 
600             break;
601         }
602 
603         Buffer += FieldLength;
604     }
605 
606     *Field = LocalField;
607     *RetSubtable = Subtable;
608     return (AE_OK);
609 
610 Error:
611     ACPI_FREE (Subtable->Buffer);
612     ACPI_FREE (Subtable);
613     return (Status);
614 }
615