xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/dtcompile.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: dtcompile.c - Front-end for data table compiler
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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);
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);
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  *
428  * RETURN:      Status
429  *
430  * DESCRIPTION: Compile a subtable
431  *
432  *****************************************************************************/
433 
434 ACPI_STATUS
435 DtCompileTable (
436     DT_FIELD                **Field,
437     ACPI_DMTABLE_INFO       *Info,
438     DT_SUBTABLE             **RetSubtable)
439 {
440     DT_FIELD                *LocalField;
441     UINT32                  Length;
442     DT_SUBTABLE             *Subtable;
443     DT_SUBTABLE             *InlineSubtable = NULL;
444     UINT32                  FieldLength = 0;
445     UINT8                   FieldType;
446     UINT8                   *Buffer;
447     UINT8                   *FlagBuffer = NULL;
448     char                    *String;
449     UINT32                  CurrentFlagByteOffset = 0;
450     ACPI_STATUS             Status = AE_OK;
451 
452 
453     if (!Field)
454     {
455         return (AE_BAD_PARAMETER);
456     }
457     if (!*Field)
458     {
459         /*
460          * The field list is empty, this means that we are out of fields to
461          * parse. In other words, we are at the end of the table.
462          */
463         return (AE_END_OF_TABLE);
464     }
465 
466     /* Ignore optional subtable if name does not match */
467 
468     if ((Info->Flags & DT_OPTIONAL) &&
469         strcmp ((*Field)->Name, Info->Name))
470     {
471         *RetSubtable = NULL;
472         return (AE_OK);
473     }
474 
475     Length = DtGetSubtableLength (*Field, Info);
476     if (Length == ASL_EOF)
477     {
478         return (AE_ERROR);
479     }
480 
481     Subtable = UtSubtableCacheCalloc ();
482 
483     if (Length > 0)
484     {
485         String = UtLocalCacheCalloc (Length);
486         Subtable->Buffer = ACPI_CAST_PTR (UINT8, String);
487     }
488 
489     Subtable->Length = Length;
490     Subtable->TotalLength = Length;
491     Buffer = Subtable->Buffer;
492 
493     LocalField = *Field;
494     Subtable->Name = LocalField->Name;
495 
496     /*
497      * Main loop walks the info table for this ACPI table or subtable
498      */
499     for (; Info->Name; Info++)
500     {
501         if (Info->Opcode == ACPI_DMT_EXTRA_TEXT)
502         {
503             continue;
504         }
505 
506         if (!LocalField)
507         {
508             snprintf (MsgBuffer, sizeof(MsgBuffer), "Found NULL field - Field name \"%s\" needed",
509                 Info->Name);
510             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
511             Status = AE_BAD_DATA;
512             goto Error;
513         }
514 
515         /* Maintain table offsets */
516 
517         LocalField->TableOffset = Gbl_CurrentTableOffset;
518         FieldLength = DtGetFieldLength (LocalField, Info);
519         Gbl_CurrentTableOffset += FieldLength;
520 
521         FieldType = DtGetFieldType (Info);
522         Gbl_InputFieldCount++;
523 
524         switch (FieldType)
525         {
526         case DT_FIELD_TYPE_FLAGS_INTEGER:
527             /*
528              * Start of the definition of a flags field.
529              * This master flags integer starts at value zero, in preparation
530              * to compile and insert the flag fields from the individual bits
531              */
532             LocalField = LocalField->Next;
533             *Field = LocalField;
534 
535             FlagBuffer = Buffer;
536             CurrentFlagByteOffset = Info->Offset;
537             break;
538 
539         case DT_FIELD_TYPE_FLAG:
540 
541             /* Individual Flag field, can be multiple bits */
542 
543             if (FlagBuffer)
544             {
545                 /*
546                  * We must increment the FlagBuffer when we have crossed
547                  * into the next flags byte within the flags field
548                  * of type DT_FIELD_TYPE_FLAGS_INTEGER.
549                  */
550                 FlagBuffer += (Info->Offset - CurrentFlagByteOffset);
551                 CurrentFlagByteOffset = Info->Offset;
552 
553                 DtCompileFlag (FlagBuffer, LocalField, Info);
554             }
555             else
556             {
557                 /* TBD - this is an internal error */
558             }
559 
560             LocalField = LocalField->Next;
561             *Field = LocalField;
562             break;
563 
564         case DT_FIELD_TYPE_INLINE_SUBTABLE:
565             /*
566              * Recursion (one level max): compile GAS (Generic Address)
567              * or Notify in-line subtable
568              */
569             *Field = LocalField;
570 
571             switch (Info->Opcode)
572             {
573             case ACPI_DMT_GAS:
574 
575                 Status = DtCompileTable (Field, AcpiDmTableInfoGas,
576                     &InlineSubtable);
577                 break;
578 
579             case ACPI_DMT_HESTNTFY:
580 
581                 Status = DtCompileTable (Field, AcpiDmTableInfoHestNotify,
582                     &InlineSubtable);
583                 break;
584 
585             case ACPI_DMT_IORTMEM:
586 
587                 Status = DtCompileTable (Field, AcpiDmTableInfoIortAcc,
588                     &InlineSubtable);
589                 break;
590 
591             default:
592                 sprintf (MsgBuffer, "Invalid DMT opcode: 0x%.2X",
593                     Info->Opcode);
594                 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
595                 Status = AE_BAD_DATA;
596                 break;
597             }
598 
599             if (ACPI_FAILURE (Status))
600             {
601                 goto Error;
602             }
603 
604             DtSetSubtableLength (InlineSubtable);
605 
606             memcpy (Buffer, InlineSubtable->Buffer, FieldLength);
607             LocalField = *Field;
608             break;
609 
610         case DT_FIELD_TYPE_LABEL:
611 
612             DtWriteFieldToListing (Buffer, LocalField, 0);
613             LocalField = LocalField->Next;
614             break;
615 
616         default:
617 
618             /* Normal case for most field types (Integer, String, etc.) */
619 
620             DtCompileOneField (Buffer, LocalField,
621                 FieldLength, FieldType, Info->Flags);
622 
623             DtWriteFieldToListing (Buffer, LocalField, FieldLength);
624             LocalField = LocalField->Next;
625 
626             if (Info->Flags & DT_LENGTH)
627             {
628                 /* Field is an Integer that will contain a subtable length */
629 
630                 Subtable->LengthField = Buffer;
631                 Subtable->SizeOfLengthField = FieldLength;
632             }
633             break;
634         }
635 
636         Buffer += FieldLength;
637     }
638 
639     *Field = LocalField;
640     *RetSubtable = Subtable;
641     return (AE_OK);
642 
643 Error:
644     ACPI_FREE (Subtable->Buffer);
645     ACPI_FREE (Subtable);
646     return (Status);
647 }
648 
649 
650 /******************************************************************************
651  *
652  * FUNCTION:    DtCompileTwoSubtables
653  *
654  * PARAMETERS:  List                - Current field list pointer
655  *              TableInfo1          - Info table 1
656  *              TableInfo1          - Info table 2
657  *
658  * RETURN:      Status
659  *
660  * DESCRIPTION: Compile tables with a header and one or more same subtables.
661  *              Include CPEP, EINJ, ERST, MCFG, MSCT, WDAT
662  *
663  *****************************************************************************/
664 
665 ACPI_STATUS
666 DtCompileTwoSubtables (
667     void                    **List,
668     ACPI_DMTABLE_INFO       *TableInfo1,
669     ACPI_DMTABLE_INFO       *TableInfo2)
670 {
671     ACPI_STATUS             Status;
672     DT_SUBTABLE             *Subtable;
673     DT_SUBTABLE             *ParentTable;
674     DT_FIELD                **PFieldList = (DT_FIELD **) List;
675 
676 
677     Status = DtCompileTable (PFieldList, TableInfo1, &Subtable);
678     if (ACPI_FAILURE (Status))
679     {
680         return (Status);
681     }
682 
683     ParentTable = DtPeekSubtable ();
684     DtInsertSubtable (ParentTable, Subtable);
685 
686     while (*PFieldList)
687     {
688         Status = DtCompileTable (PFieldList, TableInfo2, &Subtable);
689         if (ACPI_FAILURE (Status))
690         {
691             return (Status);
692         }
693 
694         DtInsertSubtable (ParentTable, Subtable);
695     }
696 
697     return (AE_OK);
698 }
699 
700 
701 /******************************************************************************
702  *
703  * FUNCTION:    DtCompilePadding
704  *
705  * PARAMETERS:  Length              - Padding field size
706  *              RetSubtable         - Compile result of table
707  *
708  * RETURN:      Status
709  *
710  * DESCRIPTION: Compile a subtable for padding purpose
711  *
712  *****************************************************************************/
713 
714 ACPI_STATUS
715 DtCompilePadding (
716     UINT32                  Length,
717     DT_SUBTABLE             **RetSubtable)
718 {
719     DT_SUBTABLE             *Subtable;
720     /* UINT8                   *Buffer; */
721     char                    *String;
722 
723 
724     Subtable = UtSubtableCacheCalloc ();
725 
726     if (Length > 0)
727     {
728         String = UtLocalCacheCalloc (Length);
729         Subtable->Buffer = ACPI_CAST_PTR (UINT8, String);
730     }
731 
732     Subtable->Length = Length;
733     Subtable->TotalLength = Length;
734     /* Buffer = Subtable->Buffer; */
735 
736     *RetSubtable = Subtable;
737     return (AE_OK);
738 }
739