1 /****************************************************************************** 2 * 3 * Module Name: aslcodegen - AML code generation 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 111 DbgPrint (ASL_TREE_OUTPUT, 112 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr" 113 " Parent Child Next Flags AcTyp Final Col L# EL# LL# ELL#\n", 114 76, " "); 115 116 CgCloseTable (); 117 } 118 119 120 /******************************************************************************* 121 * 122 * FUNCTION: CgAmlWriteWalk 123 * 124 * PARAMETERS: ASL_WALK_CALLBACK 125 * 126 * RETURN: Status 127 * 128 * DESCRIPTION: Parse tree walk to generate the AML code. 129 * 130 ******************************************************************************/ 131 132 static ACPI_STATUS 133 CgAmlWriteWalk ( 134 ACPI_PARSE_OBJECT *Op, 135 UINT32 Level, 136 void *Context) 137 { 138 139 /* 140 * Print header at level 0. Alignment assumes 32-bit pointers 141 */ 142 if (!Level) 143 { 144 DbgPrint (ASL_TREE_OUTPUT, 145 "Final parse tree used for AML output:\n"); 146 DbgPrint (ASL_TREE_OUTPUT, 147 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr" 148 " Parent Child Next Flags AcTyp Final Col L# EL# LL# ELL#\n", 149 76, " "); 150 } 151 152 /* Debug output */ 153 154 DbgPrint (ASL_TREE_OUTPUT, 155 "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); 156 UtPrintFormattedName (Op->Asl.ParseOpcode, Level); 157 158 if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG || 159 Op->Asl.ParseOpcode == PARSEOP_NAMESTRING || 160 Op->Asl.ParseOpcode == PARSEOP_METHODCALL) 161 { 162 DbgPrint (ASL_TREE_OUTPUT, 163 "%10.32s ", Op->Asl.ExternalName); 164 } 165 else 166 { 167 DbgPrint (ASL_TREE_OUTPUT, " "); 168 } 169 170 DbgPrint (ASL_TREE_OUTPUT, 171 "%08X %04X %04X %01X %04X %04X %04X %04X " 172 "%08X %08X %08X %08X %08X %08X %04X %02d %02d %02d %02d %02d\n", 173 /* 1 */ (UINT32) Op->Asl.Value.Integer, 174 /* 2 */ Op->Asl.ParseOpcode, 175 /* 3 */ Op->Asl.AmlOpcode, 176 /* 4 */ Op->Asl.AmlOpcodeLength, 177 /* 5 */ Op->Asl.AmlPkgLenBytes, 178 /* 6 */ Op->Asl.AmlLength, 179 /* 7 */ Op->Asl.AmlSubtreeLength, 180 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0, 181 /* 9 */ Op, 182 /* 10 */ Op->Asl.Parent, 183 /* 11 */ Op->Asl.Child, 184 /* 12 */ Op->Asl.Next, 185 /* 13 */ Op->Asl.CompileFlags, 186 /* 14 */ Op->Asl.AcpiBtype, 187 /* 15 */ Op->Asl.FinalAmlLength, 188 /* 16 */ Op->Asl.Column, 189 /* 17 */ Op->Asl.LineNumber, 190 /* 18 */ Op->Asl.EndLine, 191 /* 19 */ Op->Asl.LogicalLineNumber, 192 /* 20 */ Op->Asl.EndLogicalLine); 193 194 /* Generate the AML for this node */ 195 196 CgWriteNode (Op); 197 return (AE_OK); 198 } 199 200 201 /******************************************************************************* 202 * 203 * FUNCTION: CgLocalWriteAmlData 204 * 205 * PARAMETERS: Op - Current parse op 206 * Buffer - Buffer to write 207 * Length - Size of data in buffer 208 * 209 * RETURN: None 210 * 211 * DESCRIPTION: Write a buffer of AML data to the AML output file. 212 * 213 ******************************************************************************/ 214 215 static void 216 CgLocalWriteAmlData ( 217 ACPI_PARSE_OBJECT *Op, 218 void *Buffer, 219 UINT32 Length) 220 { 221 222 /* Write the raw data to the AML file */ 223 224 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length); 225 226 /* Update the final AML length for this node (used for listings) */ 227 228 if (Op) 229 { 230 Op->Asl.FinalAmlLength += Length; 231 } 232 } 233 234 235 /******************************************************************************* 236 * 237 * FUNCTION: CgWriteAmlOpcode 238 * 239 * PARAMETERS: Op - Parse node with an AML opcode 240 * 241 * RETURN: None. 242 * 243 * DESCRIPTION: Write the AML opcode corresponding to a parse node. 244 * 245 ******************************************************************************/ 246 247 static void 248 CgWriteAmlOpcode ( 249 ACPI_PARSE_OBJECT *Op) 250 { 251 UINT8 PkgLenFirstByte; 252 UINT32 i; 253 union { 254 UINT16 Opcode; 255 UINT8 OpcodeBytes[2]; 256 } Aml; 257 union { 258 UINT32 Len; 259 UINT8 LenBytes[4]; 260 } PkgLen; 261 262 263 /* We expect some DEFAULT_ARGs, just ignore them */ 264 265 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 266 { 267 return; 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 & NODE_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 426 427 /* AML filename */ 428 429 Child = Op->Asl.Child; 430 431 /* Signature */ 432 433 Child = Child->Asl.Next; 434 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 435 436 /* Revision */ 437 438 Child = Child->Asl.Next; 439 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 440 441 /* Command-line Revision override */ 442 443 if (Gbl_RevisionOverride) 444 { 445 TableHeader.Revision = Gbl_RevisionOverride; 446 } 447 448 /* OEMID */ 449 450 Child = Child->Asl.Next; 451 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 452 453 /* OEM TableID */ 454 455 Child = Child->Asl.Next; 456 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 457 458 /* OEM Revision */ 459 460 Child = Child->Asl.Next; 461 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 462 463 /* Compiler ID */ 464 465 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 466 467 /* Compiler version */ 468 469 TableHeader.AslCompilerRevision = ACPI_CA_VERSION; 470 471 /* Table length. Checksum zero for now, will rewrite later */ 472 473 TableHeader.Length = sizeof (ACPI_TABLE_HEADER) + 474 Op->Asl.AmlSubtreeLength; 475 TableHeader.Checksum = 0; 476 477 Op->Asl.FinalAmlOffset = ftell (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); 478 479 /* Write entire header and clear the table header global */ 480 481 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 482 memset (&TableHeader, 0, sizeof (ACPI_TABLE_HEADER)); 483 } 484 485 486 /******************************************************************************* 487 * 488 * FUNCTION: CgUpdateHeader 489 * 490 * PARAMETERS: Op - Op for the Definition Block 491 * 492 * RETURN: None. 493 * 494 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 495 * re-writing the header for the input definition block 496 * 497 ******************************************************************************/ 498 499 static void 500 CgUpdateHeader ( 501 ACPI_PARSE_OBJECT *Op) 502 { 503 signed char Sum; 504 UINT32 i; 505 UINT32 Length; 506 UINT8 FileByte; 507 UINT8 Checksum; 508 509 510 /* Calculate the checksum over the entire definition block */ 511 512 Sum = 0; 513 Length = sizeof (ACPI_TABLE_HEADER) + Op->Asl.AmlSubtreeLength; 514 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset); 515 516 for (i = 0; i < Length; i++) 517 { 518 if (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) != AE_OK) 519 { 520 printf ("EOF while reading checksum bytes\n"); 521 return; 522 } 523 524 Sum = (signed char) (Sum + FileByte); 525 } 526 527 Checksum = (UINT8) (0 - Sum); 528 529 /* Re-write the the checksum byte */ 530 531 FlSeekFile (ASL_FILE_AML_OUTPUT, Op->Asl.FinalAmlOffset + 532 ACPI_OFFSET (ACPI_TABLE_HEADER, Checksum)); 533 534 FlWriteFile (ASL_FILE_AML_OUTPUT, &Checksum, 1); 535 } 536 537 538 /******************************************************************************* 539 * 540 * FUNCTION: CgCloseTable 541 * 542 * PARAMETERS: None. 543 * 544 * RETURN: None. 545 * 546 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 547 * re-writing each table header. This allows support for 548 * multiple definition blocks in a single source file. 549 * 550 ******************************************************************************/ 551 552 static void 553 CgCloseTable ( 554 void) 555 { 556 ACPI_PARSE_OBJECT *Op; 557 558 559 /* Process all definition blocks */ 560 561 Op = RootNode->Asl.Child; 562 while (Op) 563 { 564 CgUpdateHeader (Op); 565 Op = Op->Asl.Next; 566 } 567 } 568 569 570 /******************************************************************************* 571 * 572 * FUNCTION: CgWriteNode 573 * 574 * PARAMETERS: Op - Parse node to write. 575 * 576 * RETURN: None. 577 * 578 * DESCRIPTION: Write the AML that corresponds to a parse node. 579 * 580 ******************************************************************************/ 581 582 static void 583 CgWriteNode ( 584 ACPI_PARSE_OBJECT *Op) 585 { 586 ASL_RESOURCE_NODE *Rnode; 587 588 589 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 590 /* TBD: this may not be the best place for this check */ 591 592 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 593 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 594 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 595 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 596 { 597 return; 598 } 599 600 Op->Asl.FinalAmlLength = 0; 601 602 switch (Op->Asl.AmlOpcode) 603 { 604 case AML_RAW_DATA_BYTE: 605 case AML_RAW_DATA_WORD: 606 case AML_RAW_DATA_DWORD: 607 case AML_RAW_DATA_QWORD: 608 609 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 610 return; 611 612 613 case AML_RAW_DATA_BUFFER: 614 615 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 616 return; 617 618 619 case AML_RAW_DATA_CHAIN: 620 621 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 622 while (Rnode) 623 { 624 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 625 Rnode = Rnode->Next; 626 } 627 return; 628 629 default: 630 631 /* Internal data opcodes must all appear above */ 632 633 break; 634 } 635 636 switch (Op->Asl.ParseOpcode) 637 { 638 case PARSEOP_DEFAULT_ARG: 639 640 break; 641 642 case PARSEOP_DEFINITION_BLOCK: 643 644 CgWriteTableHeader (Op); 645 break; 646 647 case PARSEOP_NAMESEG: 648 case PARSEOP_NAMESTRING: 649 case PARSEOP_METHODCALL: 650 651 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 652 break; 653 654 default: 655 656 CgWriteAmlOpcode (Op); 657 break; 658 } 659 } 660