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