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