1 /******************************************************************************* 2 * 3 * Module Name: dmcstyle - Support for C-style operator disassembly 4 * 5 ******************************************************************************/ 6 7 /****************************************************************************** 8 * 9 * 1. Copyright Notice 10 * 11 * Some or all of this work - Copyright (c) 1999 - 2020, Intel Corp. 12 * All rights reserved. 13 * 14 * 2. License 15 * 16 * 2.1. This is your license from Intel Corp. under its intellectual property 17 * rights. You may have additional license terms from the party that provided 18 * you this software, covering your right to use that party's intellectual 19 * property rights. 20 * 21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22 * copy of the source code appearing in this file ("Covered Code") an 23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24 * base code distributed originally by Intel ("Original Intel Code") to copy, 25 * make derivatives, distribute, use and display any portion of the Covered 26 * Code in any form, with the right to sublicense such rights; and 27 * 28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29 * license (with the right to sublicense), under only those claims of Intel 30 * patents that are infringed by the Original Intel Code, to make, use, sell, 31 * offer to sell, and import the Covered Code and derivative works thereof 32 * solely to the minimum extent necessary to exercise the above copyright 33 * license, and in no event shall the patent license extend to any additions 34 * to or modifications of the Original Intel Code. No other license or right 35 * is granted directly or by implication, estoppel or otherwise; 36 * 37 * The above copyright and patent license is granted only if the following 38 * conditions are met: 39 * 40 * 3. Conditions 41 * 42 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43 * Redistribution of source code of any substantial portion of the Covered 44 * Code or modification with rights to further distribute source must include 45 * the above Copyright Notice, the above License, this list of Conditions, 46 * and the following Disclaimer and Export Compliance provision. In addition, 47 * Licensee must cause all Covered Code to which Licensee contributes to 48 * contain a file documenting the changes Licensee made to create that Covered 49 * Code and the date of any change. Licensee must include in that file the 50 * documentation of any changes made by any predecessor Licensee. Licensee 51 * must include a prominent statement that the modification is derived, 52 * directly or indirectly, from Original Intel Code. 53 * 54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55 * Redistribution of source code of any substantial portion of the Covered 56 * Code or modification without rights to further distribute source must 57 * include the following Disclaimer and Export Compliance provision in the 58 * documentation and/or other materials provided with distribution. In 59 * addition, Licensee may not authorize further sublicense of source of any 60 * portion of the Covered Code, and must include terms to the effect that the 61 * license from Licensee to its licensee is limited to the intellectual 62 * property embodied in the software Licensee provides to its licensee, and 63 * not to intellectual property embodied in modifications its licensee may 64 * make. 65 * 66 * 3.3. Redistribution of Executable. Redistribution in executable form of any 67 * substantial portion of the Covered Code or modification must reproduce the 68 * above Copyright Notice, and the following Disclaimer and Export Compliance 69 * provision in the documentation and/or other materials provided with the 70 * distribution. 71 * 72 * 3.4. Intel retains all right, title, and interest in and to the Original 73 * Intel Code. 74 * 75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76 * Intel shall be used in advertising or otherwise to promote the sale, use or 77 * other dealings in products derived from or relating to the Covered Code 78 * without prior written authorization from Intel. 79 * 80 * 4. Disclaimer and Export Compliance 81 * 82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88 * PARTICULAR PURPOSE. 89 * 90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97 * LIMITED REMEDY. 98 * 99 * 4.3. Licensee shall not export, either directly or indirectly, any of this 100 * software or system incorporating such software without first obtaining any 101 * required license or other approval from the U. S. Department of Commerce or 102 * any other agency or department of the United States Government. In the 103 * event Licensee exports any such software from the United States or 104 * re-exports any such software from a foreign destination, Licensee shall 105 * ensure that the distribution and export/re-export of the software is in 106 * compliance with all laws, regulations, orders, or other restrictions of the 107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108 * any of its subsidiaries will export/re-export any technical data, process, 109 * software, or service, directly or indirectly, to any country for which the 110 * United States government or any agency thereof requires an export license, 111 * other governmental approval, or letter of assurance, without first obtaining 112 * such license, approval or letter. 113 * 114 ***************************************************************************** 115 * 116 * Alternatively, you may choose to be licensed under the terms of the 117 * following license: 118 * 119 * Redistribution and use in source and binary forms, with or without 120 * modification, are permitted provided that the following conditions 121 * are met: 122 * 1. Redistributions of source code must retain the above copyright 123 * notice, this list of conditions, and the following disclaimer, 124 * without modification. 125 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 126 * substantially similar to the "NO WARRANTY" disclaimer below 127 * ("Disclaimer") and any redistribution must be conditioned upon 128 * including a substantially similar Disclaimer requirement for further 129 * binary redistribution. 130 * 3. Neither the names of the above-listed copyright holders nor the names 131 * of any contributors may be used to endorse or promote products derived 132 * from this software without specific prior written permission. 133 * 134 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 135 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 136 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 137 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 138 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 139 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 140 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 141 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 142 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 143 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 144 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 145 * 146 * Alternatively, you may choose to be licensed under the terms of the 147 * GNU General Public License ("GPL") version 2 as published by the Free 148 * Software Foundation. 149 * 150 *****************************************************************************/ 151 152 #include "acpi.h" 153 #include "accommon.h" 154 #include "acparser.h" 155 #include "amlcode.h" 156 #include "acdebug.h" 157 #include "acconvert.h" 158 159 #ifdef ACPI_DISASSEMBLER 160 161 #define _COMPONENT ACPI_CA_DEBUGGER 162 ACPI_MODULE_NAME ("dmcstyle") 163 164 165 /* Local prototypes */ 166 167 static char * 168 AcpiDmGetCompoundSymbol ( 169 UINT16 AslOpcode); 170 171 static void 172 AcpiDmPromoteTarget ( 173 ACPI_PARSE_OBJECT *Op, 174 ACPI_PARSE_OBJECT *Target); 175 176 static BOOLEAN 177 AcpiDmIsValidTarget ( 178 ACPI_PARSE_OBJECT *Op); 179 180 static BOOLEAN 181 AcpiDmIsTargetAnOperand ( 182 ACPI_PARSE_OBJECT *Target, 183 ACPI_PARSE_OBJECT *Operand, 184 BOOLEAN TopLevel); 185 186 static BOOLEAN 187 AcpiDmIsOptimizationIgnored ( 188 ACPI_PARSE_OBJECT *StoreOp, 189 ACPI_PARSE_OBJECT *StoreArgument); 190 191 192 /******************************************************************************* 193 * 194 * FUNCTION: AcpiDmCheckForSymbolicOpcode 195 * 196 * PARAMETERS: Op - Current parse object 197 * Walk - Current parse tree walk info 198 * 199 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise 200 * 201 * DESCRIPTION: This is the main code that implements disassembly of AML code 202 * to C-style operators. Called during descending phase of the 203 * parse tree walk. 204 * 205 ******************************************************************************/ 206 207 BOOLEAN 208 AcpiDmCheckForSymbolicOpcode ( 209 ACPI_PARSE_OBJECT *Op, 210 ACPI_OP_WALK_INFO *Info) 211 { 212 char *OperatorSymbol = NULL; 213 ACPI_PARSE_OBJECT *Argument1; 214 ACPI_PARSE_OBJECT *Argument2; 215 ACPI_PARSE_OBJECT *Target; 216 ACPI_PARSE_OBJECT *Target2; 217 218 219 /* Exit immediately if ASL+ not enabled */ 220 221 if (!AcpiGbl_CstyleDisassembly) 222 { 223 return (FALSE); 224 } 225 226 /* Get the first operand */ 227 228 Argument1 = AcpiPsGetArg (Op, 0); 229 if (!Argument1) 230 { 231 return (FALSE); 232 } 233 234 /* Get the second operand */ 235 236 Argument2 = Argument1->Common.Next; 237 238 /* Setup the operator string for this opcode */ 239 240 switch (Op->Common.AmlOpcode) 241 { 242 case AML_ADD_OP: 243 OperatorSymbol = " + "; 244 break; 245 246 case AML_SUBTRACT_OP: 247 OperatorSymbol = " - "; 248 break; 249 250 case AML_MULTIPLY_OP: 251 OperatorSymbol = " * "; 252 break; 253 254 case AML_DIVIDE_OP: 255 OperatorSymbol = " / "; 256 break; 257 258 case AML_MOD_OP: 259 OperatorSymbol = " % "; 260 break; 261 262 case AML_SHIFT_LEFT_OP: 263 OperatorSymbol = " << "; 264 break; 265 266 case AML_SHIFT_RIGHT_OP: 267 OperatorSymbol = " >> "; 268 break; 269 270 case AML_BIT_AND_OP: 271 OperatorSymbol = " & "; 272 break; 273 274 case AML_BIT_OR_OP: 275 OperatorSymbol = " | "; 276 break; 277 278 case AML_BIT_XOR_OP: 279 OperatorSymbol = " ^ "; 280 break; 281 282 /* Logical operators, no target */ 283 284 case AML_LOGICAL_AND_OP: 285 OperatorSymbol = " && "; 286 break; 287 288 case AML_LOGICAL_EQUAL_OP: 289 OperatorSymbol = " == "; 290 break; 291 292 case AML_LOGICAL_GREATER_OP: 293 OperatorSymbol = " > "; 294 break; 295 296 case AML_LOGICAL_LESS_OP: 297 OperatorSymbol = " < "; 298 break; 299 300 case AML_LOGICAL_OR_OP: 301 OperatorSymbol = " || "; 302 break; 303 304 case AML_LOGICAL_NOT_OP: 305 /* 306 * Check for the LNOT sub-opcodes. These correspond to 307 * LNotEqual, LLessEqual, and LGreaterEqual. There are 308 * no actual AML opcodes for these operators. 309 */ 310 switch (Argument1->Common.AmlOpcode) 311 { 312 case AML_LOGICAL_EQUAL_OP: 313 OperatorSymbol = " != "; 314 break; 315 316 case AML_LOGICAL_GREATER_OP: 317 OperatorSymbol = " <= "; 318 break; 319 320 case AML_LOGICAL_LESS_OP: 321 OperatorSymbol = " >= "; 322 break; 323 324 default: 325 326 /* Unary LNOT case, emit "!" immediately */ 327 328 AcpiOsPrintf ("!"); 329 return (TRUE); 330 } 331 332 Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 333 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 334 335 /* Save symbol string in the next child (not peer) */ 336 337 Argument2 = AcpiPsGetArg (Argument1, 0); 338 if (!Argument2) 339 { 340 return (FALSE); 341 } 342 343 Argument2->Common.OperatorSymbol = OperatorSymbol; 344 return (TRUE); 345 346 case AML_INDEX_OP: 347 /* 348 * Check for constant source operand. Note: although technically 349 * legal syntax, the iASL compiler does not support this with 350 * the symbolic operators for Index(). It doesn't make sense to 351 * use Index() with a constant anyway. 352 */ 353 if ((Argument1->Common.AmlOpcode == AML_STRING_OP) || 354 (Argument1->Common.AmlOpcode == AML_BUFFER_OP) || 355 (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) || 356 (Argument1->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)) 357 { 358 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN; 359 return (FALSE); 360 } 361 362 /* Index operator is [] */ 363 364 Argument1->Common.OperatorSymbol = " ["; 365 Argument2->Common.OperatorSymbol = "]"; 366 break; 367 368 /* Unary operators */ 369 370 case AML_DECREMENT_OP: 371 OperatorSymbol = "--"; 372 break; 373 374 case AML_INCREMENT_OP: 375 OperatorSymbol = "++"; 376 break; 377 378 case AML_BIT_NOT_OP: 379 case AML_STORE_OP: 380 OperatorSymbol = NULL; 381 break; 382 383 default: 384 return (FALSE); 385 } 386 387 if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX) 388 { 389 return (TRUE); 390 } 391 392 /* 393 * This is the key to how the disassembly of the C-style operators 394 * works. We save the operator symbol in the first child, thus 395 * deferring symbol output until after the first operand has been 396 * emitted. 397 */ 398 if (!Argument1->Common.OperatorSymbol) 399 { 400 Argument1->Common.OperatorSymbol = OperatorSymbol; 401 } 402 403 /* 404 * Check for a valid target as the 3rd (or sometimes 2nd) operand 405 * 406 * Compound assignment operator support: 407 * Attempt to optimize constructs of the form: 408 * Add (Local1, 0xFF, Local1) 409 * to: 410 * Local1 += 0xFF 411 * 412 * Only the math operators and Store() have a target. 413 * Logicals have no target. 414 */ 415 switch (Op->Common.AmlOpcode) 416 { 417 case AML_ADD_OP: 418 case AML_SUBTRACT_OP: 419 case AML_MULTIPLY_OP: 420 case AML_DIVIDE_OP: 421 case AML_MOD_OP: 422 case AML_SHIFT_LEFT_OP: 423 case AML_SHIFT_RIGHT_OP: 424 case AML_BIT_AND_OP: 425 case AML_BIT_OR_OP: 426 case AML_BIT_XOR_OP: 427 428 /* Target is 3rd operand */ 429 430 Target = Argument2->Common.Next; 431 if (Op->Common.AmlOpcode == AML_DIVIDE_OP) 432 { 433 Target2 = Target->Common.Next; 434 435 /* 436 * Divide has an extra target operand (Remainder). 437 * Default behavior is to simply ignore ASL+ conversion 438 * if the remainder target (modulo) is specified. 439 */ 440 if (!AcpiGbl_DoDisassemblerOptimizations) 441 { 442 if (AcpiDmIsValidTarget (Target)) 443 { 444 Argument1->Common.OperatorSymbol = NULL; 445 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 446 return (FALSE); 447 } 448 449 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 450 Target = Target2; 451 } 452 else 453 { 454 /* 455 * Divide has an extra target operand (Remainder). 456 * If both targets are specified, it cannot be converted 457 * to a C-style operator. 458 */ 459 if (AcpiDmIsValidTarget (Target) && 460 AcpiDmIsValidTarget (Target2)) 461 { 462 Argument1->Common.OperatorSymbol = NULL; 463 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 464 return (FALSE); 465 } 466 467 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */ 468 { 469 /* Convert the Divide to Modulo */ 470 471 Op->Common.AmlOpcode = AML_MOD_OP; 472 473 Argument1->Common.OperatorSymbol = " % "; 474 Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 475 } 476 else /* Only second Target (quotient) is valid */ 477 { 478 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 479 Target = Target2; 480 } 481 } 482 } 483 484 /* Parser should ensure there is at least a placeholder target */ 485 486 if (!Target) 487 { 488 return (FALSE); 489 } 490 491 if (!AcpiDmIsValidTarget (Target)) 492 { 493 /* Not a valid target (placeholder only, from parser) */ 494 break; 495 } 496 497 /* 498 * Promote the target up to the first child in the parse 499 * tree. This is done because the target will be output 500 * first, in the form: 501 * <Target> = Operands... 502 */ 503 AcpiDmPromoteTarget (Op, Target); 504 505 /* Check operands for conversion to a "Compound Assignment" */ 506 507 switch (Op->Common.AmlOpcode) 508 { 509 /* Commutative operators */ 510 511 case AML_ADD_OP: 512 case AML_MULTIPLY_OP: 513 case AML_BIT_AND_OP: 514 case AML_BIT_OR_OP: 515 case AML_BIT_XOR_OP: 516 /* 517 * For the commutative operators, we can convert to a 518 * compound statement only if at least one (either) operand 519 * is the same as the target. 520 * 521 * Add (A, B, A) --> A += B 522 * Add (B, A, A) --> A += B 523 * Add (B, C, A) --> A = (B + C) 524 */ 525 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) || 526 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE))) 527 { 528 Target->Common.OperatorSymbol = 529 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 530 531 /* Convert operator to compound assignment */ 532 533 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 534 Argument1->Common.OperatorSymbol = NULL; 535 return (TRUE); 536 } 537 break; 538 539 /* Non-commutative operators */ 540 541 case AML_SUBTRACT_OP: 542 case AML_DIVIDE_OP: 543 case AML_MOD_OP: 544 case AML_SHIFT_LEFT_OP: 545 case AML_SHIFT_RIGHT_OP: 546 /* 547 * For the non-commutative operators, we can convert to a 548 * compound statement only if the target is the same as the 549 * first operand. 550 * 551 * Subtract (A, B, A) --> A -= B 552 * Subtract (B, A, A) --> A = (B - A) 553 */ 554 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE))) 555 { 556 Target->Common.OperatorSymbol = 557 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 558 559 /* Convert operator to compound assignment */ 560 561 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 562 Argument1->Common.OperatorSymbol = NULL; 563 return (TRUE); 564 } 565 break; 566 567 default: 568 break; 569 } 570 571 /* 572 * If we are within a C-style expression, emit an extra open 573 * paren. Implemented by examining the parent op. 574 */ 575 switch (Op->Common.Parent->Common.AmlOpcode) 576 { 577 case AML_ADD_OP: 578 case AML_SUBTRACT_OP: 579 case AML_MULTIPLY_OP: 580 case AML_DIVIDE_OP: 581 case AML_MOD_OP: 582 case AML_SHIFT_LEFT_OP: 583 case AML_SHIFT_RIGHT_OP: 584 case AML_BIT_AND_OP: 585 case AML_BIT_OR_OP: 586 case AML_BIT_XOR_OP: 587 case AML_LOGICAL_AND_OP: 588 case AML_LOGICAL_EQUAL_OP: 589 case AML_LOGICAL_GREATER_OP: 590 case AML_LOGICAL_LESS_OP: 591 case AML_LOGICAL_OR_OP: 592 593 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT; 594 AcpiOsPrintf ("("); 595 break; 596 597 default: 598 break; 599 } 600 601 /* Normal output for ASL/AML operators with a target operand */ 602 603 Target->Common.OperatorSymbol = " = ("; 604 return (TRUE); 605 606 /* Binary operators, no parens */ 607 608 case AML_DECREMENT_OP: 609 case AML_INCREMENT_OP: 610 return (TRUE); 611 612 case AML_INDEX_OP: 613 614 /* Target is optional, 3rd operand */ 615 616 Target = Argument2->Common.Next; 617 if (AcpiDmIsValidTarget (Target)) 618 { 619 AcpiDmPromoteTarget (Op, Target); 620 621 if (!Target->Common.OperatorSymbol) 622 { 623 Target->Common.OperatorSymbol = " = "; 624 } 625 } 626 return (TRUE); 627 628 case AML_STORE_OP: 629 /* 630 * For Store, the Target is the 2nd operand. We know the target 631 * is valid, because it is not optional. 632 * 633 * Ignore any optimizations/folding if flag is set. 634 * Used for iASL/disassembler test suite only. 635 */ 636 if (AcpiDmIsOptimizationIgnored (Op, Argument1)) 637 { 638 return (FALSE); 639 } 640 641 /* 642 * Perform conversion. 643 * In the parse tree, simply swap the target with the 644 * source so that the target is processed first. 645 */ 646 Target = Argument1->Common.Next; 647 if (!Target) 648 { 649 return (FALSE); 650 } 651 652 AcpiDmPromoteTarget (Op, Target); 653 if (!Target->Common.OperatorSymbol) 654 { 655 Target->Common.OperatorSymbol = " = "; 656 } 657 return (TRUE); 658 659 case AML_BIT_NOT_OP: 660 661 /* Target is optional, 2nd operand */ 662 663 Target = Argument1->Common.Next; 664 if (!Target) 665 { 666 return (FALSE); 667 } 668 669 if (AcpiDmIsValidTarget (Target)) 670 { 671 /* Valid target, not a placeholder */ 672 673 AcpiDmPromoteTarget (Op, Target); 674 Target->Common.OperatorSymbol = " = ~"; 675 } 676 else 677 { 678 /* No target. Emit this prefix operator immediately */ 679 680 AcpiOsPrintf ("~"); 681 } 682 return (TRUE); 683 684 default: 685 break; 686 } 687 688 /* All other operators, emit an open paren */ 689 690 AcpiOsPrintf ("("); 691 return (TRUE); 692 } 693 694 695 /******************************************************************************* 696 * 697 * FUNCTION: AcpiDmIsOptimizationIgnored 698 * 699 * PARAMETERS: StoreOp - Store operator parse object 700 * StoreArgument - Target associate with the Op 701 * 702 * RETURN: TRUE if this Store operator should not be converted/removed. 703 * 704 * DESCRIPTION: The following function implements "Do not optimize if a 705 * store is immediately followed by a math/bit operator that 706 * has no target". 707 * 708 * Function is ignored if DoDisassemblerOptimizations is TRUE. 709 * This is the default, ignore this function. 710 * 711 * Disables these types of optimizations, and simply emits 712 * legacy ASL code: 713 * Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2) 714 * --> INT2 = INT1 + 4 715 * 716 * Store (Not (INT1), INT2) --> Not (INT1, INT2) 717 * --> INT2 = ~INT1 718 * 719 * Used only for the ASL test suite. For the test suite, we 720 * don't want to perform some optimizations to ensure binary 721 * compatibility with the generation of the legacy ASL->AML. 722 * In other words, for all test modules we want exactly: 723 * (ASL+ -> AML) == (ASL- -> AML) 724 * 725 ******************************************************************************/ 726 727 static BOOLEAN 728 AcpiDmIsOptimizationIgnored ( 729 ACPI_PARSE_OBJECT *StoreOp, 730 ACPI_PARSE_OBJECT *StoreArgument) 731 { 732 ACPI_PARSE_OBJECT *Argument1; 733 ACPI_PARSE_OBJECT *Argument2; 734 ACPI_PARSE_OBJECT *Target; 735 736 737 /* No optimizations/folding for the typical case */ 738 739 if (AcpiGbl_DoDisassemblerOptimizations) 740 { 741 return (FALSE); 742 } 743 744 /* 745 * Only a small subset of ASL/AML operators can be optimized. 746 * Can only optimize/fold if there is no target (or targets) 747 * specified for the operator. And of course, the operator 748 * is surrrounded by a Store() operator. 749 */ 750 switch (StoreArgument->Common.AmlOpcode) 751 { 752 case AML_ADD_OP: 753 case AML_SUBTRACT_OP: 754 case AML_MULTIPLY_OP: 755 case AML_MOD_OP: 756 case AML_SHIFT_LEFT_OP: 757 case AML_SHIFT_RIGHT_OP: 758 case AML_BIT_AND_OP: 759 case AML_BIT_OR_OP: 760 case AML_BIT_XOR_OP: 761 case AML_INDEX_OP: 762 763 /* These operators have two arguments and one target */ 764 765 Argument1 = StoreArgument->Common.Value.Arg; 766 Argument2 = Argument1->Common.Next; 767 Target = Argument2->Common.Next; 768 769 if (!AcpiDmIsValidTarget (Target)) 770 { 771 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 772 return (TRUE); 773 } 774 break; 775 776 case AML_DIVIDE_OP: 777 778 /* This operator has two arguments and two targets */ 779 780 Argument1 = StoreArgument->Common.Value.Arg; 781 Argument2 = Argument1->Common.Next; 782 Target = Argument2->Common.Next; 783 784 if (!AcpiDmIsValidTarget (Target) || 785 !AcpiDmIsValidTarget (Target->Common.Next)) 786 { 787 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 788 return (TRUE); 789 } 790 break; 791 792 case AML_BIT_NOT_OP: 793 794 /* This operator has one operand and one target */ 795 796 Argument1 = StoreArgument->Common.Value.Arg; 797 Target = Argument1->Common.Next; 798 799 if (!AcpiDmIsValidTarget (Target)) 800 { 801 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 802 return (TRUE); 803 } 804 break; 805 806 default: 807 break; 808 } 809 810 return (FALSE); 811 } 812 813 814 /******************************************************************************* 815 * 816 * FUNCTION: AcpiDmCloseOperator 817 * 818 * PARAMETERS: Op - Current parse object 819 * 820 * RETURN: None 821 * 822 * DESCRIPTION: Closes an operator by adding a closing parentheses if and 823 * when necessary. Called during ascending phase of the 824 * parse tree walk. 825 * 826 ******************************************************************************/ 827 828 void 829 AcpiDmCloseOperator ( 830 ACPI_PARSE_OBJECT *Op) 831 { 832 833 /* Always emit paren if ASL+ disassembly disabled */ 834 835 if (!AcpiGbl_CstyleDisassembly) 836 { 837 AcpiOsPrintf (")"); 838 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 839 return; 840 } 841 842 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY) 843 { 844 AcpiOsPrintf (")"); 845 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 846 return; 847 } 848 849 /* Check if we need to add an additional closing paren */ 850 851 switch (Op->Common.AmlOpcode) 852 { 853 case AML_ADD_OP: 854 case AML_SUBTRACT_OP: 855 case AML_MULTIPLY_OP: 856 case AML_DIVIDE_OP: 857 case AML_MOD_OP: 858 case AML_SHIFT_LEFT_OP: 859 case AML_SHIFT_RIGHT_OP: 860 case AML_BIT_AND_OP: 861 case AML_BIT_OR_OP: 862 case AML_BIT_XOR_OP: 863 case AML_LOGICAL_AND_OP: 864 case AML_LOGICAL_EQUAL_OP: 865 case AML_LOGICAL_GREATER_OP: 866 case AML_LOGICAL_LESS_OP: 867 case AML_LOGICAL_OR_OP: 868 869 /* Emit paren only if this is not a compound assignment */ 870 871 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT) 872 { 873 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 874 return; 875 } 876 877 /* Emit extra close paren for assignment within an expression */ 878 879 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT) 880 { 881 AcpiOsPrintf (")"); 882 } 883 break; 884 885 case AML_INDEX_OP: 886 887 /* This is case for unsupported Index() source constants */ 888 889 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN) 890 { 891 AcpiOsPrintf (")"); 892 } 893 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 894 return; 895 896 /* No need for parens for these */ 897 898 case AML_DECREMENT_OP: 899 case AML_INCREMENT_OP: 900 case AML_LOGICAL_NOT_OP: 901 case AML_BIT_NOT_OP: 902 case AML_STORE_OP: 903 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 904 return; 905 906 default: 907 908 /* Always emit paren for non-ASL+ operators */ 909 break; 910 } 911 912 AcpiOsPrintf (")"); 913 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 914 915 return; 916 } 917 918 919 /******************************************************************************* 920 * 921 * FUNCTION: AcpiDmGetCompoundSymbol 922 * 923 * PARAMETERS: AslOpcode 924 * 925 * RETURN: String containing the compound assignment symbol 926 * 927 * DESCRIPTION: Detect opcodes that can be converted to compound assignment, 928 * return the appropriate operator string. 929 * 930 ******************************************************************************/ 931 932 static char * 933 AcpiDmGetCompoundSymbol ( 934 UINT16 AmlOpcode) 935 { 936 char *Symbol; 937 938 939 switch (AmlOpcode) 940 { 941 case AML_ADD_OP: 942 Symbol = " += "; 943 break; 944 945 case AML_SUBTRACT_OP: 946 Symbol = " -= "; 947 break; 948 949 case AML_MULTIPLY_OP: 950 Symbol = " *= "; 951 break; 952 953 case AML_DIVIDE_OP: 954 Symbol = " /= "; 955 break; 956 957 case AML_MOD_OP: 958 Symbol = " %= "; 959 break; 960 961 case AML_SHIFT_LEFT_OP: 962 Symbol = " <<= "; 963 break; 964 965 case AML_SHIFT_RIGHT_OP: 966 Symbol = " >>= "; 967 break; 968 969 case AML_BIT_AND_OP: 970 Symbol = " &= "; 971 break; 972 973 case AML_BIT_OR_OP: 974 Symbol = " |= "; 975 break; 976 977 case AML_BIT_XOR_OP: 978 Symbol = " ^= "; 979 break; 980 981 default: 982 983 /* No operator string for all other opcodes */ 984 985 return (NULL); 986 } 987 988 return (Symbol); 989 } 990 991 992 /******************************************************************************* 993 * 994 * FUNCTION: AcpiDmPromoteTarget 995 * 996 * PARAMETERS: Op - Operator parse object 997 * Target - Target associate with the Op 998 * 999 * RETURN: None 1000 * 1001 * DESCRIPTION: Transform the parse tree by moving the target up to the first 1002 * child of the Op. 1003 * 1004 ******************************************************************************/ 1005 1006 static void 1007 AcpiDmPromoteTarget ( 1008 ACPI_PARSE_OBJECT *Op, 1009 ACPI_PARSE_OBJECT *Target) 1010 { 1011 ACPI_PARSE_OBJECT *Child; 1012 1013 1014 /* Link target directly to the Op as first child */ 1015 1016 Child = Op->Common.Value.Arg; 1017 Op->Common.Value.Arg = Target; 1018 Target->Common.Next = Child; 1019 1020 /* Find the last peer, it is linked to the target. Unlink it. */ 1021 1022 while (Child->Common.Next != Target) 1023 { 1024 Child = Child->Common.Next; 1025 } 1026 1027 Child->Common.Next = NULL; 1028 } 1029 1030 1031 /******************************************************************************* 1032 * 1033 * FUNCTION: AcpiDmIsValidTarget 1034 * 1035 * PARAMETERS: Target - Target Op from the parse tree 1036 * 1037 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder 1038 * Op that was inserted by the parser. 1039 * 1040 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target. 1041 * In other words, determine if the optional target is used or 1042 * not. Note: If Target is NULL, something is seriously wrong, 1043 * probably with the parse tree. 1044 * 1045 ******************************************************************************/ 1046 1047 static BOOLEAN 1048 AcpiDmIsValidTarget ( 1049 ACPI_PARSE_OBJECT *Target) 1050 { 1051 1052 if (!Target) 1053 { 1054 return (FALSE); 1055 } 1056 1057 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 1058 (Target->Common.Value.Arg == NULL)) 1059 { 1060 return (FALSE); 1061 } 1062 1063 return (TRUE); 1064 } 1065 1066 1067 /******************************************************************************* 1068 * 1069 * FUNCTION: AcpiDmIsTargetAnOperand 1070 * 1071 * PARAMETERS: Target - Target associated with the expression 1072 * Operand - An operand associated with expression 1073 * 1074 * RETURN: TRUE if expression can be converted to a compound assignment. 1075 * FALSE otherwise. 1076 * 1077 * DESCRIPTION: Determine if the Target duplicates the operand, in order to 1078 * detect if the expression can be converted to a compound 1079 * assignment. (+=, *=, etc.) 1080 * 1081 ******************************************************************************/ 1082 1083 static BOOLEAN 1084 AcpiDmIsTargetAnOperand ( 1085 ACPI_PARSE_OBJECT *Target, 1086 ACPI_PARSE_OBJECT *Operand, 1087 BOOLEAN TopLevel) 1088 { 1089 const ACPI_OPCODE_INFO *OpInfo; 1090 BOOLEAN Same; 1091 1092 1093 /* 1094 * Opcodes must match. Note: ignoring the difference between nameseg 1095 * and namepath for now. May be needed later. 1096 */ 1097 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode) 1098 { 1099 return (FALSE); 1100 } 1101 1102 /* Nodes should match, even if they are NULL */ 1103 1104 if (Target->Common.Node != Operand->Common.Node) 1105 { 1106 return (FALSE); 1107 } 1108 1109 /* Determine if a child exists */ 1110 1111 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode); 1112 if (OpInfo->Flags & AML_HAS_ARGS) 1113 { 1114 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg, 1115 Operand->Common.Value.Arg, FALSE); 1116 if (!Same) 1117 { 1118 return (FALSE); 1119 } 1120 } 1121 1122 /* Check the next peer, as long as we are not at the top level */ 1123 1124 if ((!TopLevel) && 1125 Target->Common.Next) 1126 { 1127 Same = AcpiDmIsTargetAnOperand (Target->Common.Next, 1128 Operand->Common.Next, FALSE); 1129 if (!Same) 1130 { 1131 return (FALSE); 1132 } 1133 } 1134 1135 /* Suppress the duplicate operand at the top-level */ 1136 1137 if (TopLevel) 1138 { 1139 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1140 } 1141 return (TRUE); 1142 } 1143 1144 #endif 1145