1 /****************************************************************************** 2 * 3 * Module Name: dtcompile.c - Front-end for data table compiler 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 snprintf (VersionString, sizeof(VersionString), "%X", 215 (UINT32) ACPI_CA_VERSION); 216 return (AE_OK); 217 } 218 219 220 /****************************************************************************** 221 * 222 * FUNCTION: DtInsertCompilerIds 223 * 224 * PARAMETERS: FieldList - Current field list pointer 225 * 226 * RETURN: None 227 * 228 * DESCRIPTION: Insert the IDs (Name, Version) of the current compiler into 229 * the original ACPI table header. 230 * 231 *****************************************************************************/ 232 233 static void 234 DtInsertCompilerIds ( 235 DT_FIELD *FieldList) 236 { 237 DT_FIELD *Next; 238 UINT32 i; 239 240 241 /* 242 * Don't insert current compiler ID if requested. Used for compiler 243 * debug/validation only. 244 */ 245 if (Gbl_UseOriginalCompilerId) 246 { 247 return; 248 } 249 250 /* Walk to the Compiler fields at the end of the header */ 251 252 Next = FieldList; 253 for (i = 0; i < 7; i++) 254 { 255 Next = Next->Next; 256 } 257 258 Next->Value = ASL_CREATOR_ID; 259 Next->Flags = DT_FIELD_NOT_ALLOCATED; 260 261 Next = Next->Next; 262 Next->Value = VersionString; 263 Next->Flags = DT_FIELD_NOT_ALLOCATED; 264 } 265 266 267 /****************************************************************************** 268 * 269 * FUNCTION: DtCompileDataTable 270 * 271 * PARAMETERS: FieldList - Current field list pointer 272 * 273 * RETURN: Status 274 * 275 * DESCRIPTION: Entry point to compile one data table 276 * 277 *****************************************************************************/ 278 279 static ACPI_STATUS 280 DtCompileDataTable ( 281 DT_FIELD **FieldList) 282 { 283 ACPI_DMTABLE_DATA *TableData; 284 DT_SUBTABLE *Subtable; 285 char *Signature; 286 ACPI_TABLE_HEADER *AcpiTableHeader; 287 ACPI_STATUS Status; 288 DT_FIELD *RootField = *FieldList; 289 290 291 /* Verify that we at least have a table signature and save it */ 292 293 Signature = DtGetFieldValue (*FieldList); 294 if (!Signature) 295 { 296 snprintf (MsgBuffer, sizeof(MsgBuffer), "Expected \"%s\"", "Signature"); 297 DtNameError (ASL_ERROR, ASL_MSG_INVALID_FIELD_NAME, 298 *FieldList, MsgBuffer); 299 return (AE_ERROR); 300 } 301 302 Gbl_Signature = UtLocalCalloc (ACPI_STRLEN (Signature) + 1); 303 strcpy (Gbl_Signature, Signature); 304 305 /* 306 * Handle tables that don't use the common ACPI table header structure. 307 * Currently, these are the FACS and RSDP. Also check for an OEMx table, 308 * these tables have user-defined contents. 309 */ 310 if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_FACS)) 311 { 312 Status = DtCompileFacs (FieldList); 313 if (ACPI_FAILURE (Status)) 314 { 315 return (Status); 316 } 317 318 DtSetTableLength (); 319 return (Status); 320 } 321 else if (ACPI_VALIDATE_RSDP_SIG (Signature)) 322 { 323 Status = DtCompileRsdp (FieldList); 324 return (Status); 325 } 326 else if (ACPI_COMPARE_NAME (Signature, ACPI_SIG_S3PT)) 327 { 328 Status = DtCompileS3pt (FieldList); 329 if (ACPI_FAILURE (Status)) 330 { 331 return (Status); 332 } 333 334 DtSetTableLength (); 335 return (Status); 336 } 337 338 /* 339 * All other tables must use the common ACPI table header. Insert the 340 * current iASL IDs (name, version), and compile the header now. 341 */ 342 DtInsertCompilerIds (*FieldList); 343 344 Status = DtCompileTable (FieldList, AcpiDmTableInfoHeader, 345 &Gbl_RootTable, TRUE); 346 if (ACPI_FAILURE (Status)) 347 { 348 return (Status); 349 } 350 351 DtPushSubtable (Gbl_RootTable); 352 353 /* Validate the signature via the ACPI table list */ 354 355 TableData = AcpiDmGetTableData (Signature); 356 if (!TableData || Gbl_CompileGeneric) 357 { 358 DtCompileGeneric ((void **) FieldList); 359 goto FinishHeader; 360 } 361 362 /* Dispatch to per-table compile */ 363 364 if (TableData->CmTableHandler) 365 { 366 /* Complex table, has a handler */ 367 368 Status = TableData->CmTableHandler ((void **) FieldList); 369 if (ACPI_FAILURE (Status)) 370 { 371 return (Status); 372 } 373 } 374 else if (TableData->TableInfo) 375 { 376 /* Simple table, just walk the info table */ 377 378 Subtable = NULL; 379 Status = DtCompileTable (FieldList, TableData->TableInfo, 380 &Subtable, TRUE); 381 if (ACPI_FAILURE (Status)) 382 { 383 return (Status); 384 } 385 386 DtInsertSubtable (Gbl_RootTable, Subtable); 387 DtPopSubtable (); 388 } 389 else 390 { 391 DtFatal (ASL_MSG_COMPILER_INTERNAL, *FieldList, 392 "Missing table dispatch info"); 393 return (AE_ERROR); 394 } 395 396 FinishHeader: 397 398 /* Set the final table length and then the checksum */ 399 400 DtSetTableLength (); 401 AcpiTableHeader = ACPI_CAST_PTR ( 402 ACPI_TABLE_HEADER, Gbl_RootTable->Buffer); 403 DtSetTableChecksum (&AcpiTableHeader->Checksum); 404 405 DtDumpFieldList (RootField); 406 DtDumpSubtableList (); 407 return (AE_OK); 408 } 409 410 411 /****************************************************************************** 412 * 413 * FUNCTION: DtCompileTable 414 * 415 * PARAMETERS: Field - Current field list pointer 416 * Info - Info table for this ACPI table 417 * RetSubtable - Compile result of table 418 * Required - If this subtable must exist 419 * 420 * RETURN: Status 421 * 422 * DESCRIPTION: Compile a subtable 423 * 424 *****************************************************************************/ 425 426 ACPI_STATUS 427 DtCompileTable ( 428 DT_FIELD **Field, 429 ACPI_DMTABLE_INFO *Info, 430 DT_SUBTABLE **RetSubtable, 431 BOOLEAN Required) 432 { 433 DT_FIELD *LocalField; 434 UINT32 Length; 435 DT_SUBTABLE *Subtable; 436 DT_SUBTABLE *InlineSubtable; 437 UINT32 FieldLength = 0; 438 UINT8 FieldType; 439 UINT8 *Buffer; 440 UINT8 *FlagBuffer = NULL; 441 UINT32 CurrentFlagByteOffset = 0; 442 ACPI_STATUS Status; 443 444 445 if (!Field || !*Field) 446 { 447 return (AE_BAD_PARAMETER); 448 } 449 450 /* Ignore optional subtable if name does not match */ 451 452 if ((Info->Flags & DT_OPTIONAL) && 453 ACPI_STRCMP ((*Field)->Name, Info->Name)) 454 { 455 *RetSubtable = NULL; 456 return (AE_OK); 457 } 458 459 Length = DtGetSubtableLength (*Field, Info); 460 if (Length == ASL_EOF) 461 { 462 return (AE_ERROR); 463 } 464 465 Subtable = UtLocalCalloc (sizeof (DT_SUBTABLE)); 466 467 if (Length > 0) 468 { 469 Subtable->Buffer = UtLocalCalloc (Length); 470 } 471 Subtable->Length = Length; 472 Subtable->TotalLength = Length; 473 Buffer = Subtable->Buffer; 474 475 LocalField = *Field; 476 477 /* 478 * Main loop walks the info table for this ACPI table or subtable 479 */ 480 for (; Info->Name; Info++) 481 { 482 if (Info->Opcode == ACPI_DMT_EXTRA_TEXT) 483 { 484 continue; 485 } 486 487 if (!LocalField) 488 { 489 snprintf (MsgBuffer, sizeof(MsgBuffer), "Found NULL field - Field name \"%s\" needed", 490 Info->Name); 491 DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer); 492 Status = AE_BAD_DATA; 493 goto Error; 494 } 495 496 /* Maintain table offsets */ 497 498 LocalField->TableOffset = Gbl_CurrentTableOffset; 499 FieldLength = DtGetFieldLength (LocalField, Info); 500 Gbl_CurrentTableOffset += FieldLength; 501 502 FieldType = DtGetFieldType (Info); 503 Gbl_InputFieldCount++; 504 505 switch (FieldType) 506 { 507 case DT_FIELD_TYPE_FLAGS_INTEGER: 508 /* 509 * Start of the definition of a flags field. 510 * This master flags integer starts at value zero, in preparation 511 * to compile and insert the flag fields from the individual bits 512 */ 513 LocalField = LocalField->Next; 514 *Field = LocalField; 515 516 FlagBuffer = Buffer; 517 CurrentFlagByteOffset = Info->Offset; 518 break; 519 520 case DT_FIELD_TYPE_FLAG: 521 522 /* Individual Flag field, can be multiple bits */ 523 524 if (FlagBuffer) 525 { 526 /* 527 * We must increment the FlagBuffer when we have crossed 528 * into the next flags byte within the flags field 529 * of type DT_FIELD_TYPE_FLAGS_INTEGER. 530 */ 531 FlagBuffer += (Info->Offset - CurrentFlagByteOffset); 532 CurrentFlagByteOffset = Info->Offset; 533 534 DtCompileFlag (FlagBuffer, LocalField, Info); 535 } 536 else 537 { 538 /* TBD - this is an internal error */ 539 } 540 541 LocalField = LocalField->Next; 542 *Field = LocalField; 543 break; 544 545 case DT_FIELD_TYPE_INLINE_SUBTABLE: 546 /* 547 * Recursion (one level max): compile GAS (Generic Address) 548 * or Notify in-line subtable 549 */ 550 *Field = LocalField; 551 552 if (Info->Opcode == ACPI_DMT_GAS) 553 { 554 Status = DtCompileTable (Field, AcpiDmTableInfoGas, 555 &InlineSubtable, TRUE); 556 } 557 else 558 { 559 Status = DtCompileTable (Field, AcpiDmTableInfoHestNotify, 560 &InlineSubtable, TRUE); 561 } 562 563 if (ACPI_FAILURE (Status)) 564 { 565 goto Error; 566 } 567 568 DtSetSubtableLength (InlineSubtable); 569 570 ACPI_MEMCPY (Buffer, InlineSubtable->Buffer, FieldLength); 571 ACPI_FREE (InlineSubtable->Buffer); 572 ACPI_FREE (InlineSubtable); 573 LocalField = *Field; 574 break; 575 576 case DT_FIELD_TYPE_LABEL: 577 578 DtWriteFieldToListing (Buffer, LocalField, 0); 579 LocalField = LocalField->Next; 580 break; 581 582 default: 583 584 /* Normal case for most field types (Integer, String, etc.) */ 585 586 DtCompileOneField (Buffer, LocalField, 587 FieldLength, FieldType, Info->Flags); 588 589 DtWriteFieldToListing (Buffer, LocalField, FieldLength); 590 LocalField = LocalField->Next; 591 592 if (Info->Flags & DT_LENGTH) 593 { 594 /* Field is an Integer that will contain a subtable length */ 595 596 Subtable->LengthField = Buffer; 597 Subtable->SizeOfLengthField = FieldLength; 598 } 599 600 break; 601 } 602 603 Buffer += FieldLength; 604 } 605 606 *Field = LocalField; 607 *RetSubtable = Subtable; 608 return (AE_OK); 609 610 Error: 611 ACPI_FREE (Subtable->Buffer); 612 ACPI_FREE (Subtable); 613 return (Status); 614 } 615