1 /******************************************************************************* 2 * 3 * Module Name: dmopcode - AML disassembler, specific AML opcodes 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2021, 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 MERCHANTABILITY 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 "acpi.h" 45 #include "accommon.h" 46 #include "acparser.h" 47 #include "amlcode.h" 48 #include "acinterp.h" 49 #include "acnamesp.h" 50 #include "acdebug.h" 51 #include "acconvert.h" 52 53 54 #define _COMPONENT ACPI_CA_DEBUGGER 55 ACPI_MODULE_NAME ("dmopcode") 56 57 58 /* Local prototypes */ 59 60 static void 61 AcpiDmMatchKeyword ( 62 ACPI_PARSE_OBJECT *Op); 63 64 static void 65 AcpiDmConvertToElseIf ( 66 ACPI_PARSE_OBJECT *Op); 67 68 static void 69 AcpiDmPromoteSubtree ( 70 ACPI_PARSE_OBJECT *StartOp); 71 72 /******************************************************************************* 73 * 74 * FUNCTION: AcpiDmDisplayTargetPathname 75 * 76 * PARAMETERS: Op - Parse object 77 * 78 * RETURN: None 79 * 80 * DESCRIPTION: For AML opcodes that have a target operand, display the full 81 * pathname for the target, in a comment field. Handles Return() 82 * statements also. 83 * 84 ******************************************************************************/ 85 86 void 87 AcpiDmDisplayTargetPathname ( 88 ACPI_PARSE_OBJECT *Op) 89 { 90 ACPI_PARSE_OBJECT *NextOp; 91 ACPI_PARSE_OBJECT *PrevOp = NULL; 92 char *Pathname; 93 const ACPI_OPCODE_INFO *OpInfo; 94 95 96 if (Op->Common.AmlOpcode == AML_RETURN_OP) 97 { 98 PrevOp = Op->Asl.Value.Arg; 99 } 100 else 101 { 102 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 103 if (!(OpInfo->Flags & AML_HAS_TARGET)) 104 { 105 return; 106 } 107 108 /* Target is the last Op in the arg list */ 109 110 NextOp = Op->Asl.Value.Arg; 111 while (NextOp) 112 { 113 PrevOp = NextOp; 114 NextOp = PrevOp->Asl.Next; 115 } 116 } 117 118 if (!PrevOp) 119 { 120 return; 121 } 122 123 /* We must have a namepath AML opcode */ 124 125 if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP) 126 { 127 return; 128 } 129 130 /* A null string is the "no target specified" case */ 131 132 if (!PrevOp->Asl.Value.String) 133 { 134 return; 135 } 136 137 /* No node means "unresolved external reference" */ 138 139 if (!PrevOp->Asl.Node) 140 { 141 AcpiOsPrintf (" /* External reference */"); 142 return; 143 } 144 145 /* Ignore if path is already from the root */ 146 147 if (*PrevOp->Asl.Value.String == '\\') 148 { 149 return; 150 } 151 152 /* Now: we can get the full pathname */ 153 154 Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node); 155 if (!Pathname) 156 { 157 return; 158 } 159 160 AcpiOsPrintf (" /* %s */", Pathname); 161 ACPI_FREE (Pathname); 162 } 163 164 165 /******************************************************************************* 166 * 167 * FUNCTION: AcpiDmNotifyDescription 168 * 169 * PARAMETERS: Op - Name() parse object 170 * 171 * RETURN: None 172 * 173 * DESCRIPTION: Emit a description comment for the value associated with a 174 * Notify() operator. 175 * 176 ******************************************************************************/ 177 178 void 179 AcpiDmNotifyDescription ( 180 ACPI_PARSE_OBJECT *Op) 181 { 182 ACPI_PARSE_OBJECT *NextOp; 183 ACPI_NAMESPACE_NODE *Node; 184 UINT8 NotifyValue; 185 UINT8 Type = ACPI_TYPE_ANY; 186 187 188 /* The notify value is the second argument */ 189 190 NextOp = Op->Asl.Value.Arg; 191 NextOp = NextOp->Asl.Next; 192 193 switch (NextOp->Common.AmlOpcode) 194 { 195 case AML_ZERO_OP: 196 case AML_ONE_OP: 197 198 NotifyValue = (UINT8) NextOp->Common.AmlOpcode; 199 break; 200 201 case AML_BYTE_OP: 202 203 NotifyValue = (UINT8) NextOp->Asl.Value.Integer; 204 break; 205 206 default: 207 return; 208 } 209 210 /* 211 * Attempt to get the namespace node so we can determine the object type. 212 * Some notify values are dependent on the object type (Device, Thermal, 213 * or Processor). 214 */ 215 Node = Op->Asl.Node; 216 if (Node) 217 { 218 Type = Node->Type; 219 } 220 221 AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type)); 222 } 223 224 225 /******************************************************************************* 226 * 227 * FUNCTION: AcpiDmPredefinedDescription 228 * 229 * PARAMETERS: Op - Name() parse object 230 * 231 * RETURN: None 232 * 233 * DESCRIPTION: Emit a description comment for a predefined ACPI name. 234 * Used for iASL compiler only. 235 * 236 ******************************************************************************/ 237 238 void 239 AcpiDmPredefinedDescription ( 240 ACPI_PARSE_OBJECT *Op) 241 { 242 #ifdef ACPI_ASL_COMPILER 243 const AH_PREDEFINED_NAME *Info; 244 char *NameString; 245 int LastCharIsDigit; 246 int LastCharsAreHex; 247 248 249 if (!Op) 250 { 251 return; 252 } 253 254 /* Ensure that the comment field is emitted only once */ 255 256 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED) 257 { 258 return; 259 } 260 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED; 261 262 /* Predefined name must start with an underscore */ 263 264 NameString = ACPI_CAST_PTR (char, &Op->Named.Name); 265 if (NameString[0] != '_') 266 { 267 return; 268 } 269 270 /* 271 * Check for the special ACPI names: 272 * _ACd, _ALd, _EJd, _Exx, _Lxx, _Qxx, _Wxx, _T_a 273 * (where d=decimal_digit, x=hex_digit, a=anything) 274 * 275 * Convert these to the generic name for table lookup. 276 * Note: NameString is guaranteed to be upper case here. 277 */ 278 LastCharIsDigit = 279 (isdigit ((int) NameString[3])); /* d */ 280 LastCharsAreHex = 281 (isxdigit ((int) NameString[2]) && /* xx */ 282 isxdigit ((int) NameString[3])); 283 284 switch (NameString[1]) 285 { 286 case 'A': 287 288 if ((NameString[2] == 'C') && (LastCharIsDigit)) 289 { 290 NameString = "_ACx"; 291 } 292 else if ((NameString[2] == 'L') && (LastCharIsDigit)) 293 { 294 NameString = "_ALx"; 295 } 296 break; 297 298 case 'E': 299 300 if ((NameString[2] == 'J') && (LastCharIsDigit)) 301 { 302 NameString = "_EJx"; 303 } 304 else if (LastCharsAreHex) 305 { 306 NameString = "_Exx"; 307 } 308 break; 309 310 case 'L': 311 312 if (LastCharsAreHex) 313 { 314 NameString = "_Lxx"; 315 } 316 break; 317 318 case 'Q': 319 320 if (LastCharsAreHex) 321 { 322 NameString = "_Qxx"; 323 } 324 break; 325 326 case 'T': 327 328 if (NameString[2] == '_') 329 { 330 NameString = "_T_x"; 331 } 332 break; 333 334 case 'W': 335 336 if (LastCharsAreHex) 337 { 338 NameString = "_Wxx"; 339 } 340 break; 341 342 default: 343 344 break; 345 } 346 347 /* Match the name in the info table */ 348 349 Info = AcpiAhMatchPredefinedName (NameString); 350 if (Info) 351 { 352 AcpiOsPrintf (" // %4.4s: %s", 353 NameString, ACPI_CAST_PTR (char, Info->Description)); 354 } 355 356 #endif 357 return; 358 } 359 360 361 /******************************************************************************* 362 * 363 * FUNCTION: AcpiDmFieldPredefinedDescription 364 * 365 * PARAMETERS: Op - Parse object 366 * 367 * RETURN: None 368 * 369 * DESCRIPTION: Emit a description comment for a resource descriptor tag 370 * (which is a predefined ACPI name.) Used for iASL compiler only. 371 * 372 ******************************************************************************/ 373 374 void 375 AcpiDmFieldPredefinedDescription ( 376 ACPI_PARSE_OBJECT *Op) 377 { 378 #ifdef ACPI_ASL_COMPILER 379 ACPI_PARSE_OBJECT *IndexOp; 380 char *Tag; 381 const ACPI_OPCODE_INFO *OpInfo; 382 const AH_PREDEFINED_NAME *Info; 383 384 385 if (!Op) 386 { 387 return; 388 } 389 390 /* Ensure that the comment field is emitted only once */ 391 392 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED) 393 { 394 return; 395 } 396 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED; 397 398 /* 399 * Op must be one of the Create* operators: CreateField, CreateBitField, 400 * CreateByteField, CreateWordField, CreateDwordField, CreateQwordField 401 */ 402 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 403 if (!(OpInfo->Flags & AML_CREATE)) 404 { 405 return; 406 } 407 408 /* Second argument is the Index argument */ 409 410 IndexOp = Op->Common.Value.Arg; 411 IndexOp = IndexOp->Common.Next; 412 413 /* Index argument must be a namepath */ 414 415 if (IndexOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP) 416 { 417 return; 418 } 419 420 /* Major cheat: We previously put the Tag ptr in the Node field */ 421 422 Tag = ACPI_CAST_PTR (char, IndexOp->Common.Node); 423 if (!Tag || (*Tag == 0)) 424 { 425 return; 426 } 427 428 /* Is the tag a predefined name? */ 429 430 Info = AcpiAhMatchPredefinedName (Tag); 431 if (!Info) 432 { 433 /* Not a predefined name (does not start with underscore) */ 434 435 return; 436 } 437 438 AcpiOsPrintf (" // %4.4s: %s", Tag, 439 ACPI_CAST_PTR (char, Info->Description)); 440 441 /* String contains the prefix path, free it */ 442 443 ACPI_FREE (IndexOp->Common.Value.String); 444 IndexOp->Common.Value.String = NULL; 445 #endif 446 447 return; 448 } 449 450 451 /******************************************************************************* 452 * 453 * FUNCTION: AcpiDmMethodFlags 454 * 455 * PARAMETERS: Op - Method Object to be examined 456 * 457 * RETURN: None 458 * 459 * DESCRIPTION: Decode control method flags 460 * 461 ******************************************************************************/ 462 463 void 464 AcpiDmMethodFlags ( 465 ACPI_PARSE_OBJECT *Op) 466 { 467 UINT32 Flags; 468 UINT32 Args; 469 470 471 /* The next Op contains the flags */ 472 473 Op = AcpiPsGetDepthNext (NULL, Op); 474 Flags = (UINT8) Op->Common.Value.Integer; 475 Args = Flags & 0x07; 476 477 /* Mark the Op as completed */ 478 479 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 480 481 /* 1) Method argument count */ 482 483 AcpiOsPrintf (", %u, ", Args); 484 485 /* 2) Serialize rule */ 486 487 if (!(Flags & 0x08)) 488 { 489 AcpiOsPrintf ("Not"); 490 } 491 492 AcpiOsPrintf ("Serialized"); 493 494 /* 3) SyncLevel */ 495 496 if (Flags & 0xF0) 497 { 498 AcpiOsPrintf (", %u", Flags >> 4); 499 } 500 } 501 502 503 /******************************************************************************* 504 * 505 * FUNCTION: AcpiDmFieldFlags 506 * 507 * PARAMETERS: Op - Field Object to be examined 508 * 509 * RETURN: None 510 * 511 * DESCRIPTION: Decode Field definition flags 512 * 513 ******************************************************************************/ 514 515 void 516 AcpiDmFieldFlags ( 517 ACPI_PARSE_OBJECT *Op) 518 { 519 UINT32 Flags; 520 521 522 Op = Op->Common.Next; 523 Flags = (UINT8) Op->Common.Value.Integer; 524 525 /* Mark the Op as completed */ 526 527 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 528 529 AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]); 530 AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]); 531 AcpiOsPrintf ("%s)", AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]); 532 } 533 534 535 /******************************************************************************* 536 * 537 * FUNCTION: AcpiDmAddressSpace 538 * 539 * PARAMETERS: SpaceId - ID to be translated 540 * 541 * RETURN: None 542 * 543 * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword 544 * 545 ******************************************************************************/ 546 547 void 548 AcpiDmAddressSpace ( 549 UINT8 SpaceId) 550 { 551 552 if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) 553 { 554 if (SpaceId == 0x7F) 555 { 556 AcpiOsPrintf ("FFixedHW, "); 557 } 558 else 559 { 560 AcpiOsPrintf ("0x%.2X, ", SpaceId); 561 } 562 } 563 else 564 { 565 AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]); 566 } 567 } 568 569 570 /******************************************************************************* 571 * 572 * FUNCTION: AcpiDmRegionFlags 573 * 574 * PARAMETERS: Op - Object to be examined 575 * 576 * RETURN: None 577 * 578 * DESCRIPTION: Decode OperationRegion flags 579 * 580 ******************************************************************************/ 581 582 void 583 AcpiDmRegionFlags ( 584 ACPI_PARSE_OBJECT *Op) 585 { 586 587 /* The next Op contains the SpaceId */ 588 589 Op = AcpiPsGetDepthNext (NULL, Op); 590 591 /* Mark the Op as completed */ 592 593 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 594 595 AcpiOsPrintf (", "); 596 AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer); 597 } 598 599 600 /******************************************************************************* 601 * 602 * FUNCTION: AcpiDmMatchOp 603 * 604 * PARAMETERS: Op - Match Object to be examined 605 * 606 * RETURN: None 607 * 608 * DESCRIPTION: Decode Match opcode operands 609 * 610 ******************************************************************************/ 611 612 void 613 AcpiDmMatchOp ( 614 ACPI_PARSE_OBJECT *Op) 615 { 616 ACPI_PARSE_OBJECT *NextOp; 617 618 619 NextOp = AcpiPsGetDepthNext (NULL, Op); 620 NextOp = NextOp->Common.Next; 621 622 if (!NextOp) 623 { 624 /* Handle partial tree during single-step */ 625 626 return; 627 } 628 629 /* Mark the two nodes that contain the encoding for the match keywords */ 630 631 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 632 633 NextOp = NextOp->Common.Next; 634 NextOp = NextOp->Common.Next; 635 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 636 } 637 638 639 /******************************************************************************* 640 * 641 * FUNCTION: AcpiDmMatchKeyword 642 * 643 * PARAMETERS: Op - Match Object to be examined 644 * 645 * RETURN: None 646 * 647 * DESCRIPTION: Decode Match opcode operands 648 * 649 ******************************************************************************/ 650 651 static void 652 AcpiDmMatchKeyword ( 653 ACPI_PARSE_OBJECT *Op) 654 { 655 656 if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE) 657 { 658 AcpiOsPrintf ("/* Unknown Match Keyword encoding */"); 659 } 660 else 661 { 662 AcpiOsPrintf ("%s", 663 AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer]); 664 } 665 } 666 667 668 /******************************************************************************* 669 * 670 * FUNCTION: AcpiDmDisassembleOneOp 671 * 672 * PARAMETERS: WalkState - Current walk info 673 * Info - Parse tree walk info 674 * Op - Op that is to be printed 675 * 676 * RETURN: None 677 * 678 * DESCRIPTION: Disassemble a single AML opcode 679 * 680 ******************************************************************************/ 681 682 void 683 AcpiDmDisassembleOneOp ( 684 ACPI_WALK_STATE *WalkState, 685 ACPI_OP_WALK_INFO *Info, 686 ACPI_PARSE_OBJECT *Op) 687 { 688 const ACPI_OPCODE_INFO *OpInfo = NULL; 689 UINT32 Offset; 690 UINT32 Length; 691 ACPI_PARSE_OBJECT *Child; 692 ACPI_STATUS Status; 693 UINT8 *Aml; 694 const AH_DEVICE_ID *IdInfo; 695 696 697 if (!Op) 698 { 699 AcpiOsPrintf ("<NULL OP PTR>"); 700 return; 701 } 702 703 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF) 704 { 705 return; /* ElseIf macro was already emitted */ 706 } 707 708 switch (Op->Common.DisasmOpcode) 709 { 710 case ACPI_DASM_MATCHOP: 711 712 AcpiDmMatchKeyword (Op); 713 return; 714 715 case ACPI_DASM_LNOT_SUFFIX: 716 717 if (!AcpiGbl_CstyleDisassembly) 718 { 719 switch (Op->Common.AmlOpcode) 720 { 721 case AML_LOGICAL_EQUAL_OP: 722 AcpiOsPrintf ("LNotEqual"); 723 break; 724 725 case AML_LOGICAL_GREATER_OP: 726 AcpiOsPrintf ("LLessEqual"); 727 break; 728 729 case AML_LOGICAL_LESS_OP: 730 AcpiOsPrintf ("LGreaterEqual"); 731 break; 732 733 default: 734 break; 735 } 736 } 737 738 Op->Common.DisasmOpcode = 0; 739 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 740 return; 741 742 default: 743 break; 744 } 745 746 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 747 748 /* The op and arguments */ 749 750 switch (Op->Common.AmlOpcode) 751 { 752 case AML_LOGICAL_NOT_OP: 753 754 Child = Op->Common.Value.Arg; 755 if ((Child->Common.AmlOpcode == AML_LOGICAL_EQUAL_OP) || 756 (Child->Common.AmlOpcode == AML_LOGICAL_GREATER_OP) || 757 (Child->Common.AmlOpcode == AML_LOGICAL_LESS_OP)) 758 { 759 Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 760 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 761 } 762 else 763 { 764 AcpiOsPrintf ("%s", OpInfo->Name); 765 } 766 break; 767 768 case AML_BYTE_OP: 769 770 AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer); 771 break; 772 773 case AML_WORD_OP: 774 775 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 776 { 777 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 778 } 779 else 780 { 781 AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer); 782 } 783 break; 784 785 case AML_DWORD_OP: 786 787 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 788 { 789 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 790 } 791 else 792 { 793 AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer); 794 } 795 break; 796 797 case AML_QWORD_OP: 798 799 AcpiOsPrintf ("0x%8.8X%8.8X", 800 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); 801 break; 802 803 case AML_STRING_OP: 804 805 AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX); 806 807 /* For _HID/_CID strings, attempt to output a descriptive comment */ 808 809 if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING) 810 { 811 /* If we know about the ID, emit the description */ 812 813 IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String); 814 if (IdInfo) 815 { 816 AcpiOsPrintf (" /* %s */", IdInfo->Description); 817 } 818 } 819 break; 820 821 case AML_BUFFER_OP: 822 /* 823 * Determine the type of buffer. We can have one of the following: 824 * 825 * 1) ResourceTemplate containing Resource Descriptors. 826 * 2) Unicode String buffer 827 * 3) ASCII String buffer 828 * 4) Raw data buffer (if none of the above) 829 * 830 * Since there are no special AML opcodes to differentiate these 831 * types of buffers, we have to closely look at the data in the 832 * buffer to determine the type. 833 */ 834 if (!AcpiGbl_NoResourceDisassembly) 835 { 836 Status = AcpiDmIsResourceTemplate (WalkState, Op); 837 if (ACPI_SUCCESS (Status)) 838 { 839 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 840 AcpiOsPrintf ("ResourceTemplate"); 841 break; 842 } 843 else if (Status == AE_AML_NO_RESOURCE_END_TAG) 844 { 845 AcpiOsPrintf ( 846 "/**** Is ResourceTemplate, " 847 "but EndTag not at buffer end ****/ "); 848 } 849 } 850 851 if (AcpiDmIsUuidBuffer (Op)) 852 { 853 Op->Common.DisasmOpcode = ACPI_DASM_UUID; 854 AcpiOsPrintf ("ToUUID ("); 855 } 856 else if (AcpiDmIsUnicodeBuffer (Op)) 857 { 858 Op->Common.DisasmOpcode = ACPI_DASM_UNICODE; 859 AcpiOsPrintf ("Unicode ("); 860 } 861 else if (AcpiDmIsStringBuffer (Op)) 862 { 863 Op->Common.DisasmOpcode = ACPI_DASM_STRING; 864 AcpiOsPrintf ("Buffer"); 865 } 866 else if (AcpiDmIsPldBuffer (Op)) 867 { 868 Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD; 869 AcpiOsPrintf ("ToPLD ("); 870 } 871 else 872 { 873 Op->Common.DisasmOpcode = ACPI_DASM_BUFFER; 874 AcpiOsPrintf ("Buffer"); 875 } 876 break; 877 878 case AML_INT_NAMEPATH_OP: 879 880 AcpiDmNamestring (Op->Common.Value.Name); 881 break; 882 883 case AML_INT_NAMEDFIELD_OP: 884 885 Length = AcpiDmDumpName (Op->Named.Name); 886 887 AcpiOsPrintf (","); 888 ASL_CV_PRINT_ONE_COMMENT (Op, AML_NAMECOMMENT, NULL, 0); 889 AcpiOsPrintf ("%*.s %u", (unsigned) (5 - Length), " ", 890 (UINT32) Op->Common.Value.Integer); 891 892 AcpiDmCommaIfFieldMember (Op); 893 894 Info->BitOffset += (UINT32) Op->Common.Value.Integer; 895 break; 896 897 case AML_INT_RESERVEDFIELD_OP: 898 899 /* Offset() -- Must account for previous offsets */ 900 901 Offset = (UINT32) Op->Common.Value.Integer; 902 Info->BitOffset += Offset; 903 904 if (Info->BitOffset % 8 == 0) 905 { 906 AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset)); 907 } 908 else 909 { 910 AcpiOsPrintf (" , %u", Offset); 911 } 912 913 AcpiDmCommaIfFieldMember (Op); 914 break; 915 916 case AML_INT_ACCESSFIELD_OP: 917 case AML_INT_EXTACCESSFIELD_OP: 918 919 AcpiOsPrintf ("AccessAs (%s, ", 920 AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]); 921 922 AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8)); 923 924 if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP) 925 { 926 AcpiOsPrintf (" (0x%2.2X)", (unsigned) 927 ((Op->Common.Value.Integer >> 16) & 0xFF)); 928 } 929 930 AcpiOsPrintf (")"); 931 AcpiDmCommaIfFieldMember (Op); 932 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 933 break; 934 935 case AML_INT_CONNECTION_OP: 936 /* 937 * Two types of Connection() - one with a buffer object, the 938 * other with a namestring that points to a buffer object. 939 */ 940 AcpiOsPrintf ("Connection ("); 941 Child = Op->Common.Value.Arg; 942 943 if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP) 944 { 945 AcpiOsPrintf ("\n"); 946 947 Aml = Child->Named.Data; 948 Length = (UINT32) Child->Common.Value.Integer; 949 950 Info->Level += 1; 951 Info->MappingOp = Op; 952 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 953 954 AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length); 955 956 Info->Level -= 1; 957 AcpiDmIndent (Info->Level); 958 } 959 else 960 { 961 AcpiDmNamestring (Child->Common.Value.Name); 962 } 963 964 AcpiOsPrintf (")"); 965 AcpiDmCommaIfFieldMember (Op); 966 ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0); 967 ASL_CV_PRINT_ONE_COMMENT (Op, AMLCOMMENT_INLINE, NULL, 0); 968 AcpiOsPrintf ("\n"); 969 970 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */ 971 Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 972 break; 973 974 case AML_INT_BYTELIST_OP: 975 976 AcpiDmByteList (Info, Op); 977 break; 978 979 case AML_INT_METHODCALL_OP: 980 981 Op = AcpiPsGetDepthNext (NULL, Op); 982 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 983 984 AcpiDmNamestring (Op->Common.Value.Name); 985 break; 986 987 case AML_WHILE_OP: 988 989 if (Op->Common.DisasmOpcode == ACPI_DASM_SWITCH) 990 { 991 AcpiOsPrintf ("%s", "Switch"); 992 break; 993 } 994 995 AcpiOsPrintf ("%s", OpInfo->Name); 996 break; 997 998 case AML_IF_OP: 999 1000 if (Op->Common.DisasmOpcode == ACPI_DASM_CASE) 1001 { 1002 AcpiOsPrintf ("%s", "Case"); 1003 break; 1004 } 1005 1006 AcpiOsPrintf ("%s", OpInfo->Name); 1007 break; 1008 1009 case AML_ELSE_OP: 1010 1011 AcpiDmConvertToElseIf (Op); 1012 break; 1013 1014 case AML_EXTERNAL_OP: 1015 1016 if (AcpiGbl_DmEmitExternalOpcodes) 1017 { 1018 AcpiDmEmitExternal (Op, AcpiPsGetArg(Op, 0)); 1019 } 1020 1021 break; 1022 1023 default: 1024 1025 /* Just get the opcode name and print it */ 1026 1027 AcpiOsPrintf ("%s", OpInfo->Name); 1028 1029 1030 #ifdef ACPI_DEBUGGER 1031 1032 if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) && 1033 (WalkState) && 1034 (WalkState->Results) && 1035 (WalkState->ResultCount)) 1036 { 1037 AcpiDbDecodeInternalObject ( 1038 WalkState->Results->Results.ObjDesc [ 1039 (WalkState->ResultCount - 1) % 1040 ACPI_RESULTS_FRAME_OBJ_NUM]); 1041 } 1042 #endif 1043 1044 break; 1045 } 1046 } 1047 1048 1049 /******************************************************************************* 1050 * 1051 * FUNCTION: AcpiDmConvertToElseIf 1052 * 1053 * PARAMETERS: OriginalElseOp - ELSE Object to be examined 1054 * 1055 * RETURN: None. Emits either an "Else" or an "ElseIf" ASL operator. 1056 * 1057 * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf 1058 * 1059 * EXAMPLE: 1060 * 1061 * This If..Else..If nested sequence: 1062 * 1063 * If (Arg0 == 1) 1064 * { 1065 * Local0 = 4 1066 * } 1067 * Else 1068 * { 1069 * If (Arg0 == 2) 1070 * { 1071 * Local0 = 5 1072 * } 1073 * } 1074 * 1075 * Is converted to this simpler If..ElseIf sequence: 1076 * 1077 * If (Arg0 == 1) 1078 * { 1079 * Local0 = 4 1080 * } 1081 * ElseIf (Arg0 == 2) 1082 * { 1083 * Local0 = 5 1084 * } 1085 * 1086 * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL 1087 * macro that emits an Else opcode followed by an If opcode. This function 1088 * reverses these AML sequences back to an ElseIf macro where possible. This 1089 * can make the disassembled ASL code simpler and more like the original code. 1090 * 1091 ******************************************************************************/ 1092 1093 static void 1094 AcpiDmConvertToElseIf ( 1095 ACPI_PARSE_OBJECT *OriginalElseOp) 1096 { 1097 ACPI_PARSE_OBJECT *IfOp; 1098 ACPI_PARSE_OBJECT *ElseOp; 1099 1100 1101 /* 1102 * To be able to perform the conversion, two conditions must be satisfied: 1103 * 1) The first child of the Else must be an If statement. 1104 * 2) The If block can only be followed by an Else block and these must 1105 * be the only blocks under the original Else. 1106 */ 1107 IfOp = OriginalElseOp->Common.Value.Arg; 1108 1109 if (!IfOp || 1110 (IfOp->Common.AmlOpcode != AML_IF_OP) || 1111 (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP))) 1112 { 1113 /* Not a proper Else..If sequence, cannot convert to ElseIf */ 1114 1115 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1116 { 1117 AcpiOsPrintf ("%s", "Default"); 1118 return; 1119 } 1120 1121 AcpiOsPrintf ("%s", "Else"); 1122 return; 1123 } 1124 1125 /* Cannot have anything following the If...Else block */ 1126 1127 ElseOp = IfOp->Common.Next; 1128 if (ElseOp && ElseOp->Common.Next) 1129 { 1130 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1131 { 1132 AcpiOsPrintf ("%s", "Default"); 1133 return; 1134 } 1135 1136 AcpiOsPrintf ("%s", "Else"); 1137 return; 1138 } 1139 1140 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1141 { 1142 /* 1143 * There is an ElseIf but in this case the Else is actually 1144 * a Default block for a Switch/Case statement. No conversion. 1145 */ 1146 AcpiOsPrintf ("%s", "Default"); 1147 return; 1148 } 1149 1150 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_CASE) 1151 { 1152 /* 1153 * This ElseIf is actually a Case block for a Switch/Case 1154 * statement. Print Case but do not return so that we can 1155 * promote the subtree and keep the indentation level. 1156 */ 1157 AcpiOsPrintf ("%s", "Case"); 1158 } 1159 else 1160 { 1161 /* Emit ElseIf, mark the IF as now an ELSEIF */ 1162 1163 AcpiOsPrintf ("%s", "ElseIf"); 1164 } 1165 1166 IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF; 1167 1168 /* The IF parent will now be the same as the original ELSE parent */ 1169 1170 IfOp->Common.Parent = OriginalElseOp->Common.Parent; 1171 1172 /* 1173 * Update the NEXT pointers to restructure the parse tree, essentially 1174 * promoting an If..Else block up to the same level as the original 1175 * Else. 1176 * 1177 * Check if the IF has a corresponding ELSE peer 1178 */ 1179 ElseOp = IfOp->Common.Next; 1180 if (ElseOp && 1181 (ElseOp->Common.AmlOpcode == AML_ELSE_OP)) 1182 { 1183 /* If an ELSE matches the IF, promote it also */ 1184 1185 ElseOp->Common.Parent = OriginalElseOp->Common.Parent; 1186 1187 /* Promote the entire block under the ElseIf (All Next OPs) */ 1188 1189 AcpiDmPromoteSubtree (OriginalElseOp); 1190 } 1191 else 1192 { 1193 /* Otherwise, set the IF NEXT to the original ELSE NEXT */ 1194 1195 IfOp->Common.Next = OriginalElseOp->Common.Next; 1196 } 1197 1198 /* Detach the child IF block from the original ELSE */ 1199 1200 OriginalElseOp->Common.Value.Arg = NULL; 1201 1202 /* Ignore the original ELSE from now on */ 1203 1204 OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1205 OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 1206 1207 /* Insert IF (now ELSEIF) as next peer of the original ELSE */ 1208 1209 OriginalElseOp->Common.Next = IfOp; 1210 } 1211 1212 1213 /******************************************************************************* 1214 * 1215 * FUNCTION: AcpiDmPromoteSubtree 1216 * 1217 * PARAMETERS: StartOpOp - Original parent of the entire subtree 1218 * 1219 * RETURN: None 1220 * 1221 * DESCRIPTION: Promote an entire parse subtree up one level. 1222 * 1223 ******************************************************************************/ 1224 1225 static void 1226 AcpiDmPromoteSubtree ( 1227 ACPI_PARSE_OBJECT *StartOp) 1228 { 1229 ACPI_PARSE_OBJECT *Op; 1230 ACPI_PARSE_OBJECT *ParentOp; 1231 1232 1233 /* New parent for subtree elements */ 1234 1235 ParentOp = StartOp->Common.Parent; 1236 1237 /* First child starts the subtree */ 1238 1239 Op = StartOp->Common.Value.Arg; 1240 1241 /* Walk the top-level elements of the subtree */ 1242 1243 while (Op) 1244 { 1245 Op->Common.Parent = ParentOp; 1246 if (!Op->Common.Next) 1247 { 1248 /* Last Op in list, update its next field */ 1249 1250 Op->Common.Next = StartOp->Common.Next; 1251 break; 1252 } 1253 Op = Op->Common.Next; 1254 } 1255 } 1256