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