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 <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 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\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\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\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 191 /* Generate the AML for this node */ 192 193 CgWriteNode (Op); 194 return (AE_OK); 195 } 196 197 198 /******************************************************************************* 199 * 200 * FUNCTION: CgLocalWriteAmlData 201 * 202 * PARAMETERS: Op - Current parse op 203 * Buffer - Buffer to write 204 * Length - Size of data in buffer 205 * 206 * RETURN: None 207 * 208 * DESCRIPTION: Write a buffer of AML data to the AML output file. 209 * 210 ******************************************************************************/ 211 212 static void 213 CgLocalWriteAmlData ( 214 ACPI_PARSE_OBJECT *Op, 215 void *Buffer, 216 UINT32 Length) 217 { 218 219 /* Write the raw data to the AML file */ 220 221 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length); 222 223 /* Update the final AML length for this node (used for listings) */ 224 225 if (Op) 226 { 227 Op->Asl.FinalAmlLength += Length; 228 } 229 } 230 231 232 /******************************************************************************* 233 * 234 * FUNCTION: CgWriteAmlOpcode 235 * 236 * PARAMETERS: Op - Parse node with an AML opcode 237 * 238 * RETURN: None. 239 * 240 * DESCRIPTION: Write the AML opcode corresponding to a parse node. 241 * 242 ******************************************************************************/ 243 244 static void 245 CgWriteAmlOpcode ( 246 ACPI_PARSE_OBJECT *Op) 247 { 248 UINT8 PkgLenFirstByte; 249 UINT32 i; 250 union { 251 UINT16 Opcode; 252 UINT8 OpcodeBytes[2]; 253 } Aml; 254 union { 255 UINT32 Len; 256 UINT8 LenBytes[4]; 257 } PkgLen; 258 259 260 /* We expect some DEFAULT_ARGs, just ignore them */ 261 262 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 263 { 264 return; 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, "Found a node with an unassigned AML opcode\n"); 275 return; 276 277 case AML_INT_RESERVEDFIELD_OP: 278 279 /* Special opcodes for within a field definition */ 280 281 Aml.Opcode = AML_FIELD_OFFSET_OP; 282 break; 283 284 case AML_INT_ACCESSFIELD_OP: 285 286 Aml.Opcode = AML_FIELD_ACCESS_OP; 287 break; 288 289 case AML_INT_CONNECTION_OP: 290 291 Aml.Opcode = AML_FIELD_CONNECTION_OP; 292 break; 293 294 default: 295 296 Aml.Opcode = Op->Asl.AmlOpcode; 297 break; 298 } 299 300 301 switch (Aml.Opcode) 302 { 303 case AML_PACKAGE_LENGTH: 304 305 /* Value is the length to be encoded (Used in field definitions) */ 306 307 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 308 break; 309 310 default: 311 312 /* Check for two-byte opcode */ 313 314 if (Aml.Opcode > 0x00FF) 315 { 316 /* Write the high byte first */ 317 318 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 319 } 320 321 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 322 323 /* Subtreelength doesn't include length of package length bytes */ 324 325 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 326 break; 327 } 328 329 /* Does this opcode have an associated "PackageLength" field? */ 330 331 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 332 { 333 if (Op->Asl.AmlPkgLenBytes == 1) 334 { 335 /* Simplest case -- no bytes to follow, just write the count */ 336 337 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 338 } 339 else if (Op->Asl.AmlPkgLenBytes != 0) 340 { 341 /* 342 * Encode the "bytes to follow" in the first byte, top two bits. 343 * The low-order nybble of the length is in the bottom 4 bits 344 */ 345 PkgLenFirstByte = (UINT8) 346 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 347 (PkgLen.LenBytes[0] & 0x0F)); 348 349 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 350 351 /* 352 * Shift the length over by the 4 bits we just stuffed 353 * in the first byte 354 */ 355 PkgLen.Len >>= 4; 356 357 /* Now we can write the remaining bytes - 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 = Gbl_TableLength; 468 TableHeader.Checksum = 0; 469 470 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 471 } 472 473 474 /******************************************************************************* 475 * 476 * FUNCTION: CgCloseTable 477 * 478 * PARAMETERS: None. 479 * 480 * RETURN: None. 481 * 482 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 483 * re-writing the header. 484 * 485 ******************************************************************************/ 486 487 static void 488 CgCloseTable ( 489 void) 490 { 491 signed char Sum; 492 UINT8 FileByte; 493 494 495 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 496 Sum = 0; 497 498 /* Calculate the checksum over the entire file */ 499 500 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 501 { 502 Sum = (signed char) (Sum + FileByte); 503 } 504 505 /* Re-write the table header with the checksum */ 506 507 TableHeader.Checksum = (UINT8) (0 - Sum); 508 509 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 510 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 511 } 512 513 514 /******************************************************************************* 515 * 516 * FUNCTION: CgWriteNode 517 * 518 * PARAMETERS: Op - Parse node to write. 519 * 520 * RETURN: None. 521 * 522 * DESCRIPTION: Write the AML that corresponds to a parse node. 523 * 524 ******************************************************************************/ 525 526 static void 527 CgWriteNode ( 528 ACPI_PARSE_OBJECT *Op) 529 { 530 ASL_RESOURCE_NODE *Rnode; 531 532 533 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 534 /* TBD: this may not be the best place for this check */ 535 536 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 537 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 538 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 539 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 540 { 541 return; 542 } 543 544 Op->Asl.FinalAmlLength = 0; 545 546 switch (Op->Asl.AmlOpcode) 547 { 548 case AML_RAW_DATA_BYTE: 549 case AML_RAW_DATA_WORD: 550 case AML_RAW_DATA_DWORD: 551 case AML_RAW_DATA_QWORD: 552 553 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 554 return; 555 556 557 case AML_RAW_DATA_BUFFER: 558 559 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 560 return; 561 562 563 case AML_RAW_DATA_CHAIN: 564 565 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 566 while (Rnode) 567 { 568 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 569 Rnode = Rnode->Next; 570 } 571 return; 572 573 default: 574 575 /* Internal data opcodes must all appear above */ 576 577 break; 578 } 579 580 switch (Op->Asl.ParseOpcode) 581 { 582 case PARSEOP_DEFAULT_ARG: 583 584 break; 585 586 case PARSEOP_DEFINITIONBLOCK: 587 588 CgWriteTableHeader (Op); 589 break; 590 591 case PARSEOP_NAMESEG: 592 case PARSEOP_NAMESTRING: 593 case PARSEOP_METHODCALL: 594 595 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 596 break; 597 598 default: 599 600 CgWriteAmlOpcode (Op); 601 break; 602 } 603 } 604