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 - 2023, 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 <contrib/dev/acpica/include/acpi.h> 153 #include <contrib/dev/acpica/include/accommon.h> 154 #include <contrib/dev/acpica/include/acparser.h> 155 #include <contrib/dev/acpica/include/amlcode.h> 156 #include <contrib/dev/acpica/include/acdebug.h> 157 #include <contrib/dev/acpica/include/acconvert.h> 158 159 160 #define _COMPONENT ACPI_CA_DEBUGGER 161 ACPI_MODULE_NAME ("dmcstyle") 162 163 164 /* Local prototypes */ 165 166 static char * 167 AcpiDmGetCompoundSymbol ( 168 UINT16 AslOpcode); 169 170 static void 171 AcpiDmPromoteTarget ( 172 ACPI_PARSE_OBJECT *Op, 173 ACPI_PARSE_OBJECT *Target); 174 175 static BOOLEAN 176 AcpiDmIsValidTarget ( 177 ACPI_PARSE_OBJECT *Op); 178 179 static BOOLEAN 180 AcpiDmIsTargetAnOperand ( 181 ACPI_PARSE_OBJECT *Target, 182 ACPI_PARSE_OBJECT *Operand, 183 BOOLEAN TopLevel); 184 185 static BOOLEAN 186 AcpiDmIsOptimizationIgnored ( 187 ACPI_PARSE_OBJECT *StoreOp, 188 ACPI_PARSE_OBJECT *StoreArgument); 189 190 191 /******************************************************************************* 192 * 193 * FUNCTION: AcpiDmCheckForSymbolicOpcode 194 * 195 * PARAMETERS: Op - Current parse object 196 * Walk - Current parse tree walk info 197 * 198 * RETURN: TRUE if opcode can be converted to symbolic, FALSE otherwise 199 * 200 * DESCRIPTION: This is the main code that implements disassembly of AML code 201 * to C-style operators. Called during descending phase of the 202 * parse tree walk. 203 * 204 ******************************************************************************/ 205 206 BOOLEAN 207 AcpiDmCheckForSymbolicOpcode ( 208 ACPI_PARSE_OBJECT *Op, 209 ACPI_OP_WALK_INFO *Info) 210 { 211 char *OperatorSymbol = NULL; 212 ACPI_PARSE_OBJECT *Argument1; 213 ACPI_PARSE_OBJECT *Argument2; 214 ACPI_PARSE_OBJECT *Target; 215 ACPI_PARSE_OBJECT *Target2; 216 217 218 /* Exit immediately if ASL+ not enabled */ 219 220 if (!AcpiGbl_CstyleDisassembly) 221 { 222 return (FALSE); 223 } 224 225 /* Get the first operand */ 226 227 Argument1 = AcpiPsGetArg (Op, 0); 228 if (!Argument1) 229 { 230 return (FALSE); 231 } 232 233 /* Get the second operand */ 234 235 Argument2 = Argument1->Common.Next; 236 237 /* Setup the operator string for this opcode */ 238 239 switch (Op->Common.AmlOpcode) 240 { 241 case AML_ADD_OP: 242 OperatorSymbol = " + "; 243 break; 244 245 case AML_SUBTRACT_OP: 246 OperatorSymbol = " - "; 247 break; 248 249 case AML_MULTIPLY_OP: 250 OperatorSymbol = " * "; 251 break; 252 253 case AML_DIVIDE_OP: 254 OperatorSymbol = " / "; 255 break; 256 257 case AML_MOD_OP: 258 OperatorSymbol = " % "; 259 break; 260 261 case AML_SHIFT_LEFT_OP: 262 OperatorSymbol = " << "; 263 break; 264 265 case AML_SHIFT_RIGHT_OP: 266 OperatorSymbol = " >> "; 267 break; 268 269 case AML_BIT_AND_OP: 270 OperatorSymbol = " & "; 271 break; 272 273 case AML_BIT_OR_OP: 274 OperatorSymbol = " | "; 275 break; 276 277 case AML_BIT_XOR_OP: 278 OperatorSymbol = " ^ "; 279 break; 280 281 /* Logical operators, no target */ 282 283 case AML_LOGICAL_AND_OP: 284 OperatorSymbol = " && "; 285 break; 286 287 case AML_LOGICAL_EQUAL_OP: 288 OperatorSymbol = " == "; 289 break; 290 291 case AML_LOGICAL_GREATER_OP: 292 OperatorSymbol = " > "; 293 break; 294 295 case AML_LOGICAL_LESS_OP: 296 OperatorSymbol = " < "; 297 break; 298 299 case AML_LOGICAL_OR_OP: 300 OperatorSymbol = " || "; 301 break; 302 303 case AML_LOGICAL_NOT_OP: 304 /* 305 * Check for the LNOT sub-opcodes. These correspond to 306 * LNotEqual, LLessEqual, and LGreaterEqual. There are 307 * no actual AML opcodes for these operators. 308 */ 309 switch (Argument1->Common.AmlOpcode) 310 { 311 case AML_LOGICAL_EQUAL_OP: 312 OperatorSymbol = " != "; 313 break; 314 315 case AML_LOGICAL_GREATER_OP: 316 OperatorSymbol = " <= "; 317 break; 318 319 case AML_LOGICAL_LESS_OP: 320 OperatorSymbol = " >= "; 321 break; 322 323 default: 324 325 /* Unary LNOT case, emit "!" immediately */ 326 327 AcpiOsPrintf ("!"); 328 return (TRUE); 329 } 330 331 Argument1->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 332 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 333 334 /* Save symbol string in the next child (not peer) */ 335 336 Argument2 = AcpiPsGetArg (Argument1, 0); 337 if (!Argument2) 338 { 339 return (FALSE); 340 } 341 342 Argument2->Common.OperatorSymbol = OperatorSymbol; 343 return (TRUE); 344 345 case AML_INDEX_OP: 346 /* 347 * Check for constant source operand. Note: although technically 348 * legal syntax, the iASL compiler does not support this with 349 * the symbolic operators for Index(). It doesn't make sense to 350 * use Index() with a constant anyway. 351 */ 352 if ((Argument1->Common.AmlOpcode == AML_STRING_OP) || 353 (Argument1->Common.AmlOpcode == AML_BUFFER_OP) || 354 (Argument1->Common.AmlOpcode == AML_PACKAGE_OP) || 355 (Argument1->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)) 356 { 357 Op->Common.DisasmFlags |= ACPI_PARSEOP_CLOSING_PAREN; 358 return (FALSE); 359 } 360 361 /* Index operator is [] */ 362 363 Argument1->Common.OperatorSymbol = " ["; 364 Argument2->Common.OperatorSymbol = "]"; 365 break; 366 367 /* Unary operators */ 368 369 case AML_DECREMENT_OP: 370 OperatorSymbol = "--"; 371 break; 372 373 case AML_INCREMENT_OP: 374 OperatorSymbol = "++"; 375 break; 376 377 case AML_BIT_NOT_OP: 378 case AML_STORE_OP: 379 OperatorSymbol = NULL; 380 break; 381 382 default: 383 return (FALSE); 384 } 385 386 if (Argument1->Common.DisasmOpcode == ACPI_DASM_LNOT_SUFFIX) 387 { 388 return (TRUE); 389 } 390 391 /* 392 * This is the key to how the disassembly of the C-style operators 393 * works. We save the operator symbol in the first child, thus 394 * deferring symbol output until after the first operand has been 395 * emitted. 396 */ 397 if (!Argument1->Common.OperatorSymbol) 398 { 399 Argument1->Common.OperatorSymbol = OperatorSymbol; 400 } 401 402 /* 403 * Check for a valid target as the 3rd (or sometimes 2nd) operand 404 * 405 * Compound assignment operator support: 406 * Attempt to optimize constructs of the form: 407 * Add (Local1, 0xFF, Local1) 408 * to: 409 * Local1 += 0xFF 410 * 411 * Only the math operators and Store() have a target. 412 * Logicals have no target. 413 */ 414 switch (Op->Common.AmlOpcode) 415 { 416 case AML_ADD_OP: 417 case AML_SUBTRACT_OP: 418 case AML_MULTIPLY_OP: 419 case AML_DIVIDE_OP: 420 case AML_MOD_OP: 421 case AML_SHIFT_LEFT_OP: 422 case AML_SHIFT_RIGHT_OP: 423 case AML_BIT_AND_OP: 424 case AML_BIT_OR_OP: 425 case AML_BIT_XOR_OP: 426 427 /* Target is 3rd operand */ 428 429 Target = Argument2->Common.Next; 430 if (Op->Common.AmlOpcode == AML_DIVIDE_OP) 431 { 432 Target2 = Target->Common.Next; 433 434 /* 435 * Divide has an extra target operand (Remainder). 436 * Default behavior is to simply ignore ASL+ conversion 437 * if the remainder target (modulo) is specified. 438 */ 439 if (!AcpiGbl_DoDisassemblerOptimizations) 440 { 441 if (AcpiDmIsValidTarget (Target)) 442 { 443 Argument1->Common.OperatorSymbol = NULL; 444 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 445 return (FALSE); 446 } 447 448 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 449 Target = Target2; 450 } 451 else 452 { 453 /* 454 * Divide has an extra target operand (Remainder). 455 * If both targets are specified, it cannot be converted 456 * to a C-style operator. 457 */ 458 if (AcpiDmIsValidTarget (Target) && 459 AcpiDmIsValidTarget (Target2)) 460 { 461 Argument1->Common.OperatorSymbol = NULL; 462 Op->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 463 return (FALSE); 464 } 465 466 if (AcpiDmIsValidTarget (Target)) /* Only first Target is valid (remainder) */ 467 { 468 /* Convert the Divide to Modulo */ 469 470 Op->Common.AmlOpcode = AML_MOD_OP; 471 472 Argument1->Common.OperatorSymbol = " % "; 473 Target2->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 474 } 475 else /* Only second Target (quotient) is valid */ 476 { 477 Target->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 478 Target = Target2; 479 } 480 } 481 } 482 483 /* Parser should ensure there is at least a placeholder target */ 484 485 if (!Target) 486 { 487 return (FALSE); 488 } 489 490 if (!AcpiDmIsValidTarget (Target)) 491 { 492 /* Not a valid target (placeholder only, from parser) */ 493 break; 494 } 495 496 /* 497 * Promote the target up to the first child in the parse 498 * tree. This is done because the target will be output 499 * first, in the form: 500 * <Target> = Operands... 501 */ 502 AcpiDmPromoteTarget (Op, Target); 503 504 /* Check operands for conversion to a "Compound Assignment" */ 505 506 switch (Op->Common.AmlOpcode) 507 { 508 /* Commutative operators */ 509 510 case AML_ADD_OP: 511 case AML_MULTIPLY_OP: 512 case AML_BIT_AND_OP: 513 case AML_BIT_OR_OP: 514 case AML_BIT_XOR_OP: 515 /* 516 * For the commutative operators, we can convert to a 517 * compound statement only if at least one (either) operand 518 * is the same as the target. 519 * 520 * Add (A, B, A) --> A += B 521 * Add (B, A, A) --> A += B 522 * Add (B, C, A) --> A = (B + C) 523 */ 524 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE)) || 525 (AcpiDmIsTargetAnOperand (Target, Argument2, TRUE))) 526 { 527 Target->Common.OperatorSymbol = 528 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 529 530 /* Convert operator to compound assignment */ 531 532 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 533 Argument1->Common.OperatorSymbol = NULL; 534 return (TRUE); 535 } 536 break; 537 538 /* Non-commutative operators */ 539 540 case AML_SUBTRACT_OP: 541 case AML_DIVIDE_OP: 542 case AML_MOD_OP: 543 case AML_SHIFT_LEFT_OP: 544 case AML_SHIFT_RIGHT_OP: 545 /* 546 * For the non-commutative operators, we can convert to a 547 * compound statement only if the target is the same as the 548 * first operand. 549 * 550 * Subtract (A, B, A) --> A -= B 551 * Subtract (B, A, A) --> A = (B - A) 552 */ 553 if ((AcpiDmIsTargetAnOperand (Target, Argument1, TRUE))) 554 { 555 Target->Common.OperatorSymbol = 556 AcpiDmGetCompoundSymbol (Op->Common.AmlOpcode); 557 558 /* Convert operator to compound assignment */ 559 560 Op->Common.DisasmFlags |= ACPI_PARSEOP_COMPOUND_ASSIGNMENT; 561 Argument1->Common.OperatorSymbol = NULL; 562 return (TRUE); 563 } 564 break; 565 566 default: 567 break; 568 } 569 570 /* 571 * If we are within a C-style expression, emit an extra open 572 * paren. Implemented by examining the parent op. 573 */ 574 switch (Op->Common.Parent->Common.AmlOpcode) 575 { 576 case AML_ADD_OP: 577 case AML_SUBTRACT_OP: 578 case AML_MULTIPLY_OP: 579 case AML_DIVIDE_OP: 580 case AML_MOD_OP: 581 case AML_SHIFT_LEFT_OP: 582 case AML_SHIFT_RIGHT_OP: 583 case AML_BIT_AND_OP: 584 case AML_BIT_OR_OP: 585 case AML_BIT_XOR_OP: 586 case AML_LOGICAL_AND_OP: 587 case AML_LOGICAL_EQUAL_OP: 588 case AML_LOGICAL_GREATER_OP: 589 case AML_LOGICAL_LESS_OP: 590 case AML_LOGICAL_OR_OP: 591 592 Op->Common.DisasmFlags |= ACPI_PARSEOP_ASSIGNMENT; 593 AcpiOsPrintf ("("); 594 break; 595 596 default: 597 break; 598 } 599 600 /* Normal output for ASL/AML operators with a target operand */ 601 602 Target->Common.OperatorSymbol = " = ("; 603 return (TRUE); 604 605 /* Binary operators, no parens */ 606 607 case AML_DECREMENT_OP: 608 case AML_INCREMENT_OP: 609 return (TRUE); 610 611 case AML_INDEX_OP: 612 613 /* Target is optional, 3rd operand */ 614 615 Target = Argument2->Common.Next; 616 if (AcpiDmIsValidTarget (Target)) 617 { 618 AcpiDmPromoteTarget (Op, Target); 619 620 if (!Target->Common.OperatorSymbol) 621 { 622 Target->Common.OperatorSymbol = " = "; 623 } 624 } 625 return (TRUE); 626 627 case AML_STORE_OP: 628 /* 629 * For Store, the Target is the 2nd operand. We know the target 630 * is valid, because it is not optional. 631 * 632 * Ignore any optimizations/folding if flag is set. 633 * Used for iASL/disassembler test suite only. 634 */ 635 if (AcpiDmIsOptimizationIgnored (Op, Argument1)) 636 { 637 return (FALSE); 638 } 639 640 /* 641 * Perform conversion. 642 * In the parse tree, simply swap the target with the 643 * source so that the target is processed first. 644 */ 645 Target = Argument1->Common.Next; 646 if (!Target) 647 { 648 return (FALSE); 649 } 650 651 AcpiDmPromoteTarget (Op, Target); 652 if (!Target->Common.OperatorSymbol) 653 { 654 Target->Common.OperatorSymbol = " = "; 655 } 656 return (TRUE); 657 658 case AML_BIT_NOT_OP: 659 660 /* Target is optional, 2nd operand */ 661 662 Target = Argument1->Common.Next; 663 if (!Target) 664 { 665 return (FALSE); 666 } 667 668 if (AcpiDmIsValidTarget (Target)) 669 { 670 /* Valid target, not a placeholder */ 671 672 AcpiDmPromoteTarget (Op, Target); 673 Target->Common.OperatorSymbol = " = ~"; 674 } 675 else 676 { 677 /* No target. Emit this prefix operator immediately */ 678 679 AcpiOsPrintf ("~"); 680 } 681 return (TRUE); 682 683 default: 684 break; 685 } 686 687 /* All other operators, emit an open paren */ 688 689 AcpiOsPrintf ("("); 690 return (TRUE); 691 } 692 693 694 /******************************************************************************* 695 * 696 * FUNCTION: AcpiDmIsOptimizationIgnored 697 * 698 * PARAMETERS: StoreOp - Store operator parse object 699 * StoreArgument - Target associate with the Op 700 * 701 * RETURN: TRUE if this Store operator should not be converted/removed. 702 * 703 * DESCRIPTION: The following function implements "Do not optimize if a 704 * store is immediately followed by a math/bit operator that 705 * has no target". 706 * 707 * Function is ignored if DoDisassemblerOptimizations is TRUE. 708 * This is the default, ignore this function. 709 * 710 * Disables these types of optimizations, and simply emits 711 * legacy ASL code: 712 * Store (Add (INT1, 4), INT2) --> Add (INT1, 4, INT2) 713 * --> INT2 = INT1 + 4 714 * 715 * Store (Not (INT1), INT2) --> Not (INT1, INT2) 716 * --> INT2 = ~INT1 717 * 718 * Used only for the ASL test suite. For the test suite, we 719 * don't want to perform some optimizations to ensure binary 720 * compatibility with the generation of the legacy ASL->AML. 721 * In other words, for all test modules we want exactly: 722 * (ASL+ -> AML) == (ASL- -> AML) 723 * 724 ******************************************************************************/ 725 726 static BOOLEAN 727 AcpiDmIsOptimizationIgnored ( 728 ACPI_PARSE_OBJECT *StoreOp, 729 ACPI_PARSE_OBJECT *StoreArgument) 730 { 731 ACPI_PARSE_OBJECT *Argument1; 732 ACPI_PARSE_OBJECT *Argument2; 733 ACPI_PARSE_OBJECT *Target; 734 735 736 /* No optimizations/folding for the typical case */ 737 738 if (AcpiGbl_DoDisassemblerOptimizations) 739 { 740 return (FALSE); 741 } 742 743 /* 744 * Only a small subset of ASL/AML operators can be optimized. 745 * Can only optimize/fold if there is no target (or targets) 746 * specified for the operator. And of course, the operator 747 * is surrounded by a Store() operator. 748 */ 749 switch (StoreArgument->Common.AmlOpcode) 750 { 751 case AML_ADD_OP: 752 case AML_SUBTRACT_OP: 753 case AML_MULTIPLY_OP: 754 case AML_MOD_OP: 755 case AML_SHIFT_LEFT_OP: 756 case AML_SHIFT_RIGHT_OP: 757 case AML_BIT_AND_OP: 758 case AML_BIT_OR_OP: 759 case AML_BIT_XOR_OP: 760 case AML_INDEX_OP: 761 762 /* These operators have two arguments and one target */ 763 764 Argument1 = StoreArgument->Common.Value.Arg; 765 Argument2 = Argument1->Common.Next; 766 Target = Argument2->Common.Next; 767 768 if (!AcpiDmIsValidTarget (Target)) 769 { 770 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 771 return (TRUE); 772 } 773 break; 774 775 case AML_DIVIDE_OP: 776 777 /* This operator has two arguments and two targets */ 778 779 Argument1 = StoreArgument->Common.Value.Arg; 780 Argument2 = Argument1->Common.Next; 781 Target = Argument2->Common.Next; 782 783 if (!AcpiDmIsValidTarget (Target) || 784 !AcpiDmIsValidTarget (Target->Common.Next)) 785 { 786 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 787 return (TRUE); 788 } 789 break; 790 791 case AML_BIT_NOT_OP: 792 793 /* This operator has one operand and one target */ 794 795 Argument1 = StoreArgument->Common.Value.Arg; 796 Target = Argument1->Common.Next; 797 798 if (!AcpiDmIsValidTarget (Target)) 799 { 800 StoreOp->Common.DisasmFlags |= ACPI_PARSEOP_LEGACY_ASL_ONLY; 801 return (TRUE); 802 } 803 break; 804 805 default: 806 break; 807 } 808 809 return (FALSE); 810 } 811 812 813 /******************************************************************************* 814 * 815 * FUNCTION: AcpiDmCloseOperator 816 * 817 * PARAMETERS: Op - Current parse object 818 * 819 * RETURN: None 820 * 821 * DESCRIPTION: Closes an operator by adding a closing parentheses if and 822 * when necessary. Called during ascending phase of the 823 * parse tree walk. 824 * 825 ******************************************************************************/ 826 827 void 828 AcpiDmCloseOperator ( 829 ACPI_PARSE_OBJECT *Op) 830 { 831 832 /* Always emit paren if ASL+ disassembly disabled */ 833 834 if (!AcpiGbl_CstyleDisassembly) 835 { 836 AcpiOsPrintf (")"); 837 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 838 return; 839 } 840 841 if (Op->Common.DisasmFlags & ACPI_PARSEOP_LEGACY_ASL_ONLY) 842 { 843 AcpiOsPrintf (")"); 844 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 845 return; 846 } 847 848 /* Check if we need to add an additional closing paren */ 849 850 switch (Op->Common.AmlOpcode) 851 { 852 case AML_ADD_OP: 853 case AML_SUBTRACT_OP: 854 case AML_MULTIPLY_OP: 855 case AML_DIVIDE_OP: 856 case AML_MOD_OP: 857 case AML_SHIFT_LEFT_OP: 858 case AML_SHIFT_RIGHT_OP: 859 case AML_BIT_AND_OP: 860 case AML_BIT_OR_OP: 861 case AML_BIT_XOR_OP: 862 case AML_LOGICAL_AND_OP: 863 case AML_LOGICAL_EQUAL_OP: 864 case AML_LOGICAL_GREATER_OP: 865 case AML_LOGICAL_LESS_OP: 866 case AML_LOGICAL_OR_OP: 867 868 /* Emit paren only if this is not a compound assignment */ 869 870 if (Op->Common.DisasmFlags & ACPI_PARSEOP_COMPOUND_ASSIGNMENT) 871 { 872 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 873 return; 874 } 875 876 /* Emit extra close paren for assignment within an expression */ 877 878 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ASSIGNMENT) 879 { 880 AcpiOsPrintf (")"); 881 } 882 break; 883 884 case AML_INDEX_OP: 885 886 /* This is case for unsupported Index() source constants */ 887 888 if (Op->Common.DisasmFlags & ACPI_PARSEOP_CLOSING_PAREN) 889 { 890 AcpiOsPrintf (")"); 891 } 892 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 893 return; 894 895 /* No need for parens for these */ 896 897 case AML_DECREMENT_OP: 898 case AML_INCREMENT_OP: 899 case AML_LOGICAL_NOT_OP: 900 case AML_BIT_NOT_OP: 901 case AML_STORE_OP: 902 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 903 return; 904 905 default: 906 907 /* Always emit paren for non-ASL+ operators */ 908 break; 909 } 910 911 AcpiOsPrintf (")"); 912 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 913 914 return; 915 } 916 917 918 /******************************************************************************* 919 * 920 * FUNCTION: AcpiDmGetCompoundSymbol 921 * 922 * PARAMETERS: AslOpcode 923 * 924 * RETURN: String containing the compound assignment symbol 925 * 926 * DESCRIPTION: Detect opcodes that can be converted to compound assignment, 927 * return the appropriate operator string. 928 * 929 ******************************************************************************/ 930 931 static char * 932 AcpiDmGetCompoundSymbol ( 933 UINT16 AmlOpcode) 934 { 935 char *Symbol; 936 937 938 switch (AmlOpcode) 939 { 940 case AML_ADD_OP: 941 Symbol = " += "; 942 break; 943 944 case AML_SUBTRACT_OP: 945 Symbol = " -= "; 946 break; 947 948 case AML_MULTIPLY_OP: 949 Symbol = " *= "; 950 break; 951 952 case AML_DIVIDE_OP: 953 Symbol = " /= "; 954 break; 955 956 case AML_MOD_OP: 957 Symbol = " %= "; 958 break; 959 960 case AML_SHIFT_LEFT_OP: 961 Symbol = " <<= "; 962 break; 963 964 case AML_SHIFT_RIGHT_OP: 965 Symbol = " >>= "; 966 break; 967 968 case AML_BIT_AND_OP: 969 Symbol = " &= "; 970 break; 971 972 case AML_BIT_OR_OP: 973 Symbol = " |= "; 974 break; 975 976 case AML_BIT_XOR_OP: 977 Symbol = " ^= "; 978 break; 979 980 default: 981 982 /* No operator string for all other opcodes */ 983 984 return (NULL); 985 } 986 987 return (Symbol); 988 } 989 990 991 /******************************************************************************* 992 * 993 * FUNCTION: AcpiDmPromoteTarget 994 * 995 * PARAMETERS: Op - Operator parse object 996 * Target - Target associate with the Op 997 * 998 * RETURN: None 999 * 1000 * DESCRIPTION: Transform the parse tree by moving the target up to the first 1001 * child of the Op. 1002 * 1003 ******************************************************************************/ 1004 1005 static void 1006 AcpiDmPromoteTarget ( 1007 ACPI_PARSE_OBJECT *Op, 1008 ACPI_PARSE_OBJECT *Target) 1009 { 1010 ACPI_PARSE_OBJECT *Child; 1011 1012 1013 /* Link target directly to the Op as first child */ 1014 1015 Child = Op->Common.Value.Arg; 1016 Op->Common.Value.Arg = Target; 1017 Target->Common.Next = Child; 1018 1019 /* Find the last peer, it is linked to the target. Unlink it. */ 1020 1021 while (Child->Common.Next != Target) 1022 { 1023 Child = Child->Common.Next; 1024 } 1025 1026 Child->Common.Next = NULL; 1027 } 1028 1029 1030 /******************************************************************************* 1031 * 1032 * FUNCTION: AcpiDmIsValidTarget 1033 * 1034 * PARAMETERS: Target - Target Op from the parse tree 1035 * 1036 * RETURN: TRUE if the Target is real. FALSE if it is just a placeholder 1037 * Op that was inserted by the parser. 1038 * 1039 * DESCRIPTION: Determine if a Target Op is a placeholder Op or a real Target. 1040 * In other words, determine if the optional target is used or 1041 * not. Note: If Target is NULL, something is seriously wrong, 1042 * probably with the parse tree. 1043 * 1044 ******************************************************************************/ 1045 1046 static BOOLEAN 1047 AcpiDmIsValidTarget ( 1048 ACPI_PARSE_OBJECT *Target) 1049 { 1050 1051 if (!Target) 1052 { 1053 return (FALSE); 1054 } 1055 1056 if ((Target->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && 1057 (Target->Common.Value.Arg == NULL)) 1058 { 1059 return (FALSE); 1060 } 1061 1062 return (TRUE); 1063 } 1064 1065 1066 /******************************************************************************* 1067 * 1068 * FUNCTION: AcpiDmIsTargetAnOperand 1069 * 1070 * PARAMETERS: Target - Target associated with the expression 1071 * Operand - An operand associated with expression 1072 * 1073 * RETURN: TRUE if expression can be converted to a compound assignment. 1074 * FALSE otherwise. 1075 * 1076 * DESCRIPTION: Determine if the Target duplicates the operand, in order to 1077 * detect if the expression can be converted to a compound 1078 * assignment. (+=, *=, etc.) 1079 * 1080 ******************************************************************************/ 1081 1082 static BOOLEAN 1083 AcpiDmIsTargetAnOperand ( 1084 ACPI_PARSE_OBJECT *Target, 1085 ACPI_PARSE_OBJECT *Operand, 1086 BOOLEAN TopLevel) 1087 { 1088 const ACPI_OPCODE_INFO *OpInfo; 1089 BOOLEAN Same; 1090 1091 1092 /* 1093 * Opcodes must match. Note: ignoring the difference between nameseg 1094 * and namepath for now. May be needed later. 1095 */ 1096 if (Target->Common.AmlOpcode != Operand->Common.AmlOpcode) 1097 { 1098 return (FALSE); 1099 } 1100 1101 /* Nodes should match, even if they are NULL */ 1102 1103 if (Target->Common.Node != Operand->Common.Node) 1104 { 1105 return (FALSE); 1106 } 1107 1108 /* Determine if a child exists */ 1109 1110 OpInfo = AcpiPsGetOpcodeInfo (Operand->Common.AmlOpcode); 1111 if (OpInfo->Flags & AML_HAS_ARGS) 1112 { 1113 Same = AcpiDmIsTargetAnOperand (Target->Common.Value.Arg, 1114 Operand->Common.Value.Arg, FALSE); 1115 if (!Same) 1116 { 1117 return (FALSE); 1118 } 1119 } 1120 1121 /* Check the next peer, as long as we are not at the top level */ 1122 1123 if ((!TopLevel) && 1124 Target->Common.Next) 1125 { 1126 Same = AcpiDmIsTargetAnOperand (Target->Common.Next, 1127 Operand->Common.Next, FALSE); 1128 if (!Same) 1129 { 1130 return (FALSE); 1131 } 1132 } 1133 1134 /* Suppress the duplicate operand at the top-level */ 1135 1136 if (TopLevel) 1137 { 1138 Operand->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1139 } 1140 return (TRUE); 1141 } 1142