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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acparser.h> 47 #include <contrib/dev/acpica/include/amlcode.h> 48 #include <contrib/dev/acpica/include/acinterp.h> 49 #include <contrib/dev/acpica/include/acnamesp.h> 50 #include <contrib/dev/acpica/include/acdebug.h> 51 52 53 #define _COMPONENT ACPI_CA_DEBUGGER 54 ACPI_MODULE_NAME ("dmopcode") 55 56 57 /* Local prototypes */ 58 59 static void 60 AcpiDmMatchKeyword ( 61 ACPI_PARSE_OBJECT *Op); 62 63 static void 64 AcpiDmConvertToElseIf ( 65 ACPI_PARSE_OBJECT *Op); 66 67 static void 68 AcpiDmPromoteSubtree ( 69 ACPI_PARSE_OBJECT *StartOp); 70 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) 424 { 425 return; 426 } 427 428 /* Match the name in the info table */ 429 430 Info = AcpiAhMatchPredefinedName (Tag); 431 if (Info) 432 { 433 AcpiOsPrintf (" // %4.4s: %s", Tag, 434 ACPI_CAST_PTR (char, Info->Description)); 435 } 436 437 #endif 438 return; 439 } 440 441 442 /******************************************************************************* 443 * 444 * FUNCTION: AcpiDmMethodFlags 445 * 446 * PARAMETERS: Op - Method Object to be examined 447 * 448 * RETURN: None 449 * 450 * DESCRIPTION: Decode control method flags 451 * 452 ******************************************************************************/ 453 454 void 455 AcpiDmMethodFlags ( 456 ACPI_PARSE_OBJECT *Op) 457 { 458 UINT32 Flags; 459 UINT32 Args; 460 461 462 /* The next Op contains the flags */ 463 464 Op = AcpiPsGetDepthNext (NULL, Op); 465 Flags = (UINT8) Op->Common.Value.Integer; 466 Args = Flags & 0x07; 467 468 /* Mark the Op as completed */ 469 470 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 471 472 /* 1) Method argument count */ 473 474 AcpiOsPrintf (", %u, ", Args); 475 476 /* 2) Serialize rule */ 477 478 if (!(Flags & 0x08)) 479 { 480 AcpiOsPrintf ("Not"); 481 } 482 483 AcpiOsPrintf ("Serialized"); 484 485 /* 3) SyncLevel */ 486 487 if (Flags & 0xF0) 488 { 489 AcpiOsPrintf (", %u", Flags >> 4); 490 } 491 } 492 493 494 /******************************************************************************* 495 * 496 * FUNCTION: AcpiDmFieldFlags 497 * 498 * PARAMETERS: Op - Field Object to be examined 499 * 500 * RETURN: None 501 * 502 * DESCRIPTION: Decode Field definition flags 503 * 504 ******************************************************************************/ 505 506 void 507 AcpiDmFieldFlags ( 508 ACPI_PARSE_OBJECT *Op) 509 { 510 UINT32 Flags; 511 512 513 Op = Op->Common.Next; 514 Flags = (UINT8) Op->Common.Value.Integer; 515 516 /* Mark the Op as completed */ 517 518 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 519 520 AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]); 521 AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]); 522 AcpiOsPrintf ("%s)", AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]); 523 } 524 525 526 /******************************************************************************* 527 * 528 * FUNCTION: AcpiDmAddressSpace 529 * 530 * PARAMETERS: SpaceId - ID to be translated 531 * 532 * RETURN: None 533 * 534 * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword 535 * 536 ******************************************************************************/ 537 538 void 539 AcpiDmAddressSpace ( 540 UINT8 SpaceId) 541 { 542 543 if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) 544 { 545 if (SpaceId == 0x7F) 546 { 547 AcpiOsPrintf ("FFixedHW, "); 548 } 549 else 550 { 551 AcpiOsPrintf ("0x%.2X, ", SpaceId); 552 } 553 } 554 else 555 { 556 AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]); 557 } 558 } 559 560 561 /******************************************************************************* 562 * 563 * FUNCTION: AcpiDmRegionFlags 564 * 565 * PARAMETERS: Op - Object to be examined 566 * 567 * RETURN: None 568 * 569 * DESCRIPTION: Decode OperationRegion flags 570 * 571 ******************************************************************************/ 572 573 void 574 AcpiDmRegionFlags ( 575 ACPI_PARSE_OBJECT *Op) 576 { 577 578 /* The next Op contains the SpaceId */ 579 580 Op = AcpiPsGetDepthNext (NULL, Op); 581 582 /* Mark the Op as completed */ 583 584 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 585 586 AcpiOsPrintf (", "); 587 AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer); 588 } 589 590 591 /******************************************************************************* 592 * 593 * FUNCTION: AcpiDmMatchOp 594 * 595 * PARAMETERS: Op - Match Object to be examined 596 * 597 * RETURN: None 598 * 599 * DESCRIPTION: Decode Match opcode operands 600 * 601 ******************************************************************************/ 602 603 void 604 AcpiDmMatchOp ( 605 ACPI_PARSE_OBJECT *Op) 606 { 607 ACPI_PARSE_OBJECT *NextOp; 608 609 610 NextOp = AcpiPsGetDepthNext (NULL, Op); 611 NextOp = NextOp->Common.Next; 612 613 if (!NextOp) 614 { 615 /* Handle partial tree during single-step */ 616 617 return; 618 } 619 620 /* Mark the two nodes that contain the encoding for the match keywords */ 621 622 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 623 624 NextOp = NextOp->Common.Next; 625 NextOp = NextOp->Common.Next; 626 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 627 } 628 629 630 /******************************************************************************* 631 * 632 * FUNCTION: AcpiDmMatchKeyword 633 * 634 * PARAMETERS: Op - Match Object to be examined 635 * 636 * RETURN: None 637 * 638 * DESCRIPTION: Decode Match opcode operands 639 * 640 ******************************************************************************/ 641 642 static void 643 AcpiDmMatchKeyword ( 644 ACPI_PARSE_OBJECT *Op) 645 { 646 647 if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE) 648 { 649 AcpiOsPrintf ("/* Unknown Match Keyword encoding */"); 650 } 651 else 652 { 653 AcpiOsPrintf ("%s", 654 AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer]); 655 } 656 } 657 658 659 /******************************************************************************* 660 * 661 * FUNCTION: AcpiDmDisassembleOneOp 662 * 663 * PARAMETERS: WalkState - Current walk info 664 * Info - Parse tree walk info 665 * Op - Op that is to be printed 666 * 667 * RETURN: None 668 * 669 * DESCRIPTION: Disassemble a single AML opcode 670 * 671 ******************************************************************************/ 672 673 void 674 AcpiDmDisassembleOneOp ( 675 ACPI_WALK_STATE *WalkState, 676 ACPI_OP_WALK_INFO *Info, 677 ACPI_PARSE_OBJECT *Op) 678 { 679 const ACPI_OPCODE_INFO *OpInfo = NULL; 680 UINT32 Offset; 681 UINT32 Length; 682 ACPI_PARSE_OBJECT *Child; 683 ACPI_STATUS Status; 684 UINT8 *Aml; 685 const AH_DEVICE_ID *IdInfo; 686 687 688 if (!Op) 689 { 690 AcpiOsPrintf ("<NULL OP PTR>"); 691 return; 692 } 693 694 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF) 695 { 696 return; /* ElseIf macro was already emitted */ 697 } 698 699 switch (Op->Common.DisasmOpcode) 700 { 701 case ACPI_DASM_MATCHOP: 702 703 AcpiDmMatchKeyword (Op); 704 return; 705 706 case ACPI_DASM_LNOT_SUFFIX: 707 708 if (!AcpiGbl_CstyleDisassembly) 709 { 710 switch (Op->Common.AmlOpcode) 711 { 712 case AML_LEQUAL_OP: 713 AcpiOsPrintf ("LNotEqual"); 714 break; 715 716 case AML_LGREATER_OP: 717 AcpiOsPrintf ("LLessEqual"); 718 break; 719 720 case AML_LLESS_OP: 721 AcpiOsPrintf ("LGreaterEqual"); 722 break; 723 724 default: 725 break; 726 } 727 } 728 729 Op->Common.DisasmOpcode = 0; 730 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 731 return; 732 733 default: 734 break; 735 } 736 737 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 738 739 /* The op and arguments */ 740 741 switch (Op->Common.AmlOpcode) 742 { 743 case AML_LNOT_OP: 744 745 Child = Op->Common.Value.Arg; 746 if ((Child->Common.AmlOpcode == AML_LEQUAL_OP) || 747 (Child->Common.AmlOpcode == AML_LGREATER_OP) || 748 (Child->Common.AmlOpcode == AML_LLESS_OP)) 749 { 750 Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 751 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 752 } 753 else 754 { 755 AcpiOsPrintf ("%s", OpInfo->Name); 756 } 757 break; 758 759 case AML_BYTE_OP: 760 761 AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer); 762 break; 763 764 case AML_WORD_OP: 765 766 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 767 { 768 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 769 } 770 else 771 { 772 AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer); 773 } 774 break; 775 776 case AML_DWORD_OP: 777 778 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 779 { 780 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 781 } 782 else 783 { 784 AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer); 785 } 786 break; 787 788 case AML_QWORD_OP: 789 790 AcpiOsPrintf ("0x%8.8X%8.8X", 791 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); 792 break; 793 794 case AML_STRING_OP: 795 796 AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX); 797 798 /* For _HID/_CID strings, attempt to output a descriptive comment */ 799 800 if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING) 801 { 802 /* If we know about the ID, emit the description */ 803 804 IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String); 805 if (IdInfo) 806 { 807 AcpiOsPrintf (" /* %s */", IdInfo->Description); 808 } 809 } 810 break; 811 812 case AML_BUFFER_OP: 813 /* 814 * Determine the type of buffer. We can have one of the following: 815 * 816 * 1) ResourceTemplate containing Resource Descriptors. 817 * 2) Unicode String buffer 818 * 3) ASCII String buffer 819 * 4) Raw data buffer (if none of the above) 820 * 821 * Since there are no special AML opcodes to differentiate these 822 * types of buffers, we have to closely look at the data in the 823 * buffer to determine the type. 824 */ 825 if (!AcpiGbl_NoResourceDisassembly) 826 { 827 Status = AcpiDmIsResourceTemplate (WalkState, Op); 828 if (ACPI_SUCCESS (Status)) 829 { 830 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 831 AcpiOsPrintf ("ResourceTemplate"); 832 break; 833 } 834 else if (Status == AE_AML_NO_RESOURCE_END_TAG) 835 { 836 AcpiOsPrintf ( 837 "/**** Is ResourceTemplate, " 838 "but EndTag not at buffer end ****/ "); 839 } 840 } 841 842 if (AcpiDmIsUuidBuffer (Op)) 843 { 844 Op->Common.DisasmOpcode = ACPI_DASM_UUID; 845 AcpiOsPrintf ("ToUUID ("); 846 } 847 else if (AcpiDmIsUnicodeBuffer (Op)) 848 { 849 Op->Common.DisasmOpcode = ACPI_DASM_UNICODE; 850 AcpiOsPrintf ("Unicode ("); 851 } 852 else if (AcpiDmIsStringBuffer (Op)) 853 { 854 Op->Common.DisasmOpcode = ACPI_DASM_STRING; 855 AcpiOsPrintf ("Buffer"); 856 } 857 else if (AcpiDmIsPldBuffer (Op)) 858 { 859 Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD; 860 AcpiOsPrintf ("ToPLD ("); 861 } 862 else 863 { 864 Op->Common.DisasmOpcode = ACPI_DASM_BUFFER; 865 AcpiOsPrintf ("Buffer"); 866 } 867 break; 868 869 case AML_INT_NAMEPATH_OP: 870 871 AcpiDmNamestring (Op->Common.Value.Name); 872 break; 873 874 case AML_INT_NAMEDFIELD_OP: 875 876 Length = AcpiDmDumpName (Op->Named.Name); 877 AcpiOsPrintf (",%*.s %u", (unsigned) (5 - Length), " ", 878 (UINT32) Op->Common.Value.Integer); 879 AcpiDmCommaIfFieldMember (Op); 880 881 Info->BitOffset += (UINT32) Op->Common.Value.Integer; 882 break; 883 884 case AML_INT_RESERVEDFIELD_OP: 885 886 /* Offset() -- Must account for previous offsets */ 887 888 Offset = (UINT32) Op->Common.Value.Integer; 889 Info->BitOffset += Offset; 890 891 if (Info->BitOffset % 8 == 0) 892 { 893 AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset)); 894 } 895 else 896 { 897 AcpiOsPrintf (" , %u", Offset); 898 } 899 900 AcpiDmCommaIfFieldMember (Op); 901 break; 902 903 case AML_INT_ACCESSFIELD_OP: 904 case AML_INT_EXTACCESSFIELD_OP: 905 906 AcpiOsPrintf ("AccessAs (%s, ", 907 AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]); 908 909 AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8)); 910 911 if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP) 912 { 913 AcpiOsPrintf (" (0x%2.2X)", (unsigned) 914 ((Op->Common.Value.Integer >> 16) & 0xFF)); 915 } 916 917 AcpiOsPrintf (")"); 918 AcpiDmCommaIfFieldMember (Op); 919 break; 920 921 case AML_INT_CONNECTION_OP: 922 /* 923 * Two types of Connection() - one with a buffer object, the 924 * other with a namestring that points to a buffer object. 925 */ 926 AcpiOsPrintf ("Connection ("); 927 Child = Op->Common.Value.Arg; 928 929 if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP) 930 { 931 AcpiOsPrintf ("\n"); 932 933 Aml = Child->Named.Data; 934 Length = (UINT32) Child->Common.Value.Integer; 935 936 Info->Level += 1; 937 Info->MappingOp = Op; 938 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 939 940 AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length); 941 942 Info->Level -= 1; 943 AcpiDmIndent (Info->Level); 944 } 945 else 946 { 947 AcpiDmNamestring (Child->Common.Value.Name); 948 } 949 950 AcpiOsPrintf (")"); 951 AcpiDmCommaIfFieldMember (Op); 952 AcpiOsPrintf ("\n"); 953 954 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */ 955 Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 956 break; 957 958 case AML_INT_BYTELIST_OP: 959 960 AcpiDmByteList (Info, Op); 961 break; 962 963 case AML_INT_METHODCALL_OP: 964 965 Op = AcpiPsGetDepthNext (NULL, Op); 966 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 967 968 AcpiDmNamestring (Op->Common.Value.Name); 969 break; 970 971 case AML_ELSE_OP: 972 973 AcpiDmConvertToElseIf (Op); 974 break; 975 976 case AML_EXTERNAL_OP: 977 978 if (AcpiGbl_DmEmitExternalOpcodes) 979 { 980 AcpiOsPrintf ("/* Opcode 0x15 */ "); 981 982 /* Fallthrough */ 983 } 984 else 985 { 986 break; 987 } 988 989 default: 990 991 /* Just get the opcode name and print it */ 992 993 AcpiOsPrintf ("%s", OpInfo->Name); 994 995 996 #ifdef ACPI_DEBUGGER 997 998 if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) && 999 (WalkState) && 1000 (WalkState->Results) && 1001 (WalkState->ResultCount)) 1002 { 1003 AcpiDbDecodeInternalObject ( 1004 WalkState->Results->Results.ObjDesc [ 1005 (WalkState->ResultCount - 1) % 1006 ACPI_RESULTS_FRAME_OBJ_NUM]); 1007 } 1008 #endif 1009 1010 break; 1011 } 1012 } 1013 1014 1015 /******************************************************************************* 1016 * 1017 * FUNCTION: AcpiDmConvertToElseIf 1018 * 1019 * PARAMETERS: OriginalElseOp - ELSE Object to be examined 1020 * 1021 * RETURN: None. Emits either an "Else" or an "ElseIf" ASL operator. 1022 * 1023 * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf 1024 * 1025 * EXAMPLE: 1026 * 1027 * This If..Else..If nested sequence: 1028 * 1029 * If (Arg0 == 1) 1030 * { 1031 * Local0 = 4 1032 * } 1033 * Else 1034 * { 1035 * If (Arg0 == 2) 1036 * { 1037 * Local0 = 5 1038 * } 1039 * } 1040 * 1041 * Is converted to this simpler If..ElseIf sequence: 1042 * 1043 * If (Arg0 == 1) 1044 * { 1045 * Local0 = 4 1046 * } 1047 * ElseIf (Arg0 == 2) 1048 * { 1049 * Local0 = 5 1050 * } 1051 * 1052 * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL 1053 * macro that emits an Else opcode followed by an If opcode. This function 1054 * reverses these AML sequences back to an ElseIf macro where possible. This 1055 * can make the disassembled ASL code simpler and more like the original code. 1056 * 1057 ******************************************************************************/ 1058 1059 static void 1060 AcpiDmConvertToElseIf ( 1061 ACPI_PARSE_OBJECT *OriginalElseOp) 1062 { 1063 ACPI_PARSE_OBJECT *IfOp; 1064 ACPI_PARSE_OBJECT *ElseOp; 1065 1066 1067 /* 1068 * To be able to perform the conversion, two conditions must be satisfied: 1069 * 1) The first child of the Else must be an If statement. 1070 * 2) The If block can only be followed by an Else block and these must 1071 * be the only blocks under the original Else. 1072 */ 1073 IfOp = OriginalElseOp->Common.Value.Arg; 1074 1075 if (!IfOp || 1076 (IfOp->Common.AmlOpcode != AML_IF_OP) || 1077 (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP))) 1078 { 1079 /* Not a proper Else..If sequence, cannot convert to ElseIf */ 1080 1081 AcpiOsPrintf ("%s", "Else"); 1082 return; 1083 } 1084 1085 /* Cannot have anything following the If...Else block */ 1086 1087 ElseOp = IfOp->Common.Next; 1088 if (ElseOp && ElseOp->Common.Next) 1089 { 1090 AcpiOsPrintf ("%s", "Else"); 1091 return; 1092 } 1093 1094 /* Emit ElseIf, mark the IF as now an ELSEIF */ 1095 1096 AcpiOsPrintf ("%s", "ElseIf"); 1097 IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF; 1098 1099 /* The IF parent will now be the same as the original ELSE parent */ 1100 1101 IfOp->Common.Parent = OriginalElseOp->Common.Parent; 1102 1103 /* 1104 * Update the NEXT pointers to restructure the parse tree, essentially 1105 * promoting an If..Else block up to the same level as the original 1106 * Else. 1107 * 1108 * Check if the IF has a corresponding ELSE peer 1109 */ 1110 ElseOp = IfOp->Common.Next; 1111 if (ElseOp && 1112 (ElseOp->Common.AmlOpcode == AML_ELSE_OP)) 1113 { 1114 /* If an ELSE matches the IF, promote it also */ 1115 1116 ElseOp->Common.Parent = OriginalElseOp->Common.Parent; 1117 1118 /* Promote the entire block under the ElseIf (All Next OPs) */ 1119 1120 AcpiDmPromoteSubtree (OriginalElseOp); 1121 } 1122 else 1123 { 1124 /* Otherwise, set the IF NEXT to the original ELSE NEXT */ 1125 1126 IfOp->Common.Next = OriginalElseOp->Common.Next; 1127 } 1128 1129 /* Detach the child IF block from the original ELSE */ 1130 1131 OriginalElseOp->Common.Value.Arg = NULL; 1132 1133 /* Ignore the original ELSE from now on */ 1134 1135 OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1136 OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 1137 1138 /* Insert IF (now ELSEIF) as next peer of the original ELSE */ 1139 1140 OriginalElseOp->Common.Next = IfOp; 1141 } 1142 1143 1144 /******************************************************************************* 1145 * 1146 * FUNCTION: AcpiDmPromoteSubtree 1147 * 1148 * PARAMETERS: StartOpOp - Original parent of the entire subtree 1149 * 1150 * RETURN: None 1151 * 1152 * DESCRIPTION: Promote an entire parse subtree up one level. 1153 * 1154 ******************************************************************************/ 1155 1156 static void 1157 AcpiDmPromoteSubtree ( 1158 ACPI_PARSE_OBJECT *StartOp) 1159 { 1160 ACPI_PARSE_OBJECT *Op; 1161 ACPI_PARSE_OBJECT *ParentOp; 1162 1163 1164 /* New parent for subtree elements */ 1165 1166 ParentOp = StartOp->Common.Parent; 1167 1168 /* First child starts the subtree */ 1169 1170 Op = StartOp->Common.Value.Arg; 1171 1172 /* Walk the top-level elements of the subtree */ 1173 1174 while (Op) 1175 { 1176 Op->Common.Parent = ParentOp; 1177 if (!Op->Common.Next) 1178 { 1179 /* Last Op in list, update its next field */ 1180 1181 Op->Common.Next = StartOp->Common.Next; 1182 break; 1183 } 1184 Op = Op->Common.Next; 1185 } 1186 } 1187