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 }