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 #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 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 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 /* 260 * Before printing the bytecode, generate comment byte codes 261 * associated with this node. 262 */ 263 if (Gbl_CaptureComments) 264 { 265 CgWriteAmlComment(Op); 266 } 267 268 switch (Op->Asl.AmlOpcode) 269 { 270 case AML_UNASSIGNED_OPCODE: 271 272 /* These opcodes should not get here */ 273 274 printf ("Found a node with an unassigned AML opcode\n"); 275 FlPrintFile (ASL_FILE_STDERR, 276 "Found a node with an unassigned AML opcode\n"); 277 return; 278 279 case AML_INT_RESERVEDFIELD_OP: 280 281 /* Special opcodes for within a field definition */ 282 283 Aml.Opcode = AML_FIELD_OFFSET_OP; 284 break; 285 286 case AML_INT_ACCESSFIELD_OP: 287 288 Aml.Opcode = AML_FIELD_ACCESS_OP; 289 break; 290 291 case AML_INT_CONNECTION_OP: 292 293 Aml.Opcode = AML_FIELD_CONNECTION_OP; 294 break; 295 296 default: 297 298 Aml.Opcode = Op->Asl.AmlOpcode; 299 break; 300 } 301 302 303 switch (Aml.Opcode) 304 { 305 case AML_PACKAGE_LENGTH: 306 307 /* Value is the length to be encoded (Used in field definitions) */ 308 309 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 310 break; 311 312 default: 313 314 /* Check for two-byte opcode */ 315 316 if (Aml.Opcode > 0x00FF) 317 { 318 /* Write the high byte first */ 319 320 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 321 } 322 323 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 324 325 /* Subtreelength doesn't include length of package length bytes */ 326 327 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 328 break; 329 } 330 331 /* Does this opcode have an associated "PackageLength" field? */ 332 333 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 334 { 335 if (Op->Asl.AmlPkgLenBytes == 1) 336 { 337 /* Simplest case -- no bytes to follow, just write the count */ 338 339 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 340 } 341 else if (Op->Asl.AmlPkgLenBytes != 0) 342 { 343 /* 344 * Encode the "bytes to follow" in the first byte, top two bits. 345 * The low-order nybble of the length is in the bottom 4 bits 346 */ 347 PkgLenFirstByte = (UINT8) 348 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 349 (PkgLen.LenBytes[0] & 0x0F)); 350 351 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 352 353 /* 354 * Shift the length over by the 4 bits we just stuffed 355 * in the first byte 356 */ 357 PkgLen.Len >>= 4; 358 359 /* 360 * Now we can write the remaining bytes - 361 * either 1, 2, or 3 bytes 362 */ 363 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++) 364 { 365 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1); 366 } 367 } 368 } 369 370 switch (Aml.Opcode) 371 { 372 case AML_BYTE_OP: 373 374 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1); 375 break; 376 377 case AML_WORD_OP: 378 379 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2); 380 break; 381 382 case AML_DWORD_OP: 383 384 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4); 385 break; 386 387 case AML_QWORD_OP: 388 389 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8); 390 break; 391 392 case AML_STRING_OP: 393 394 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 395 break; 396 397 default: 398 399 /* All data opcodes must appear above */ 400 401 break; 402 } 403 } 404 405 406 /******************************************************************************* 407 * 408 * FUNCTION: CgWriteTableHeader 409 * 410 * PARAMETERS: Op - The DEFINITIONBLOCK node 411 * 412 * RETURN: None 413 * 414 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 415 * 416 ******************************************************************************/ 417 418 static void 419 CgWriteTableHeader ( 420 ACPI_PARSE_OBJECT *Op) 421 { 422 ACPI_PARSE_OBJECT *Child; 423 UINT32 CommentLength; 424 ACPI_COMMENT_NODE *Current; 425 426 427 /* AML filename */ 428 429 Child = Op->Asl.Child; 430 431 /* Signature */ 432 433 Child = Child->Asl.Next; 434 435 /* 436 * For ASL-/ASL+ converter: replace the table signature with 437 * "XXXX" and save the original table signature. This results in an AML 438 * file with the signature "XXXX". The converter should remove this AML 439 * file. In the event where this AML file does not get deleted, the 440 * "XXXX" table signature prevents this AML file from running on the AML 441 * interpreter. 442 */ 443 if (Gbl_CaptureComments) 444 { 445 strncpy(AcpiGbl_TableSig, Child->Asl.Value.String, 4); 446 Child->Asl.Value.String = ACPI_SIG_XXXX; 447 } 448 449 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 450 451 /* Revision */ 452 453 Child = Child->Asl.Next; 454 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 455 456 /* Command-line Revision override */ 457 458 if (Gbl_RevisionOverride) 459 { 460 TableHeader.Revision = Gbl_RevisionOverride; 461 } 462 463 /* OEMID */ 464 465 Child = Child->Asl.Next; 466 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 467 468 /* OEM TableID */ 469 470 Child = Child->Asl.Next; 471 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 472 473 /* OEM Revision */ 474 475 Child = Child->Asl.Next; 476 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 477 478 /* Compiler ID */ 479 480 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 481 482 /* Compiler version */ 483 484 TableHeader.AslCompilerRevision = ACPI_CA_VERSION; 485 486 /* Table length. Checksum zero for now, will rewrite later */ 487 488 TableHeader.Length = sizeof (ACPI_TABLE_HEADER) + 489 Op->Asl.AmlSubtreeLength; 490 491 /* Calculate the comment lengths for this definition block parseOp */ 492 493 if (Gbl_CaptureComments) 494 { 495 CvDbgPrint ("Calculating comment lengths for %s in write header\n", 496 Op->Asl.ParseOpName); 497 498 /* 499 * Take the filename without extensions, add 3 for the new extension 500 * and another 3 for the a908 bytecode and null terminator. 501 */ 502 TableHeader.Length += strrchr (Gbl_ParseTreeRoot->Asl.Filename, '.') 503 - Gbl_ParseTreeRoot->Asl.Filename + 1 + 3 + 3; 504 Op->Asl.AmlSubtreeLength += 505 strlen (Gbl_ParseTreeRoot->Asl.Filename) + 3; 506 CvDbgPrint (" Length: %lu\n", 507 strlen (Gbl_ParseTreeRoot->Asl.Filename) + 3); 508 509 if (Op->Asl.CommentList) 510 { 511 Current = Op->Asl.CommentList; 512 while (Current) 513 { 514 CommentLength = strlen (Current->Comment)+3; 515 CvDbgPrint ("Length of standard comment): %d\n", CommentLength); 516 CvDbgPrint (" Comment string: %s\n\n", Current->Comment); 517 TableHeader.Length += CommentLength; 518 Op->Asl.AmlSubtreeLength += CommentLength; 519 Current = Current->Next; 520 CvDbgPrint (" Length: %u\n", CommentLength); 521 } 522 } 523 if (Op->Asl.CloseBraceComment) 524 { 525 CommentLength = strlen (Op->Asl.CloseBraceComment)+3; 526 CvDbgPrint ("Length of inline comment +3: %d\n", CommentLength); 527 CvDbgPrint (" Comment string: %s\n\n", Op->Asl.CloseBraceComment); 528 TableHeader.Length += CommentLength; 529 Op->Asl.AmlSubtreeLength += CommentLength; 530 CvDbgPrint (" Length: %u\n", CommentLength); 531 } 532 } 533 534 TableHeader.Checksum = 0; 535 536 Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); 537 538 /* Write entire header and clear the table header global */ 539 540 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 541 memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER)); 542 } 543 544 545 /******************************************************************************* 546 * 547 * FUNCTION: CgUpdateHeader 548 * 549 * PARAMETERS: Op - Op for the Definition Block 550 * 551 * RETURN: None. 552 * 553 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 554 * re-writing the header for the input definition block 555 * 556 ******************************************************************************/ 557 558 static void 559 CgUpdateHeader ( 560 ACPI_PARSE_OBJECT *Op) 561 { 562 signed char Sum; 563 UINT32 i; 564 UINT32 Length; 565 UINT8 FileByte; 566 UINT8 Checksum; 567 568 569 /* Calculate the checksum over the entire definition block */ 570 571 Sum = 0; 572 Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength; 573 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset); 574 575 for (i = 0; i < Length; i++) 576 { 577 if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK) 578 { 579 printf ("EOF while reading checksum bytes\n"); 580 return; 581 } 582 583 Sum = (signed char) (Sum + FileByte); 584 } 585 586 Checksum = (UINT8) (0 - Sum); 587 588 /* Re-write the the checksum byte */ 589 590 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset + 591 ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum)); 592 593 FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1); 594 } 595 596 597 /******************************************************************************* 598 * 599 * FUNCTION: CgCloseTable 600 * 601 * PARAMETERS: None. 602 * 603 * RETURN: None. 604 * 605 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 606 * re-writing each table header. This allows support for 607 * multiple definition blocks in a single source file. 608 * 609 ******************************************************************************/ 610 611 static void 612 CgCloseTable ( 613 void) 614 { 615 ACPI_PARSE_OBJECT *Op; 616 617 618 /* Process all definition blocks */ 619 620 Op = Gbl_ParseTreeRoot->Asl.Child; 621 while (Op) 622 { 623 CgUpdateHeader (Op); 624 Op = Op->Asl.Next; 625 } 626 } 627 628 629 /******************************************************************************* 630 * 631 * FUNCTION: CgWriteNode 632 * 633 * PARAMETERS: Op - Parse node to write. 634 * 635 * RETURN: None. 636 * 637 * DESCRIPTION: Write the AML that corresponds to a parse node. 638 * 639 ******************************************************************************/ 640 641 static void 642 CgWriteNode ( 643 ACPI_PARSE_OBJECT *Op) 644 { 645 ASL_RESOURCE_NODE *Rnode; 646 647 648 /* Write all comments here. */ 649 if (Gbl_CaptureComments) 650 { 651 CgWriteAmlComment(Op); 652 } 653 654 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 655 /* TBD: this may not be the best place for this check */ 656 657 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 658 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 659 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 660 { 661 return; 662 } 663 664 if ((Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) && 665 Gbl_DoExternals == FALSE) 666 { 667 return; 668 } 669 670 Op->Asl.FinalAmlLength = 0; 671 672 switch (Op->Asl.AmlOpcode) 673 { 674 case AML_RAW_DATA_BYTE: 675 case AML_RAW_DATA_WORD: 676 case AML_RAW_DATA_DWORD: 677 case AML_RAW_DATA_QWORD: 678 679 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 680 return; 681 682 683 case AML_RAW_DATA_BUFFER: 684 685 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 686 return; 687 688 689 case AML_RAW_DATA_CHAIN: 690 691 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 692 while (Rnode) 693 { 694 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 695 Rnode = Rnode->Next; 696 } 697 return; 698 699 default: 700 701 /* Internal data opcodes must all appear above */ 702 703 break; 704 } 705 706 switch (Op->Asl.ParseOpcode) 707 { 708 case PARSEOP_DEFAULT_ARG: 709 710 break; 711 712 case PARSEOP_DEFINITION_BLOCK: 713 714 CgWriteTableHeader (Op); 715 if (Gbl_CaptureComments) 716 { 717 CgWriteAmlDefBlockComment (Op); 718 } 719 break; 720 721 case PARSEOP_NAMESEG: 722 case PARSEOP_NAMESTRING: 723 case PARSEOP_METHODCALL: 724 725 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 726 break; 727 728 default: 729 730 CgWriteAmlOpcode (Op); 731 break; 732 } 733 } 734