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