Home | History | Annotate | Line # | Download | only in compiler
aslcodegen.c revision 1.1.1.9
      1 /******************************************************************************
      2  *
      3  * Module Name: aslcodegen - AML code generation
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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 #include "aslcompiler.h"
     45 #include "aslcompiler.y.h"
     46 #include "amlcode.h"
     47 
     48 #define _COMPONENT          ACPI_COMPILER
     49         ACPI_MODULE_NAME    ("aslcodegen")
     50 
     51 /* Local prototypes */
     52 
     53 static ACPI_STATUS
     54 CgAmlWriteWalk (
     55     ACPI_PARSE_OBJECT       *Op,
     56     UINT32                  Level,
     57     void                    *Context);
     58 
     59 static void
     60 CgLocalWriteAmlData (
     61     ACPI_PARSE_OBJECT       *Op,
     62     void                    *Buffer,
     63     UINT32                  Length);
     64 
     65 static void
     66 CgWriteAmlOpcode (
     67     ACPI_PARSE_OBJECT       *Op);
     68 
     69 static void
     70 CgWriteTableHeader (
     71     ACPI_PARSE_OBJECT       *Op);
     72 
     73 static void
     74 CgCloseTable (
     75     void);
     76 
     77 static void
     78 CgWriteNode (
     79     ACPI_PARSE_OBJECT       *Op);
     80 
     81 
     82 /*******************************************************************************
     83  *
     84  * FUNCTION:    CgGenerateAmlOutput
     85  *
     86  * PARAMETERS:  None.
     87  *
     88  * RETURN:      None
     89  *
     90  * DESCRIPTION: Generate AML code. Currently generates the listing file
     91  *              simultaneously.
     92  *
     93  ******************************************************************************/
     94 
     95 void
     96 CgGenerateAmlOutput (
     97     void)
     98 {
     99 
    100     /* Generate the AML output file */
    101 
    102     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
    103     Gbl_SourceLine = 0;
    104     Gbl_NextError = Gbl_ErrorLog;
    105 
    106     TrWalkParseTree (Gbl_ParseTreeRoot, ASL_WALK_VISIT_DOWNWARD,
    107         CgAmlWriteWalk, NULL, NULL);
    108 
    109     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
    110     CgCloseTable ();
    111 }
    112 
    113 
    114 /*******************************************************************************
    115  *
    116  * FUNCTION:    CgAmlWriteWalk
    117  *
    118  * PARAMETERS:  ASL_WALK_CALLBACK
    119  *
    120  * RETURN:      Status
    121  *
    122  * DESCRIPTION: Parse tree walk to generate the AML code.
    123  *
    124  ******************************************************************************/
    125 
    126 static ACPI_STATUS
    127 CgAmlWriteWalk (
    128     ACPI_PARSE_OBJECT       *Op,
    129     UINT32                  Level,
    130     void                    *Context)
    131 {
    132 
    133     /* Generate the AML for this node */
    134 
    135     CgWriteNode (Op);
    136 
    137     if (!Gbl_DebugFlag)
    138     {
    139         return (AE_OK);
    140     }
    141 
    142     /* Print header at level 0. Alignment assumes 32-bit pointers */
    143 
    144     if (!Level)
    145     {
    146         DbgPrint (ASL_TREE_OUTPUT,
    147             "\nFinal parse tree used for AML output:\n");
    148         DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_HEADER2);
    149     }
    150 
    151     /* Dump ParseOp name and possible value */
    152 
    153     switch (Op->Asl.ParseOpcode)
    154     {
    155     case PARSEOP_NAMESEG:
    156     case PARSEOP_NAMESTRING:
    157     case PARSEOP_METHODCALL:
    158     case PARSEOP_STRING_LITERAL:
    159 
    160         UtDumpStringOp (Op, Level);
    161         break;
    162 
    163     default:
    164 
    165         UtDumpBasicOp (Op, Level);
    166         break;
    167     }
    168 
    169     DbgPrint (ASL_TREE_OUTPUT, ASL_PARSE_TREE_DEBUG2,
    170         /* 1  */ (UINT32) Op->Asl.Value.Integer,
    171         /* 2  */ Op->Asl.ParseOpcode,
    172         /* 3  */ Op->Asl.AmlOpcode,
    173         /* 4  */ Op->Asl.AmlOpcodeLength,
    174         /* 5  */ Op->Asl.AmlPkgLenBytes,
    175         /* 6  */ Op->Asl.AmlLength,
    176         /* 7  */ Op->Asl.AmlSubtreeLength,
    177         /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
    178         /* 9  */ Op,
    179         /* 10 */ Op->Asl.Parent,
    180         /* 11 */ Op->Asl.Child,
    181         /* 12 */ Op->Asl.Next,
    182         /* 13 */ Op->Asl.CompileFlags,
    183         /* 14 */ Op->Asl.AcpiBtype,
    184         /* 15 */ Op->Asl.FinalAmlLength,
    185         /* 16 */ Op->Asl.Column,
    186         /* 17 */ Op->Asl.LineNumber,
    187         /* 18 */ Op->Asl.EndLine,
    188         /* 19 */ Op->Asl.LogicalLineNumber,
    189         /* 20 */ Op->Asl.EndLogicalLine);
    190 
    191     return (AE_OK);
    192 }
    193 
    194 
    195 /*******************************************************************************
    196  *
    197  * FUNCTION:    CgLocalWriteAmlData
    198  *
    199  * PARAMETERS:  Op              - Current parse op
    200  *              Buffer          - Buffer to write
    201  *              Length          - Size of data in buffer
    202  *
    203  * RETURN:      None
    204  *
    205  * DESCRIPTION: Write a buffer of AML data to the AML output file.
    206  *
    207  ******************************************************************************/
    208 
    209 static void
    210 CgLocalWriteAmlData (
    211     ACPI_PARSE_OBJECT       *Op,
    212     void                    *Buffer,
    213     UINT32                  Length)
    214 {
    215 
    216     /* Write the raw data to the AML file */
    217 
    218     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
    219 
    220     /* Update the final AML length for this node (used for listings) */
    221 
    222     if (Op)
    223     {
    224         Op->Asl.FinalAmlLength += Length;
    225     }
    226 }
    227 
    228 
    229 /*******************************************************************************
    230  *
    231  * FUNCTION:    CgWriteAmlOpcode
    232  *
    233  * PARAMETERS:  Op            - Parse node with an AML opcode
    234  *
    235  * RETURN:      None.
    236  *
    237  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
    238  *
    239  ******************************************************************************/
    240 
    241 static void
    242 CgWriteAmlOpcode (
    243     ACPI_PARSE_OBJECT       *Op)
    244 {
    245     UINT8                   PkgLenFirstByte;
    246     UINT32                  i;
    247     union {
    248         UINT16                  Opcode;
    249         UINT8                   OpcodeBytes[2];
    250     } Aml;
    251     union {
    252         UINT32                  Len;
    253         UINT8                   LenBytes[4];
    254     } PkgLen;
    255 
    256 
    257     /* We expect some DEFAULT_ARGs, just ignore them */
    258 
    259     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
    260     {
    261         return;
    262     }
    263 
    264     switch (Op->Asl.AmlOpcode)
    265     {
    266     case AML_UNASSIGNED_OPCODE:
    267 
    268         /* These opcodes should not get here */
    269 
    270         printf ("Found a node with an unassigned AML opcode\n");
    271         FlPrintFile (ASL_FILE_STDERR,
    272             "Found a node with an unassigned AML opcode\n");
    273         return;
    274 
    275     case AML_INT_RESERVEDFIELD_OP:
    276 
    277         /* Special opcodes for within a field definition */
    278 
    279         Aml.Opcode = AML_FIELD_OFFSET_OP;
    280         break;
    281 
    282     case AML_INT_ACCESSFIELD_OP:
    283 
    284         Aml.Opcode = AML_FIELD_ACCESS_OP;
    285         break;
    286 
    287     case AML_INT_CONNECTION_OP:
    288 
    289         Aml.Opcode = AML_FIELD_CONNECTION_OP;
    290         break;
    291 
    292     default:
    293 
    294         Aml.Opcode = Op->Asl.AmlOpcode;
    295         break;
    296     }
    297 
    298 
    299     switch (Aml.Opcode)
    300     {
    301     case AML_PACKAGE_LENGTH:
    302 
    303         /* Value is the length to be encoded (Used in field definitions) */
    304 
    305         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
    306         break;
    307 
    308     default:
    309 
    310         /* Check for two-byte opcode */
    311 
    312         if (Aml.Opcode > 0x00FF)
    313         {
    314             /* Write the high byte first */
    315 
    316             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
    317         }
    318 
    319         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
    320 
    321         /* Subtreelength doesn't include length of package length bytes */
    322 
    323         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
    324         break;
    325     }
    326 
    327     /* Does this opcode have an associated "PackageLength" field? */
    328 
    329     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
    330     {
    331         if (Op->Asl.AmlPkgLenBytes == 1)
    332         {
    333             /* Simplest case -- no bytes to follow, just write the count */
    334 
    335             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
    336         }
    337         else if (Op->Asl.AmlPkgLenBytes != 0)
    338         {
    339             /*
    340              * Encode the "bytes to follow" in the first byte, top two bits.
    341              * The low-order nybble of the length is in the bottom 4 bits
    342              */
    343             PkgLenFirstByte = (UINT8)
    344                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
    345                 (PkgLen.LenBytes[0] & 0x0F));
    346 
    347             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
    348 
    349             /*
    350              * Shift the length over by the 4 bits we just stuffed
    351              * in the first byte
    352              */
    353             PkgLen.Len >>= 4;
    354 
    355             /*
    356              * Now we can write the remaining bytes -
    357              * either 1, 2, or 3 bytes
    358              */
    359             for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
    360             {
    361                 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
    362             }
    363         }
    364     }
    365 
    366     switch (Aml.Opcode)
    367     {
    368     case AML_BYTE_OP:
    369 
    370         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
    371         break;
    372 
    373     case AML_WORD_OP:
    374 
    375         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
    376        break;
    377 
    378     case AML_DWORD_OP:
    379 
    380         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
    381         break;
    382 
    383     case AML_QWORD_OP:
    384 
    385         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
    386         break;
    387 
    388     case AML_STRING_OP:
    389 
    390         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
    391         break;
    392 
    393     default:
    394 
    395         /* All data opcodes must appear above */
    396 
    397         break;
    398     }
    399 }
    400 
    401 
    402 /*******************************************************************************
    403  *
    404  * FUNCTION:    CgWriteTableHeader
    405  *
    406  * PARAMETERS:  Op        - The DEFINITIONBLOCK node
    407  *
    408  * RETURN:      None
    409  *
    410  * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
    411  *
    412  ******************************************************************************/
    413 
    414 static void
    415 CgWriteTableHeader (
    416     ACPI_PARSE_OBJECT       *Op)
    417 {
    418     ACPI_PARSE_OBJECT       *Child;
    419 
    420 
    421     /* AML filename */
    422 
    423     Child = Op->Asl.Child;
    424 
    425     /* Signature */
    426 
    427     Child = Child->Asl.Next;
    428     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
    429 
    430     /* Revision */
    431 
    432     Child = Child->Asl.Next;
    433     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
    434 
    435     /* Command-line Revision override */
    436 
    437     if (Gbl_RevisionOverride)
    438     {
    439         TableHeader.Revision = Gbl_RevisionOverride;
    440     }
    441 
    442     /* OEMID */
    443 
    444     Child = Child->Asl.Next;
    445     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
    446 
    447     /* OEM TableID */
    448 
    449     Child = Child->Asl.Next;
    450     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
    451 
    452     /* OEM Revision */
    453 
    454     Child = Child->Asl.Next;
    455     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
    456 
    457     /* Compiler ID */
    458 
    459     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
    460 
    461     /* Compiler version */
    462 
    463     TableHeader.AslCompilerRevision = ACPI_CA_VERSION;
    464 
    465     /* Table length. Checksum zero for now, will rewrite later */
    466 
    467     TableHeader.Length = sizeof (ACPI_TABLE_HEADER) +
    468         Op->Asl.AmlSubtreeLength;
    469     TableHeader.Checksum = 0;
    470 
    471     Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
    472 
    473     /* Write entire header and clear the table header global */
    474 
    475     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
    476     memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER));
    477 }
    478 
    479 
    480 /*******************************************************************************
    481  *
    482  * FUNCTION:    CgUpdateHeader
    483  *
    484  * PARAMETERS:  Op                  - Op for the Definition Block
    485  *
    486  * RETURN:      None.
    487  *
    488  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
    489  *              re-writing the header for the input definition block
    490  *
    491  ******************************************************************************/
    492 
    493 static void
    494 CgUpdateHeader (
    495     ACPI_PARSE_OBJECT   *Op)
    496 {
    497     signed char         Sum;
    498     UINT32              i;
    499     UINT32              Length;
    500     UINT8               FileByte;
    501     UINT8               Checksum;
    502 
    503 
    504     /* Calculate the checksum over the entire definition block */
    505 
    506     Sum = 0;
    507     Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength;
    508     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset);
    509 
    510     for (i = 0; i < Length; i++)
    511     {
    512         if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK)
    513         {
    514             printf ("EOF while reading checksum bytes\n");
    515             return;
    516         }
    517 
    518         Sum = (signed char) (Sum + FileByte);
    519     }
    520 
    521     Checksum = (UINT8) (0 - Sum);
    522 
    523     /* Re-write the the checksum byte */
    524 
    525     FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset +
    526         ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum));
    527 
    528     FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1);
    529 }
    530 
    531 
    532 /*******************************************************************************
    533  *
    534  * FUNCTION:    CgCloseTable
    535  *
    536  * PARAMETERS:  None.
    537  *
    538  * RETURN:      None.
    539  *
    540  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
    541  *              re-writing each table header. This allows support for
    542  *              multiple definition blocks in a single source file.
    543  *
    544  ******************************************************************************/
    545 
    546 static void
    547 CgCloseTable (
    548     void)
    549 {
    550     ACPI_PARSE_OBJECT   *Op;
    551 
    552 
    553     /* Process all definition blocks */
    554 
    555     Op = Gbl_ParseTreeRoot->Asl.Child;
    556     while (Op)
    557     {
    558         CgUpdateHeader (Op);
    559         Op = Op->Asl.Next;
    560     }
    561 }
    562 
    563 
    564 /*******************************************************************************
    565  *
    566  * FUNCTION:    CgWriteNode
    567  *
    568  * PARAMETERS:  Op            - Parse node to write.
    569  *
    570  * RETURN:      None.
    571  *
    572  * DESCRIPTION: Write the AML that corresponds to a parse node.
    573  *
    574  ******************************************************************************/
    575 
    576 static void
    577 CgWriteNode (
    578     ACPI_PARSE_OBJECT       *Op)
    579 {
    580     ASL_RESOURCE_NODE       *Rnode;
    581 
    582 
    583     /* Always check for DEFAULT_ARG and other "Noop" nodes */
    584     /* TBD: this may not be the best place for this check */
    585 
    586     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
    587         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
    588         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
    589     {
    590         return;
    591     }
    592 
    593     if ((Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) &&
    594         Gbl_DoExternals == FALSE)
    595     {
    596         return;
    597     }
    598 
    599     Op->Asl.FinalAmlLength = 0;
    600 
    601     switch (Op->Asl.AmlOpcode)
    602     {
    603     case AML_RAW_DATA_BYTE:
    604     case AML_RAW_DATA_WORD:
    605     case AML_RAW_DATA_DWORD:
    606     case AML_RAW_DATA_QWORD:
    607 
    608         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
    609         return;
    610 
    611 
    612     case AML_RAW_DATA_BUFFER:
    613 
    614         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
    615         return;
    616 
    617 
    618     case AML_RAW_DATA_CHAIN:
    619 
    620         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
    621         while (Rnode)
    622         {
    623             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
    624             Rnode = Rnode->Next;
    625         }
    626         return;
    627 
    628     default:
    629 
    630         /* Internal data opcodes must all appear above */
    631 
    632         break;
    633     }
    634 
    635     switch (Op->Asl.ParseOpcode)
    636     {
    637     case PARSEOP_DEFAULT_ARG:
    638 
    639         break;
    640 
    641     case PARSEOP_DEFINITION_BLOCK:
    642 
    643         CgWriteTableHeader (Op);
    644         break;
    645 
    646     case PARSEOP_NAMESEG:
    647     case PARSEOP_NAMESTRING:
    648     case PARSEOP_METHODCALL:
    649 
    650         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
    651         break;
    652 
    653     default:
    654 
    655         CgWriteAmlOpcode (Op);
    656         break;
    657     }
    658 }
    659