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