dtcompile.c revision 1.11 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