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 #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 CgCloseTable (); 111 } 112 113 114 /******************************************************************************* 115 * 116 * FUNCTION: CgAmlWriteWalk 117 * 118 * PARAMETERS: ASL_WALK_CALLBACK 119 * 120 * RETURN: Status 121 * 122 * DESCRIPTION: Parse tree walk to generate the AML code. 123 * 124 ******************************************************************************/ 125 126 static ACPI_STATUS 127 CgAmlWriteWalk ( 128 ACPI_PARSE_OBJECT *Op, 129 UINT32 Level, 130 void *Context) 131 { 132 133 /* 134 * Print header at level 0. Alignment assumes 32-bit pointers 135 */ 136 if (!Level) 137 { 138 DbgPrint (ASL_TREE_OUTPUT, 139 "Final parse tree used for AML output:\n"); 140 DbgPrint (ASL_TREE_OUTPUT, 141 "%*s Value P_Op A_Op OpLen PByts Len SubLen PSubLen OpPtr Child Parent Flags AcTyp Final Col L\n", 142 76, " "); 143 } 144 145 /* Debug output */ 146 147 DbgPrint (ASL_TREE_OUTPUT, 148 "%5.5d [%2d]", Op->Asl.LogicalLineNumber, Level); 149 UtPrintFormattedName (Op->Asl.ParseOpcode, Level); 150 151 if (Op->Asl.ParseOpcode == PARSEOP_NAMESEG || 152 Op->Asl.ParseOpcode == PARSEOP_NAMESTRING || 153 Op->Asl.ParseOpcode == PARSEOP_METHODCALL) 154 { 155 DbgPrint (ASL_TREE_OUTPUT, 156 "%10.32s ", Op->Asl.ExternalName); 157 } 158 else 159 { 160 DbgPrint (ASL_TREE_OUTPUT, " "); 161 } 162 163 DbgPrint (ASL_TREE_OUTPUT, 164 "%08X %04X %04X %01X %04X %04X %04X %04X %08X %08X %08X %08X %08X %04X %02d %02d\n", 165 /* 1 */ (UINT32) Op->Asl.Value.Integer, 166 /* 2 */ Op->Asl.ParseOpcode, 167 /* 3 */ Op->Asl.AmlOpcode, 168 /* 4 */ Op->Asl.AmlOpcodeLength, 169 /* 5 */ Op->Asl.AmlPkgLenBytes, 170 /* 6 */ Op->Asl.AmlLength, 171 /* 7 */ Op->Asl.AmlSubtreeLength, 172 /* 8 */ Op->Asl.Parent ? Op->Asl.Parent->Asl.AmlSubtreeLength : 0, 173 /* 9 */ Op, 174 /* 10 */ Op->Asl.Child, 175 /* 11 */ Op->Asl.Parent, 176 /* 12 */ Op->Asl.CompileFlags, 177 /* 13 */ Op->Asl.AcpiBtype, 178 /* 14 */ Op->Asl.FinalAmlLength, 179 /* 15 */ Op->Asl.Column, 180 /* 16 */ Op->Asl.LineNumber); 181 182 /* Generate the AML for this node */ 183 184 CgWriteNode (Op); 185 return (AE_OK); 186 } 187 188 189 /******************************************************************************* 190 * 191 * FUNCTION: CgLocalWriteAmlData 192 * 193 * PARAMETERS: Op - Current parse op 194 * Buffer - Buffer to write 195 * Length - Size of data in buffer 196 * 197 * RETURN: None 198 * 199 * DESCRIPTION: Write a buffer of AML data to the AML output file. 200 * 201 ******************************************************************************/ 202 203 static void 204 CgLocalWriteAmlData ( 205 ACPI_PARSE_OBJECT *Op, 206 void *Buffer, 207 UINT32 Length) 208 { 209 210 /* Write the raw data to the AML file */ 211 212 FlWriteFile (ASL_FILE_AML_OUTPUT, Buffer, Length); 213 214 /* Update the final AML length for this node (used for listings) */ 215 216 if (Op) 217 { 218 Op->Asl.FinalAmlLength += Length; 219 } 220 } 221 222 223 /******************************************************************************* 224 * 225 * FUNCTION: CgWriteAmlOpcode 226 * 227 * PARAMETERS: Op - Parse node with an AML opcode 228 * 229 * RETURN: None. 230 * 231 * DESCRIPTION: Write the AML opcode corresponding to a parse node. 232 * 233 ******************************************************************************/ 234 235 static void 236 CgWriteAmlOpcode ( 237 ACPI_PARSE_OBJECT *Op) 238 { 239 UINT8 PkgLenFirstByte; 240 UINT32 i; 241 union { 242 UINT16 Opcode; 243 UINT8 OpcodeBytes[2]; 244 } Aml; 245 union { 246 UINT32 Len; 247 UINT8 LenBytes[4]; 248 } PkgLen; 249 250 251 /* We expect some DEFAULT_ARGs, just ignore them */ 252 253 if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) 254 { 255 return; 256 } 257 258 switch (Op->Asl.AmlOpcode) 259 { 260 case AML_UNASSIGNED_OPCODE: 261 262 /* These opcodes should not get here */ 263 264 printf ("Found a node with an unassigned AML opcode\n"); 265 FlPrintFile (ASL_FILE_STDERR, "Found a node with an unassigned AML opcode\n"); 266 return; 267 268 case AML_INT_RESERVEDFIELD_OP: 269 270 /* Special opcodes for within a field definition */ 271 272 Aml.Opcode = AML_FIELD_OFFSET_OP; 273 break; 274 275 case AML_INT_ACCESSFIELD_OP: 276 277 Aml.Opcode = AML_FIELD_ACCESS_OP; 278 break; 279 280 case AML_INT_CONNECTION_OP: 281 282 Aml.Opcode = AML_FIELD_CONNECTION_OP; 283 break; 284 285 default: 286 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 386 /* All data opcodes must appear above */ 387 388 break; 389 } 390 } 391 392 393 /******************************************************************************* 394 * 395 * FUNCTION: CgWriteTableHeader 396 * 397 * PARAMETERS: Op - The DEFINITIONBLOCK node 398 * 399 * RETURN: None 400 * 401 * DESCRIPTION: Write a table header corresponding to the DEFINITIONBLOCK 402 * 403 ******************************************************************************/ 404 405 static void 406 CgWriteTableHeader ( 407 ACPI_PARSE_OBJECT *Op) 408 { 409 ACPI_PARSE_OBJECT *Child; 410 411 412 /* AML filename */ 413 414 Child = Op->Asl.Child; 415 416 /* Signature */ 417 418 Child = Child->Asl.Next; 419 strncpy (TableHeader.Signature, Child->Asl.Value.String, 4); 420 421 /* Revision */ 422 423 Child = Child->Asl.Next; 424 TableHeader.Revision = (UINT8) Child->Asl.Value.Integer; 425 426 /* Command-line Revision override */ 427 428 if (Gbl_RevisionOverride) 429 { 430 TableHeader.Revision = Gbl_RevisionOverride; 431 } 432 433 /* OEMID */ 434 435 Child = Child->Asl.Next; 436 strncpy (TableHeader.OemId, Child->Asl.Value.String, 6); 437 438 /* OEM TableID */ 439 440 Child = Child->Asl.Next; 441 strncpy (TableHeader.OemTableId, Child->Asl.Value.String, 8); 442 443 /* OEM Revision */ 444 445 Child = Child->Asl.Next; 446 TableHeader.OemRevision = (UINT32) Child->Asl.Value.Integer; 447 448 /* Compiler ID */ 449 450 ACPI_MOVE_NAME (TableHeader.AslCompilerId, ASL_CREATOR_ID); 451 452 /* Compiler version */ 453 454 TableHeader.AslCompilerRevision = ASL_REVISION; 455 456 /* Table length. Checksum zero for now, will rewrite later */ 457 458 TableHeader.Length = Gbl_TableLength; 459 TableHeader.Checksum = 0; 460 461 CgLocalWriteAmlData (Op, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 462 } 463 464 465 /******************************************************************************* 466 * 467 * FUNCTION: CgCloseTable 468 * 469 * PARAMETERS: None. 470 * 471 * RETURN: None. 472 * 473 * DESCRIPTION: Complete the ACPI table by calculating the checksum and 474 * re-writing the header. 475 * 476 ******************************************************************************/ 477 478 static void 479 CgCloseTable ( 480 void) 481 { 482 signed char Sum; 483 UINT8 FileByte; 484 485 486 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 487 Sum = 0; 488 489 /* Calculate the checksum over the entire file */ 490 491 while (FlReadFile (ASL_FILE_AML_OUTPUT, &FileByte, 1) == AE_OK) 492 { 493 Sum = (signed char) (Sum + FileByte); 494 } 495 496 /* Re-write the table header with the checksum */ 497 498 TableHeader.Checksum = (UINT8) (0 - Sum); 499 500 FlSeekFile (ASL_FILE_AML_OUTPUT, 0); 501 CgLocalWriteAmlData (NULL, &TableHeader, sizeof (ACPI_TABLE_HEADER)); 502 } 503 504 505 /******************************************************************************* 506 * 507 * FUNCTION: CgWriteNode 508 * 509 * PARAMETERS: Op - Parse node to write. 510 * 511 * RETURN: None. 512 * 513 * DESCRIPTION: Write the AML that corresponds to a parse node. 514 * 515 ******************************************************************************/ 516 517 static void 518 CgWriteNode ( 519 ACPI_PARSE_OBJECT *Op) 520 { 521 ASL_RESOURCE_NODE *Rnode; 522 523 524 /* Always check for DEFAULT_ARG and other "Noop" nodes */ 525 /* TBD: this may not be the best place for this check */ 526 527 if ((Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) || 528 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || 529 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE) || 530 (Op->Asl.ParseOpcode == PARSEOP_INCLUDE_END)) 531 { 532 return; 533 } 534 535 Op->Asl.FinalAmlLength = 0; 536 537 switch (Op->Asl.AmlOpcode) 538 { 539 case AML_RAW_DATA_BYTE: 540 case AML_RAW_DATA_WORD: 541 case AML_RAW_DATA_DWORD: 542 case AML_RAW_DATA_QWORD: 543 544 CgLocalWriteAmlData (Op, &Op->Asl.Value.Integer, Op->Asl.AmlLength); 545 return; 546 547 548 case AML_RAW_DATA_BUFFER: 549 550 CgLocalWriteAmlData (Op, Op->Asl.Value.Buffer, Op->Asl.AmlLength); 551 return; 552 553 554 case AML_RAW_DATA_CHAIN: 555 556 Rnode = ACPI_CAST_PTR (ASL_RESOURCE_NODE, Op->Asl.Value.Buffer); 557 while (Rnode) 558 { 559 CgLocalWriteAmlData (Op, Rnode->Buffer, Rnode->BufferLength); 560 Rnode = Rnode->Next; 561 } 562 return; 563 564 default: 565 566 /* Internal data opcodes must all appear above */ 567 568 break; 569 } 570 571 switch (Op->Asl.ParseOpcode) 572 { 573 case PARSEOP_DEFAULT_ARG: 574 575 break; 576 577 case PARSEOP_DEFINITIONBLOCK: 578 579 CgWriteTableHeader (Op); 580 break; 581 582 case PARSEOP_NAMESEG: 583 case PARSEOP_NAMESTRING: 584 case PARSEOP_METHODCALL: 585 586 CgLocalWriteAmlData (Op, Op->Asl.Value.String, Op->Asl.AmlLength); 587 break; 588 589 default: 590 591 CgWriteAmlOpcode (Op); 592 break; 593 } 594 } 595