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