1 /****************************************************************************** 2 * 3 * Module Name: aslcodegen - AML code generation 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 <contrib/dev/acpica/compiler/aslcompiler.h> 46 #include "aslcompiler.y.h" 47 #include <contrib/dev/acpica/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 Aml.Opcode = Op->Asl.AmlOpcode; 288 break; 289 } 290 291 292 switch (Aml.Opcode) 293 { 294 case AML_PACKAGE_LENGTH: 295 296 /* Value is the length to be encoded (Used in field definitions) */ 297 298 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 299 break; 300 301 default: 302 303 /* Check for two-byte opcode */ 304 305 if (Aml.Opcode > 0x00FF) 306 { 307 /* Write the high byte first */ 308 309 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 310 } 311 312 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 313 314 /* Subtreelength doesn't include length of package length bytes */ 315 316 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 317 break; 318 } 319 320 /* Does this opcode have an associated "PackageLength" field? */ 321 322 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 323 { 324 if (Op->Asl.AmlPkgLenBytes == 1) 325 { 326 /* Simplest case -- no bytes to follow, just write the count */ 327 328 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 329 } 330 else if (Op->Asl.AmlPkgLenBytes != 0) 331 { 332 /* 333 * Encode the "bytes to follow" in the first byte, top two bits. 334 * The low-order nybble of the length is in the bottom 4 bits 335 */ 336 PkgLenFirstByte = (UINT8) 337 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 338 (PkgLen.LenBytes[0] & 0x0F)); 339 340 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 341 342 /* 343 * Shift the length over by the 4 bits we just stuffed 344 * in the first byte 345 */ 346 PkgLen.Len >>= 4; 347 348 /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */ 349 350 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++) 351 { 352 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1); 353 } 354 } 355 } 356 357 switch (Aml.Opcode) 358 { 359 case AML_BYTE_OP: 360 361 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1); 362 break; 363 364 case AML_WORD_OP: 365 366 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2); 367 break; 368 369 case AML_DWORD_OP: 370 371 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4); 372 break; 373 374 case AML_QWORD_OP: 375 376 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8); 377 break; 378 379 case AML_STRING_OP: 380 381 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 382 break; 383 384 default: 385 /* All data opcodes must appear above */ 386 break; 387 } 388 } 389 390 391 /******************************************************************************* 392 * 393 * FUNCTION: CgWriteTableHeader 394 * 395 * PARAMETERS: Op - The DEFINITIONBLOCK node 396 * 397 * RETURN: None 398 * 399 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 400 * 401 ******************************************************************************/ 402 403 static void 404 CgWriteTableHeader ( 405 ACPI_PARSE_OBJECT *Op) 406 { 407 ACPI_PARSE_OBJECT *Child; 408 409 410 /* AML filename */ 411 412 Child = Op->Asl.Child; 413 414 /* Signature */ 415 416 Child = Child->Asl.Next; 417 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 418 419 /* Revision */ 420 421 Child = Child->Asl.Next; 422 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 423 424 /* Command-line Revision override */ 425 426 if (Gbl_RevisionOverride) 427 { 428 TableHeader.Revision = Gbl_RevisionOverride; 429 } 430 431 /* OEMID */ 432 433 Child = Child->Asl.Next; 434 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 435 436 /* OEM TableID */ 437 438 Child = Child->Asl.Next; 439 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 440 441 /* OEM Revision */ 442 443 Child = Child->Asl.Next; 444 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 445 446 /* Compiler ID */ 447 448 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 449 450 /* Compiler version */ 451 452 TableHeader.AslCompilerRevision = ASL_REVISION; 453 454 /* Table length. Checksum zero for now, will rewrite later */ 455 456 TableHeader.Length = Gbl_TableLength; 457 TableHeader.Checksum = 0; 458 459 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 460 } 461 462 463 /******************************************************************************* 464 * 465 * FUNCTION: CgCloseTable 466 * 467 * PARAMETERS: None. 468 * 469 * RETURN: None. 470 * 471 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 472 * re-writing the header. 473 * 474 ******************************************************************************/ 475 476 static void 477 CgCloseTable ( 478 void) 479 { 480 signed char Sum; 481 UINT8 FileByte; 482 483 484 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 485 Sum = 0; 486 487 /* Calculate the checksum over the entire file */ 488 489 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 490 { 491 Sum = (signed char) (Sum + FileByte); 492 } 493 494 /* Re-write the table header with the checksum */ 495 496 TableHeader.Checksum = (UINT8) (0 - Sum); 497 498 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 499 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 500 } 501 502 503 /******************************************************************************* 504 * 505 * FUNCTION: CgWriteNode 506 * 507 * PARAMETERS: Op - Parse node to write. 508 * 509 * RETURN: None. 510 * 511 * DESCRIPTION: Write the AML that corresponds to a parse node. 512 * 513 ******************************************************************************/ 514 515 static void 516 CgWriteNode ( 517 ACPI_PARSE_OBJECT *Op) 518 { 519 ASL_RESOURCE_NODE *Rnode; 520 521 522 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 523 /* TBD: this may not be the best place for this check */ 524 525 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 526 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 527 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 528 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 529 { 530 return; 531 } 532 533 Op->Asl.FinalAmlLength = 0; 534 535 switch (Op->Asl.AmlOpcode) 536 { 537 case AML_RAW_DATA_BYTE: 538 case AML_RAW_DATA_WORD: 539 case AML_RAW_DATA_DWORD: 540 case AML_RAW_DATA_QWORD: 541 542 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 543 return; 544 545 546 case AML_RAW_DATA_BUFFER: 547 548 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 549 return; 550 551 552 case AML_RAW_DATA_CHAIN: 553 554 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 555 while (Rnode) 556 { 557 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 558 Rnode = Rnode->Next; 559 } 560 return; 561 562 default: 563 /* Internal data opcodes must all appear above */ 564 break; 565 } 566 567 switch (Op->Asl.ParseOpcode) 568 { 569 case PARSEOP_DEFAULT_ARG: 570 571 break; 572 573 case PARSEOP_DEFINITIONBLOCK: 574 575 CgWriteTableHeader (Op); 576 break; 577 578 case PARSEOP_NAMESEG: 579 case PARSEOP_NAMESTRING: 580 case PARSEOP_METHODCALL: 581 582 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 583 break; 584 585 default: 586 587 CgWriteAmlOpcode (Op); 588 break; 589 } 590 } 591