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