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, "Found a node with an unassigned AML opcode\n"); 278 return; 279 280 case AML_INT_RESERVEDFIELD_OP: 281 282 /* Special opcodes for within a field definition */ 283 284 Aml.Opcode = AML_FIELD_OFFSET_OP; 285 break; 286 287 case AML_INT_ACCESSFIELD_OP: 288 289 Aml.Opcode = AML_FIELD_ACCESS_OP; 290 break; 291 292 case AML_INT_CONNECTION_OP: 293 294 Aml.Opcode = AML_FIELD_CONNECTION_OP; 295 break; 296 297 default: 298 299 Aml.Opcode = Op->Asl.AmlOpcode; 300 break; 301 } 302 303 304 switch (Aml.Opcode) 305 { 306 case AML_PACKAGE_LENGTH: 307 308 /* Value is the length to be encoded (Used in field definitions) */ 309 310 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 311 break; 312 313 default: 314 315 /* Check for two-byte opcode */ 316 317 if (Aml.Opcode > 0x00FF) 318 { 319 /* Write the high byte first */ 320 321 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 322 } 323 324 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 325 326 /* Subtreelength doesn't include length of package length bytes */ 327 328 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 329 break; 330 } 331 332 /* Does this opcode have an associated "PackageLength" field? */ 333 334 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 335 { 336 if (Op->Asl.AmlPkgLenBytes == 1) 337 { 338 /* Simplest case -- no bytes to follow, just write the count */ 339 340 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 341 } 342 else if (Op->Asl.AmlPkgLenBytes != 0) 343 { 344 /* 345 * Encode the "bytes to follow" in the first byte, top two bits. 346 * The low-order nybble of the length is in the bottom 4 bits 347 */ 348 PkgLenFirstByte = (UINT8) 349 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 350 (PkgLen.LenBytes[0] & 0x0F)); 351 352 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 353 354 /* 355 * Shift the length over by the 4 bits we just stuffed 356 * in the first byte 357 */ 358 PkgLen.Len >>= 4; 359 360 /* Now we can write the remaining bytes - 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 ******************************************************************************/ 416 417 static void 418 CgWriteTableHeader ( 419 ACPI_PARSE_OBJECT *Op) 420 { 421 ACPI_PARSE_OBJECT *Child; 422 423 424 /* AML filename */ 425 426 Child = Op->Asl.Child; 427 428 /* Signature */ 429 430 Child = Child->Asl.Next; 431 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 432 433 /* Revision */ 434 435 Child = Child->Asl.Next; 436 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 437 438 /* Command-line Revision override */ 439 440 if (Gbl_RevisionOverride) 441 { 442 TableHeader.Revision = Gbl_RevisionOverride; 443 } 444 445 /* OEMID */ 446 447 Child = Child->Asl.Next; 448 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 449 450 /* OEM TableID */ 451 452 Child = Child->Asl.Next; 453 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 454 455 /* OEM Revision */ 456 457 Child = Child->Asl.Next; 458 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 459 460 /* Compiler ID */ 461 462 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 463 464 /* Compiler version */ 465 466 TableHeader.AslCompilerRevision = ACPI_CA_VERSION; 467 468 /* Table length. Checksum zero for now, will rewrite later */ 469 470 TableHeader.Length = Gbl_TableLength; 471 TableHeader.Checksum = 0; 472 473 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 474 } 475 476 477 /******************************************************************************* 478 * 479 * FUNCTION: CgCloseTable 480 * 481 * PARAMETERS: None. 482 * 483 * RETURN: None. 484 * 485 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 486 * re-writing the header. 487 * 488 ******************************************************************************/ 489 490 static void 491 CgCloseTable ( 492 void) 493 { 494 signed char Sum; 495 UINT8 FileByte; 496 497 498 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 499 Sum = 0; 500 501 /* Calculate the checksum over the entire file */ 502 503 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 504 { 505 Sum = (signed char) (Sum + FileByte); 506 } 507 508 /* Re-write the table header with the checksum */ 509 510 TableHeader.Checksum = (UINT8) (0 - Sum); 511 512 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 513 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 514 } 515 516 517 /******************************************************************************* 518 * 519 * FUNCTION: CgWriteNode 520 * 521 * PARAMETERS: Op - Parse node to write. 522 * 523 * RETURN: None. 524 * 525 * DESCRIPTION: Write the AML that corresponds to a parse node. 526 * 527 ******************************************************************************/ 528 529 static void 530 CgWriteNode ( 531 ACPI_PARSE_OBJECT *Op) 532 { 533 ASL_RESOURCE_NODE *Rnode; 534 535 536 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 537 /* TBD: this may not be the best place for this check */ 538 539 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 540 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 541 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 542 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 543 { 544 return; 545 } 546 547 Op->Asl.FinalAmlLength = 0; 548 549 switch (Op->Asl.AmlOpcode) 550 { 551 case AML_RAW_DATA_BYTE: 552 case AML_RAW_DATA_WORD: 553 case AML_RAW_DATA_DWORD: 554 case AML_RAW_DATA_QWORD: 555 556 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 557 return; 558 559 560 case AML_RAW_DATA_BUFFER: 561 562 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 563 return; 564 565 566 case AML_RAW_DATA_CHAIN: 567 568 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 569 while (Rnode) 570 { 571 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 572 Rnode = Rnode->Next; 573 } 574 return; 575 576 default: 577 578 /* Internal data opcodes must all appear above */ 579 580 break; 581 } 582 583 switch (Op->Asl.ParseOpcode) 584 { 585 case PARSEOP_DEFAULT_ARG: 586 587 break; 588 589 case PARSEOP_DEFINITIONBLOCK: 590 591 CgWriteTableHeader (Op); 592 break; 593 594 case PARSEOP_NAMESEG: 595 case PARSEOP_NAMESTRING: 596 case PARSEOP_METHODCALL: 597 598 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 599 break; 600 601 default: 602 603 CgWriteAmlOpcode (Op); 604 break; 605 } 606 } 607