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 = AML_FIELD_OFFSET_OP; 275 break; 276 277 case AML_INT_ACCESSFIELD_OP: 278 279 Aml.Opcode = AML_FIELD_ACCESS_OP; 280 break; 281 282 case AML_INT_CONNECTION_OP: 283 284 Aml.Opcode = AML_FIELD_CONNECTION_OP; 285 break; 286 287 default: 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 /* All data opcodes must appear above */ 387 break; 388 } 389 } 390 391 392 /******************************************************************************* 393 * 394 * FUNCTION: CgWriteTableHeader 395 * 396 * PARAMETERS: Op - The DEFINITIONBLOCK node 397 * 398 * RETURN: None 399 * 400 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 401 * 402 ******************************************************************************/ 403 404 static void 405 CgWriteTableHeader ( 406 ACPI_PARSE_OBJECT *Op) 407 { 408 ACPI_PARSE_OBJECT *Child; 409 410 411 /* AML filename */ 412 413 Child = Op->Asl.Child; 414 415 /* Signature */ 416 417 Child = Child->Asl.Next; 418 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 419 420 /* Revision */ 421 422 Child = Child->Asl.Next; 423 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 424 425 /* Command-line Revision override */ 426 427 if (Gbl_RevisionOverride) 428 { 429 TableHeader.Revision = Gbl_RevisionOverride; 430 } 431 432 /* OEMID */ 433 434 Child = Child->Asl.Next; 435 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 436 437 /* OEM TableID */ 438 439 Child = Child->Asl.Next; 440 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 441 442 /* OEM Revision */ 443 444 Child = Child->Asl.Next; 445 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 446 447 /* Compiler ID */ 448 449 strncpy (TableHeader.AslCompilerId, ASL_CREATOR_ID, 4); 450 451 /* Compiler version */ 452 453 TableHeader.AslCompilerRevision = ASL_REVISION; 454 455 /* Table length. Checksum zero for now, will rewrite later */ 456 457 TableHeader.Length = Gbl_TableLength; 458 TableHeader.Checksum = 0; 459 460 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 461 } 462 463 464 /******************************************************************************* 465 * 466 * FUNCTION: CgCloseTable 467 * 468 * PARAMETERS: None. 469 * 470 * RETURN: None. 471 * 472 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 473 * re-writing the header. 474 * 475 ******************************************************************************/ 476 477 static void 478 CgCloseTable ( 479 void) 480 { 481 signed char Sum; 482 UINT8 FileByte; 483 484 485 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 486 Sum = 0; 487 488 /* Calculate the checksum over the entire file */ 489 490 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 491 { 492 Sum = (signed char) (Sum + FileByte); 493 } 494 495 /* Re-write the table header with the checksum */ 496 497 TableHeader.Checksum = (UINT8) (0 - Sum); 498 499 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 500 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 501 } 502 503 504 /******************************************************************************* 505 * 506 * FUNCTION: CgWriteNode 507 * 508 * PARAMETERS: Op - Parse node to write. 509 * 510 * RETURN: None. 511 * 512 * DESCRIPTION: Write the AML that corresponds to a parse node. 513 * 514 ******************************************************************************/ 515 516 static void 517 CgWriteNode ( 518 ACPI_PARSE_OBJECT *Op) 519 { 520 ASL_RESOURCE_NODE *Rnode; 521 522 523 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 524 /* TBD: this may not be the best place for this check */ 525 526 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 527 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 528 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 529 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 530 { 531 return; 532 } 533 534 Op->Asl.FinalAmlLength = 0; 535 536 switch (Op->Asl.AmlOpcode) 537 { 538 case AML_RAW_DATA_BYTE: 539 case AML_RAW_DATA_WORD: 540 case AML_RAW_DATA_DWORD: 541 case AML_RAW_DATA_QWORD: 542 543 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 544 return; 545 546 547 case AML_RAW_DATA_BUFFER: 548 549 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 550 return; 551 552 553 case AML_RAW_DATA_CHAIN: 554 555 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 556 while (Rnode) 557 { 558 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 559 Rnode = Rnode->Next; 560 } 561 return; 562 563 default: 564 /* Internal data opcodes must all appear above */ 565 break; 566 } 567 568 switch (Op->Asl.ParseOpcode) 569 { 570 case PARSEOP_DEFAULT_ARG: 571 572 break; 573 574 case PARSEOP_DEFINITIONBLOCK: 575 576 CgWriteTableHeader (Op); 577 break; 578 579 case PARSEOP_NAMESEG: 580 case PARSEOP_NAMESTRING: 581 case PARSEOP_METHODCALL: 582 583 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 584 break; 585 586 default: 587 588 CgWriteAmlOpcode (Op); 589 break; 590 } 591 } 592 593 594