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