Home | History | Annotate | Line # | Download | only in compiler
aslcodegen.c revision 1.1.1.4
      1 /******************************************************************************
      2  *
      3  * Module Name: aslcodegen - AML code generation
      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 #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     DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n");
    101 
    102     /* Generate the AML output file */
    103 
    104     FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0);
    105     Gbl_SourceLine = 0;
    106     Gbl_NextError = Gbl_ErrorLog;
    107 
    108     TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD,
    109         CgAmlWriteWalk, NULL, NULL);
    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     /*
    134      * Print header at level 0. Alignment assumes 32-bit pointers
    135      */
    136     if (!Level)
    137     {
    138         DbgPrint (ASL_TREE_OUTPUT,
    139             "Final parse tree used for AML output:\n");
    140         DbgPrint (ASL_TREE_OUTPUT,
    141             "%*s Value    P_Op A_Op OpLen PByts Len  SubLen PSubLen OpPtr    Child    Parent   Flags    AcTyp    Final Col L\n",
    142             76, " ");
    143     }
    144 
    145     /* Debug output */
    146 
    147     DbgPrint (ASL_TREE_OUTPUT,
    148         "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level);
    149     UtPrintFormattedName (Op->Asl.ParseOpcode, Level);
    150 
    151     if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG    ||
    152         Op->Asl.ParseOpcode == PARSEOP_NAMESTRING ||
    153         Op->Asl.ParseOpcode == PARSEOP_METHODCALL)
    154     {
    155         DbgPrint (ASL_TREE_OUTPUT,
    156             "%10.32s      ", Op->Asl.ExternalName);
    157     }
    158     else
    159     {
    160         DbgPrint (ASL_TREE_OUTPUT, "                ");
    161     }
    162 
    163     DbgPrint (ASL_TREE_OUTPUT,
    164     "%08X %04X %04X %01X     %04X  %04X %04X   %04X    %08X %08X %08X %08X %08X %04X  %02d  %02d\n",
    165             /* 1  */ (UINT32) Op->Asl.Value.Integer,
    166             /* 2  */ Op->Asl.ParseOpcode,
    167             /* 3  */ Op->Asl.AmlOpcode,
    168             /* 4  */ Op->Asl.AmlOpcodeLength,
    169             /* 5  */ Op->Asl.AmlPkgLenBytes,
    170             /* 6  */ Op->Asl.AmlLength,
    171             /* 7  */ Op->Asl.AmlSubtreeLength,
    172             /* 8  */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0,
    173             /* 9  */ Op,
    174             /* 10 */ Op->Asl.Child,
    175             /* 11 */ Op->Asl.Parent,
    176             /* 12 */ Op->Asl.CompileFlags,
    177             /* 13 */ Op->Asl.AcpiBtype,
    178             /* 14 */ Op->Asl.FinalAmlLength,
    179             /* 15 */ Op->Asl.Column,
    180             /* 16 */ Op->Asl.LineNumber);
    181 
    182     /* Generate the AML for this node */
    183 
    184     CgWriteNode (Op);
    185     return (AE_OK);
    186 }
    187 
    188 
    189 /*******************************************************************************
    190  *
    191  * FUNCTION:    CgLocalWriteAmlData
    192  *
    193  * PARAMETERS:  Op              - Current parse op
    194  *              Buffer          - Buffer to write
    195  *              Length          - Size of data in buffer
    196  *
    197  * RETURN:      None
    198  *
    199  * DESCRIPTION: Write a buffer of AML data to the AML output file.
    200  *
    201  ******************************************************************************/
    202 
    203 static void
    204 CgLocalWriteAmlData (
    205     ACPI_PARSE_OBJECT       *Op,
    206     void                    *Buffer,
    207     UINT32                  Length)
    208 {
    209 
    210     /* Write the raw data to the AML file */
    211 
    212     FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length);
    213 
    214     /* Update the final AML length for this node (used for listings) */
    215 
    216     if (Op)
    217     {
    218         Op->Asl.FinalAmlLength += Length;
    219     }
    220 }
    221 
    222 
    223 /*******************************************************************************
    224  *
    225  * FUNCTION:    CgWriteAmlOpcode
    226  *
    227  * PARAMETERS:  Op            - Parse node with an AML opcode
    228  *
    229  * RETURN:      None.
    230  *
    231  * DESCRIPTION: Write the AML opcode corresponding to a parse node.
    232  *
    233  ******************************************************************************/
    234 
    235 static void
    236 CgWriteAmlOpcode (
    237     ACPI_PARSE_OBJECT       *Op)
    238 {
    239     UINT8                   PkgLenFirstByte;
    240     UINT32                  i;
    241     union {
    242         UINT16                  Opcode;
    243         UINT8                   OpcodeBytes[2];
    244     } Aml;
    245     union {
    246         UINT32                  Len;
    247         UINT8                   LenBytes[4];
    248     } PkgLen;
    249 
    250 
    251     /* We expect some DEFAULT_ARGs, just ignore them */
    252 
    253     if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
    254     {
    255         return;
    256     }
    257 
    258     switch (Op->Asl.AmlOpcode)
    259     {
    260     case AML_UNASSIGNED_OPCODE:
    261 
    262         /* These opcodes should not get here */
    263 
    264         printf ("Found a node with an unassigned AML opcode\n");
    265         FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n");
    266         return;
    267 
    268     case AML_INT_RESERVEDFIELD_OP:
    269 
    270         /* Special opcodes for within a field definition */
    271 
    272         Aml.Opcode = AML_FIELD_OFFSET_OP;
    273         break;
    274 
    275     case AML_INT_ACCESSFIELD_OP:
    276 
    277         Aml.Opcode = AML_FIELD_ACCESS_OP;
    278         break;
    279 
    280     case AML_INT_CONNECTION_OP:
    281 
    282         Aml.Opcode = AML_FIELD_CONNECTION_OP;
    283         break;
    284 
    285     default:
    286 
    287         Aml.Opcode = Op->Asl.AmlOpcode;
    288         break;
    289     }
    290 
    291 
    292     switch (Aml.Opcode)
    293     {
    294     case AML_PACKAGE_LENGTH:
    295 
    296         /* Value is the length to be encoded (Used in field definitions) */
    297 
    298         PkgLen.Len = (UINT32) Op->Asl.Value.Integer;
    299         break;
    300 
    301     default:
    302 
    303         /* Check for two-byte opcode */
    304 
    305         if (Aml.Opcode > 0x00FF)
    306         {
    307             /* Write the high byte first */
    308 
    309             CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1);
    310         }
    311 
    312         CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1);
    313 
    314         /* Subtreelength doesn't include length of package length bytes */
    315 
    316         PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes;
    317         break;
    318     }
    319 
    320     /* Does this opcode have an associated "PackageLength" field? */
    321 
    322     if (Op->Asl.CompileFlags & NODE_AML_PACKAGE)
    323     {
    324         if (Op->Asl.AmlPkgLenBytes == 1)
    325         {
    326             /* Simplest case -- no bytes to follow, just write the count */
    327 
    328             CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1);
    329         }
    330         else if (Op->Asl.AmlPkgLenBytes != 0)
    331         {
    332             /*
    333              * Encode the "bytes to follow" in the first byte, top two bits.
    334              * The low-order nybble of the length is in the bottom 4 bits
    335              */
    336             PkgLenFirstByte = (UINT8)
    337                 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) |
    338                 (PkgLen.LenBytes[0] & 0x0F));
    339 
    340             CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1);
    341 
    342             /*
    343              * Shift the length over by the 4 bits we just stuffed
    344              * in the first byte
    345              */
    346             PkgLen.Len >>= 4;
    347 
    348             /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */
    349 
    350             for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++)
    351             {
    352                 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1);
    353             }
    354         }
    355     }
    356 
    357     switch (Aml.Opcode)
    358     {
    359     case AML_BYTE_OP:
    360 
    361         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1);
    362         break;
    363 
    364     case AML_WORD_OP:
    365 
    366         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2);
    367        break;
    368 
    369     case AML_DWORD_OP:
    370 
    371         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4);
    372         break;
    373 
    374     case AML_QWORD_OP:
    375 
    376         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8);
    377         break;
    378 
    379     case AML_STRING_OP:
    380 
    381         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
    382         break;
    383 
    384     default:
    385 
    386         /* All data opcodes must appear above */
    387 
    388         break;
    389     }
    390 }
    391 
    392 
    393 /*******************************************************************************
    394  *
    395  * FUNCTION:    CgWriteTableHeader
    396  *
    397  * PARAMETERS:  Op        - The DEFINITIONBLOCK node
    398  *
    399  * RETURN:      None
    400  *
    401  * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK
    402  *
    403  ******************************************************************************/
    404 
    405 static void
    406 CgWriteTableHeader (
    407     ACPI_PARSE_OBJECT       *Op)
    408 {
    409     ACPI_PARSE_OBJECT       *Child;
    410 
    411 
    412     /* AML filename */
    413 
    414     Child = Op->Asl.Child;
    415 
    416     /* Signature */
    417 
    418     Child = Child->Asl.Next;
    419     strncpy (TableHeader.Signature, Child->Asl.Value.String, 4);
    420 
    421     /* Revision */
    422 
    423     Child = Child->Asl.Next;
    424     TableHeader.Revision = (UINT8) Child->Asl.Value.Integer;
    425 
    426     /* Command-line Revision override */
    427 
    428     if (Gbl_RevisionOverride)
    429     {
    430         TableHeader.Revision = Gbl_RevisionOverride;
    431     }
    432 
    433     /* OEMID */
    434 
    435     Child = Child->Asl.Next;
    436     strncpy (TableHeader.OemId, Child->Asl.Value.String, 6);
    437 
    438     /* OEM TableID */
    439 
    440     Child = Child->Asl.Next;
    441     strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8);
    442 
    443     /* OEM Revision */
    444 
    445     Child = Child->Asl.Next;
    446     TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer;
    447 
    448     /* Compiler ID */
    449 
    450     ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID);
    451 
    452     /* Compiler version */
    453 
    454     TableHeader.AslCompilerRevision = ASL_REVISION;
    455 
    456     /* Table length. Checksum zero for now, will rewrite later */
    457 
    458     TableHeader.Length   = Gbl_TableLength;
    459     TableHeader.Checksum = 0;
    460 
    461     CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER));
    462 }
    463 
    464 
    465 /*******************************************************************************
    466  *
    467  * FUNCTION:    CgCloseTable
    468  *
    469  * PARAMETERS:  None.
    470  *
    471  * RETURN:      None.
    472  *
    473  * DESCRIPTION: Complete the ACPI table by calculating the checksum and
    474  *              re-writing the header.
    475  *
    476  ******************************************************************************/
    477 
    478 static void
    479 CgCloseTable (
    480     void)
    481 {
    482     signed char         Sum;
    483     UINT8               FileByte;
    484 
    485 
    486     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
    487     Sum = 0;
    488 
    489     /* Calculate the checksum over the entire file */
    490 
    491     while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK)
    492     {
    493         Sum = (signed char) (Sum + FileByte);
    494     }
    495 
    496     /* Re-write the table header with the checksum */
    497 
    498     TableHeader.Checksum = (UINT8) (0 - Sum);
    499 
    500     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
    501     CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER));
    502 }
    503 
    504 
    505 /*******************************************************************************
    506  *
    507  * FUNCTION:    CgWriteNode
    508  *
    509  * PARAMETERS:  Op            - Parse node to write.
    510  *
    511  * RETURN:      None.
    512  *
    513  * DESCRIPTION: Write the AML that corresponds to a parse node.
    514  *
    515  ******************************************************************************/
    516 
    517 static void
    518 CgWriteNode (
    519     ACPI_PARSE_OBJECT       *Op)
    520 {
    521     ASL_RESOURCE_NODE       *Rnode;
    522 
    523 
    524     /* Always check for DEFAULT_ARG and other "Noop" nodes */
    525     /* TBD: this may not be the best place for this check */
    526 
    527     if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)  ||
    528         (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)     ||
    529         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE)      ||
    530         (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END))
    531     {
    532         return;
    533     }
    534 
    535     Op->Asl.FinalAmlLength = 0;
    536 
    537     switch (Op->Asl.AmlOpcode)
    538     {
    539     case AML_RAW_DATA_BYTE:
    540     case AML_RAW_DATA_WORD:
    541     case AML_RAW_DATA_DWORD:
    542     case AML_RAW_DATA_QWORD:
    543 
    544         CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength);
    545         return;
    546 
    547 
    548     case AML_RAW_DATA_BUFFER:
    549 
    550         CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength);
    551         return;
    552 
    553 
    554     case AML_RAW_DATA_CHAIN:
    555 
    556         Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer);
    557         while (Rnode)
    558         {
    559             CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength);
    560             Rnode = Rnode->Next;
    561         }
    562         return;
    563 
    564     default:
    565 
    566         /* Internal data opcodes must all appear above */
    567 
    568         break;
    569     }
    570 
    571     switch (Op->Asl.ParseOpcode)
    572     {
    573     case PARSEOP_DEFAULT_ARG:
    574 
    575         break;
    576 
    577     case PARSEOP_DEFINITIONBLOCK:
    578 
    579         CgWriteTableHeader (Op);
    580         break;
    581 
    582     case PARSEOP_NAMESEG:
    583     case PARSEOP_NAMESTRING:
    584     case PARSEOP_METHODCALL:
    585 
    586         CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength);
    587         break;
    588 
    589     default:
    590 
    591         CgWriteAmlOpcode (Op);
    592         break;
    593     }
    594 }
    595