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