1 /****************************************************************************** 2 * 3 * Module Name: aslcodegen - AML code generation 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2014, 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 45 #include "aslcompiler.h" 46 #include "aslcompiler.y.h" 47 #include "amlcode.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 CgLocalWriteAmlData ( 62 ACPI_PARSE_OBJECT *Op, 63 void *Buffer, 64 UINT32 Length); 65 66 static void 67 CgWriteAmlOpcode ( 68 ACPI_PARSE_OBJECT *Op); 69 70 static void 71 CgWriteTableHeader ( 72 ACPI_PARSE_OBJECT *Op); 73 74 static void 75 CgCloseTable ( 76 void); 77 78 static void 79 CgWriteNode ( 80 ACPI_PARSE_OBJECT *Op); 81 82 83 /******************************************************************************* 84 * 85 * FUNCTION: CgGenerateAmlOutput 86 * 87 * PARAMETERS: None. 88 * 89 * RETURN: None 90 * 91 * DESCRIPTION: Generate AML code. Currently generates the listing file 92 * simultaneously. 93 * 94 ******************************************************************************/ 95 96 void 97 CgGenerateAmlOutput ( 98 void) 99 { 100 101 DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n"); 102 103 /* Generate the AML output file */ 104 105 FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0); 106 Gbl_SourceLine = 0; 107 Gbl_NextError = Gbl_ErrorLog; 108 109 TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, 110 CgAmlWriteWalk, NULL, NULL); 111 CgCloseTable (); 112 } 113 114 115 /******************************************************************************* 116 * 117 * FUNCTION: CgAmlWriteWalk 118 * 119 * PARAMETERS: ASL_WALK_CALLBACK 120 * 121 * RETURN: Status 122 * 123 * DESCRIPTION: Parse tree walk to generate the AML code. 124 * 125 ******************************************************************************/ 126 127 static ACPI_STATUS 128 CgAmlWriteWalk ( 129 ACPI_PARSE_OBJECT *Op, 130 UINT32 Level, 131 void *Context) 132 { 133 134 /* 135 * Print header at level 0. Alignment assumes 32-bit pointers 136 */ 137 if (!Level) 138 { 139 DbgPrint (ASL_TREE_OUTPUT, 140 "Final parse tree used for AML output:\n"); 141 DbgPrint (ASL_TREE_OUTPUT, 142 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr Child Parent Flags AcTyp Final Col L\n", 143 76, " "); 144 } 145 146 /* Debug output */ 147 148 DbgPrint (ASL_TREE_OUTPUT, 149 "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); 150 UtPrintFormattedName (Op->Asl.ParseOpcode, Level); 151 152 if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG || 153 Op->Asl.ParseOpcode == PARSEOP_NAMESTRING || 154 Op->Asl.ParseOpcode == PARSEOP_METHODCALL) 155 { 156 DbgPrint (ASL_TREE_OUTPUT, 157 "%10.32s ", Op->Asl.ExternalName); 158 } 159 else 160 { 161 DbgPrint (ASL_TREE_OUTPUT, " "); 162 } 163 164 DbgPrint (ASL_TREE_OUTPUT, 165 "%08X %04X %04X %01X %04X %04X %04X %04X %08X %08X %08X %08X %08X %04X %02d %02d\n", 166 /* 1 */ (UINT32) Op->Asl.Value.Integer, 167 /* 2 */ Op->Asl.ParseOpcode, 168 /* 3 */ Op->Asl.AmlOpcode, 169 /* 4 */ Op->Asl.AmlOpcodeLength, 170 /* 5 */ Op->Asl.AmlPkgLenBytes, 171 /* 6 */ Op->Asl.AmlLength, 172 /* 7 */ Op->Asl.AmlSubtreeLength, 173 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0, 174 /* 9 */ Op, 175 /* 10 */ Op->Asl.Child, 176 /* 11 */ Op->Asl.Parent, 177 /* 12 */ Op->Asl.CompileFlags, 178 /* 13 */ Op->Asl.AcpiBtype, 179 /* 14 */ Op->Asl.FinalAmlLength, 180 /* 15 */ Op->Asl.Column, 181 /* 16 */ Op->Asl.LineNumber); 182 183 /* Generate the AML for this node */ 184 185 CgWriteNode (Op); 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 static 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 switch (Op->Asl.AmlOpcode) 260 { 261 case AML_UNASSIGNED_OPCODE: 262 263 /* These opcodes should not get here */ 264 265 printf ("Found a node with an unassigned AML opcode\n"); 266 FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n"); 267 return; 268 269 case AML_INT_RESERVEDFIELD_OP: 270 271 /* Special opcodes for within a field definition */ 272 273 Aml.Opcode = AML_FIELD_OFFSET_OP; 274 break; 275 276 case AML_INT_ACCESSFIELD_OP: 277 278 Aml.Opcode = AML_FIELD_ACCESS_OP; 279 break; 280 281 case AML_INT_CONNECTION_OP: 282 283 Aml.Opcode = AML_FIELD_CONNECTION_OP; 284 break; 285 286 default: 287 288 Aml.Opcode = Op->Asl.AmlOpcode; 289 break; 290 } 291 292 293 switch (Aml.Opcode) 294 { 295 case AML_PACKAGE_LENGTH: 296 297 /* Value is the length to be encoded (Used in field definitions) */ 298 299 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 300 break; 301 302 default: 303 304 /* Check for two-byte opcode */ 305 306 if (Aml.Opcode > 0x00FF) 307 { 308 /* Write the high byte first */ 309 310 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 311 } 312 313 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 314 315 /* Subtreelength doesn't include length of package length bytes */ 316 317 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 318 break; 319 } 320 321 /* Does this opcode have an associated "PackageLength" field? */ 322 323 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 324 { 325 if (Op->Asl.AmlPkgLenBytes == 1) 326 { 327 /* Simplest case -- no bytes to follow, just write the count */ 328 329 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 330 } 331 else if (Op->Asl.AmlPkgLenBytes != 0) 332 { 333 /* 334 * Encode the "bytes to follow" in the first byte, top two bits. 335 * The low-order nybble of the length is in the bottom 4 bits 336 */ 337 PkgLenFirstByte = (UINT8) 338 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 339 (PkgLen.LenBytes[0] & 0x0F)); 340 341 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 342 343 /* 344 * Shift the length over by the 4 bits we just stuffed 345 * in the first byte 346 */ 347 PkgLen.Len >>= 4; 348 349 /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */ 350 351 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++) 352 { 353 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1); 354 } 355 } 356 } 357 358 switch (Aml.Opcode) 359 { 360 case AML_BYTE_OP: 361 362 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1); 363 break; 364 365 case AML_WORD_OP: 366 367 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2); 368 break; 369 370 case AML_DWORD_OP: 371 372 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4); 373 break; 374 375 case AML_QWORD_OP: 376 377 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8); 378 break; 379 380 case AML_STRING_OP: 381 382 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 383 break; 384 385 default: 386 387 /* All data opcodes must appear above */ 388 389 break; 390 } 391 } 392 393 394 /******************************************************************************* 395 * 396 * FUNCTION: CgWriteTableHeader 397 * 398 * PARAMETERS: Op - The DEFINITIONBLOCK node 399 * 400 * RETURN: None 401 * 402 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 403 * 404 ******************************************************************************/ 405 406 static void 407 CgWriteTableHeader ( 408 ACPI_PARSE_OBJECT *Op) 409 { 410 ACPI_PARSE_OBJECT *Child; 411 412 413 /* AML filename */ 414 415 Child = Op->Asl.Child; 416 417 /* Signature */ 418 419 Child = Child->Asl.Next; 420 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 421 422 /* Revision */ 423 424 Child = Child->Asl.Next; 425 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 426 427 /* Command-line Revision override */ 428 429 if (Gbl_RevisionOverride) 430 { 431 TableHeader.Revision = Gbl_RevisionOverride; 432 } 433 434 /* OEMID */ 435 436 Child = Child->Asl.Next; 437 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 438 439 /* OEM TableID */ 440 441 Child = Child->Asl.Next; 442 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 443 444 /* OEM Revision */ 445 446 Child = Child->Asl.Next; 447 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 448 449 /* Compiler ID */ 450 451 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 452 453 /* Compiler version */ 454 455 TableHeader.AslCompilerRevision = ASL_REVISION; 456 457 /* Table length. Checksum zero for now, will rewrite later */ 458 459 TableHeader.Length = Gbl_TableLength; 460 TableHeader.Checksum = 0; 461 462 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 463 } 464 465 466 /******************************************************************************* 467 * 468 * FUNCTION: CgCloseTable 469 * 470 * PARAMETERS: None. 471 * 472 * RETURN: None. 473 * 474 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 475 * re-writing the header. 476 * 477 ******************************************************************************/ 478 479 static void 480 CgCloseTable ( 481 void) 482 { 483 signed char Sum; 484 UINT8 FileByte; 485 486 487 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 488 Sum = 0; 489 490 /* Calculate the checksum over the entire file */ 491 492 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 493 { 494 Sum = (signed char) (Sum + FileByte); 495 } 496 497 /* Re-write the table header with the checksum */ 498 499 TableHeader.Checksum = (UINT8) (0 - Sum); 500 501 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 502 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 503 } 504 505 506 /******************************************************************************* 507 * 508 * FUNCTION: CgWriteNode 509 * 510 * PARAMETERS: Op - Parse node to write. 511 * 512 * RETURN: None. 513 * 514 * DESCRIPTION: Write the AML that corresponds to a parse node. 515 * 516 ******************************************************************************/ 517 518 static void 519 CgWriteNode ( 520 ACPI_PARSE_OBJECT *Op) 521 { 522 ASL_RESOURCE_NODE *Rnode; 523 524 525 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 526 /* TBD: this may not be the best place for this check */ 527 528 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 529 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 530 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 531 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 532 { 533 return; 534 } 535 536 Op->Asl.FinalAmlLength = 0; 537 538 switch (Op->Asl.AmlOpcode) 539 { 540 case AML_RAW_DATA_BYTE: 541 case AML_RAW_DATA_WORD: 542 case AML_RAW_DATA_DWORD: 543 case AML_RAW_DATA_QWORD: 544 545 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 546 return; 547 548 549 case AML_RAW_DATA_BUFFER: 550 551 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 552 return; 553 554 555 case AML_RAW_DATA_CHAIN: 556 557 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 558 while (Rnode) 559 { 560 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 561 Rnode = Rnode->Next; 562 } 563 return; 564 565 default: 566 567 /* Internal data opcodes must all appear above */ 568 569 break; 570 } 571 572 switch (Op->Asl.ParseOpcode) 573 { 574 case PARSEOP_DEFAULT_ARG: 575 576 break; 577 578 case PARSEOP_DEFINITIONBLOCK: 579 580 CgWriteTableHeader (Op); 581 break; 582 583 case PARSEOP_NAMESEG: 584 case PARSEOP_NAMESTRING: 585 case PARSEOP_METHODCALL: 586 587 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 588 break; 589 590 default: 591 592 CgWriteAmlOpcode (Op); 593 break; 594 } 595 }