1 2 /****************************************************************************** 3 * 4 * Module Name: aslcodegen - AML code generation 5 * 6 *****************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2011, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 46 #include <contrib/dev/acpica/compiler/aslcompiler.h> 47 #include "aslcompiler.y.h" 48 #include <contrib/dev/acpica/include/amlcode.h> 49 50 #define _COMPONENT ACPI_COMPILER 51 ACPI_MODULE_NAME ("aslcodegen") 52 53 /* Local prototypes */ 54 55 static ACPI_STATUS 56 CgAmlWriteWalk ( 57 ACPI_PARSE_OBJECT *Op, 58 UINT32 Level, 59 void *Context); 60 61 static void 62 CgLocalWriteAmlData ( 63 ACPI_PARSE_OBJECT *Op, 64 void *Buffer, 65 UINT32 Length); 66 67 static void 68 CgWriteAmlOpcode ( 69 ACPI_PARSE_OBJECT *Op); 70 71 static void 72 CgWriteTableHeader ( 73 ACPI_PARSE_OBJECT *Op); 74 75 static void 76 CgCloseTable ( 77 void); 78 79 static void 80 CgWriteNode ( 81 ACPI_PARSE_OBJECT *Op); 82 83 84 /******************************************************************************* 85 * 86 * FUNCTION: CgGenerateAmlOutput 87 * 88 * PARAMETERS: None. 89 * 90 * RETURN: None 91 * 92 * DESCRIPTION: Generate AML code. Currently generates the listing file 93 * simultaneously. 94 * 95 ******************************************************************************/ 96 97 void 98 CgGenerateAmlOutput ( 99 void) 100 { 101 102 DbgPrint (ASL_DEBUG_OUTPUT, "\nWriting AML\n\n"); 103 104 /* Generate the AML output file */ 105 106 FlSeekFile (ASL_FILE_SOURCE_OUTPUT, 0); 107 Gbl_SourceLine = 0; 108 Gbl_NextError = Gbl_ErrorLog; 109 110 TrWalkParseTree (RootNode, ASL_WALK_VISIT_DOWNWARD, 111 CgAmlWriteWalk, NULL, NULL); 112 CgCloseTable (); 113 } 114 115 116 /******************************************************************************* 117 * 118 * FUNCTION: CgAmlWriteWalk 119 * 120 * PARAMETERS: ASL_WALK_CALLBACK 121 * 122 * RETURN: Status 123 * 124 * DESCRIPTION: Parse tree walk to generate the AML code. 125 * 126 ******************************************************************************/ 127 128 static ACPI_STATUS 129 CgAmlWriteWalk ( 130 ACPI_PARSE_OBJECT *Op, 131 UINT32 Level, 132 void *Context) 133 { 134 135 /* 136 * Print header at level 0. Alignment assumes 32-bit pointers 137 */ 138 if (!Level) 139 { 140 DbgPrint (ASL_TREE_OUTPUT, 141 "Final parse tree used for AML output:\n"); 142 DbgPrint (ASL_TREE_OUTPUT, 143 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr Child Parent Flags AcTyp Final Col L\n", 144 76, " "); 145 } 146 147 /* Debug output */ 148 149 DbgPrint (ASL_TREE_OUTPUT, 150 "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); 151 UtPrintFormattedName (Op->Asl.ParseOpcode, Level); 152 153 if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG || 154 Op->Asl.ParseOpcode == PARSEOP_NAMESTRING || 155 Op->Asl.ParseOpcode == PARSEOP_METHODCALL) 156 { 157 DbgPrint (ASL_TREE_OUTPUT, 158 "%10.32s ", Op->Asl.ExternalName); 159 } 160 else 161 { 162 DbgPrint (ASL_TREE_OUTPUT, " "); 163 } 164 165 DbgPrint (ASL_TREE_OUTPUT, 166 "%08X %04X %04X %01X %04X %04X %04X %04X %08X %08X %08X %08X %08X %04X %02d %02d\n", 167 /* 1 */ (UINT32) Op->Asl.Value.Integer, 168 /* 2 */ Op->Asl.ParseOpcode, 169 /* 3 */ Op->Asl.AmlOpcode, 170 /* 4 */ Op->Asl.AmlOpcodeLength, 171 /* 5 */ Op->Asl.AmlPkgLenBytes, 172 /* 6 */ Op->Asl.AmlLength, 173 /* 7 */ Op->Asl.AmlSubtreeLength, 174 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0, 175 /* 9 */ Op, 176 /* 10 */ Op->Asl.Child, 177 /* 11 */ Op->Asl.Parent, 178 /* 12 */ Op->Asl.CompileFlags, 179 /* 13 */ Op->Asl.AcpiBtype, 180 /* 14 */ Op->Asl.FinalAmlLength, 181 /* 15 */ Op->Asl.Column, 182 /* 16 */ Op->Asl.LineNumber); 183 184 /* Generate the AML for this node */ 185 186 CgWriteNode (Op); 187 return (AE_OK); 188 } 189 190 191 /******************************************************************************* 192 * 193 * FUNCTION: CgLocalWriteAmlData 194 * 195 * PARAMETERS: Op - Current parse op 196 * Buffer - Buffer to write 197 * Length - Size of data in buffer 198 * 199 * RETURN: None 200 * 201 * DESCRIPTION: Write a buffer of AML data to the AML output file. 202 * 203 ******************************************************************************/ 204 205 static void 206 CgLocalWriteAmlData ( 207 ACPI_PARSE_OBJECT *Op, 208 void *Buffer, 209 UINT32 Length) 210 { 211 212 /* Write the raw data to the AML file */ 213 214 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length); 215 216 /* Update the final AML length for this node (used for listings) */ 217 218 if (Op) 219 { 220 Op->Asl.FinalAmlLength += Length; 221 } 222 } 223 224 225 /******************************************************************************* 226 * 227 * FUNCTION: CgWriteAmlOpcode 228 * 229 * PARAMETERS: Op - Parse node with an AML opcode 230 * 231 * RETURN: None. 232 * 233 * DESCRIPTION: Write the AML opcode corresponding to a parse node. 234 * 235 ******************************************************************************/ 236 237 static void 238 CgWriteAmlOpcode ( 239 ACPI_PARSE_OBJECT *Op) 240 { 241 UINT8 PkgLenFirstByte; 242 UINT32 i; 243 union { 244 UINT16 Opcode; 245 UINT8 OpcodeBytes[2]; 246 } Aml; 247 union { 248 UINT32 Len; 249 UINT8 LenBytes[4]; 250 } PkgLen; 251 252 253 /* We expect some DEFAULT_ARGs, just ignore them */ 254 255 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 256 { 257 return; 258 } 259 260 switch (Op->Asl.AmlOpcode) 261 { 262 case AML_UNASSIGNED_OPCODE: 263 264 /* These opcodes should not get here */ 265 266 printf ("Found a node with an unassigned AML opcode\n"); 267 fprintf (stderr, "Found a node with an unassigned AML opcode\n"); 268 return; 269 270 case AML_INT_RESERVEDFIELD_OP: 271 272 /* Special opcodes for within a field definition */ 273 274 Aml.Opcode = 0x00; 275 break; 276 277 case AML_INT_ACCESSFIELD_OP: 278 279 Aml.Opcode = 0x01; 280 break; 281 282 default: 283 Aml.Opcode = Op->Asl.AmlOpcode; 284 break; 285 } 286 287 288 switch (Aml.Opcode) 289 { 290 case AML_PACKAGE_LENGTH: 291 292 /* Value is the length to be encoded (Used in field definitions) */ 293 294 PkgLen.Len = (UINT32) Op->Asl.Value.Integer; 295 break; 296 297 default: 298 299 /* Check for two-byte opcode */ 300 301 if (Aml.Opcode > 0x00FF) 302 { 303 /* Write the high byte first */ 304 305 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[1], 1); 306 } 307 308 CgLocalWriteAmlData (Op, &Aml.OpcodeBytes[0], 1); 309 310 /* Subtreelength doesn't include length of package length bytes */ 311 312 PkgLen.Len = Op->Asl.AmlSubtreeLength + Op->Asl.AmlPkgLenBytes; 313 break; 314 } 315 316 /* Does this opcode have an associated "PackageLength" field? */ 317 318 if (Op->Asl.CompileFlags & NODE_AML_PACKAGE) 319 { 320 if (Op->Asl.AmlPkgLenBytes == 1) 321 { 322 /* Simplest case -- no bytes to follow, just write the count */ 323 324 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[0], 1); 325 } 326 else if (Op->Asl.AmlPkgLenBytes != 0) 327 { 328 /* 329 * Encode the "bytes to follow" in the first byte, top two bits. 330 * The low-order nybble of the length is in the bottom 4 bits 331 */ 332 PkgLenFirstByte = (UINT8) 333 (((UINT32) (Op->Asl.AmlPkgLenBytes - 1) << 6) | 334 (PkgLen.LenBytes[0] & 0x0F)); 335 336 CgLocalWriteAmlData (Op, &PkgLenFirstByte, 1); 337 338 /* 339 * Shift the length over by the 4 bits we just stuffed 340 * in the first byte 341 */ 342 PkgLen.Len >>= 4; 343 344 /* Now we can write the remaining bytes - either 1, 2, or 3 bytes */ 345 346 for (i = 0; i < (UINT32) (Op->Asl.AmlPkgLenBytes - 1); i++) 347 { 348 CgLocalWriteAmlData (Op, &PkgLen.LenBytes[i], 1); 349 } 350 } 351 } 352 353 switch (Aml.Opcode) 354 { 355 case AML_BYTE_OP: 356 357 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 1); 358 break; 359 360 case AML_WORD_OP: 361 362 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 2); 363 break; 364 365 case AML_DWORD_OP: 366 367 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 4); 368 break; 369 370 case AML_QWORD_OP: 371 372 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, 8); 373 break; 374 375 case AML_STRING_OP: 376 377 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 378 break; 379 380 default: 381 /* All data opcodes must appear above */ 382 break; 383 } 384 } 385 386 387 /******************************************************************************* 388 * 389 * FUNCTION: CgWriteTableHeader 390 * 391 * PARAMETERS: Op - The DEFINITIONBLOCK node 392 * 393 * RETURN: None 394 * 395 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 396 * 397 ******************************************************************************/ 398 399 static void 400 CgWriteTableHeader ( 401 ACPI_PARSE_OBJECT *Op) 402 { 403 ACPI_PARSE_OBJECT *Child; 404 405 406 /* AML filename */ 407 408 Child = Op->Asl.Child; 409 410 /* Signature */ 411 412 Child = Child->Asl.Next; 413 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 414 415 /* Revision */ 416 417 Child = Child->Asl.Next; 418 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 419 420 /* Command-line Revision override */ 421 422 if (Gbl_RevisionOverride) 423 { 424 TableHeader.Revision = Gbl_RevisionOverride; 425 } 426 427 /* OEMID */ 428 429 Child = Child->Asl.Next; 430 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 431 432 /* OEM TableID */ 433 434 Child = Child->Asl.Next; 435 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 436 437 /* OEM Revision */ 438 439 Child = Child->Asl.Next; 440 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 441 442 /* Compiler ID */ 443 444 strncpy (TableHeader.AslCompilerId, ASL_CREATOR_ID, 4); 445 446 /* Compiler version */ 447 448 TableHeader.AslCompilerRevision = ASL_REVISION; 449 450 /* Table length. Checksum zero for now, will rewrite later */ 451 452 TableHeader.Length = Gbl_TableLength; 453 TableHeader.Checksum = 0; 454 455 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 456 } 457 458 459 /******************************************************************************* 460 * 461 * FUNCTION: CgCloseTable 462 * 463 * PARAMETERS: None. 464 * 465 * RETURN: None. 466 * 467 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 468 * re-writing the header. 469 * 470 ******************************************************************************/ 471 472 static void 473 CgCloseTable ( 474 void) 475 { 476 signed char Sum; 477 UINT8 FileByte; 478 479 480 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 481 Sum = 0; 482 483 /* Calculate the checksum over the entire file */ 484 485 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 486 { 487 Sum = (signed char) (Sum + FileByte); 488 } 489 490 /* Re-write the table header with the checksum */ 491 492 TableHeader.Checksum = (UINT8) (0 - Sum); 493 494 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 495 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 496 } 497 498 499 /******************************************************************************* 500 * 501 * FUNCTION: CgWriteNode 502 * 503 * PARAMETERS: Op - Parse node to write. 504 * 505 * RETURN: None. 506 * 507 * DESCRIPTION: Write the AML that corresponds to a parse node. 508 * 509 ******************************************************************************/ 510 511 static void 512 CgWriteNode ( 513 ACPI_PARSE_OBJECT *Op) 514 { 515 ASL_RESOURCE_NODE *Rnode; 516 517 518 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 519 /* TBD: this may not be the best place for this check */ 520 521 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 522 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 523 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 524 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 525 { 526 return; 527 } 528 529 Op->Asl.FinalAmlLength = 0; 530 531 switch (Op->Asl.AmlOpcode) 532 { 533 case AML_RAW_DATA_BYTE: 534 case AML_RAW_DATA_WORD: 535 case AML_RAW_DATA_DWORD: 536 case AML_RAW_DATA_QWORD: 537 538 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 539 return; 540 541 542 case AML_RAW_DATA_BUFFER: 543 544 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 545 return; 546 547 548 case AML_RAW_DATA_CHAIN: 549 550 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 551 while (Rnode) 552 { 553 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 554 Rnode = Rnode->Next; 555 } 556 return; 557 558 default: 559 /* Internal data opcodes must all appear above */ 560 break; 561 } 562 563 switch (Op->Asl.ParseOpcode) 564 { 565 case PARSEOP_DEFAULT_ARG: 566 567 break; 568 569 case PARSEOP_DEFINITIONBLOCK: 570 571 CgWriteTableHeader (Op); 572 break; 573 574 case PARSEOP_NAMESEG: 575 case PARSEOP_NAMESTRING: 576 case PARSEOP_METHODCALL: 577 578 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 579 break; 580 581 default: 582 583 CgWriteAmlOpcode (Op); 584 break; 585 } 586 } 587 588 589