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 static BOOLEAN 73 AcpiDmIsSwitchBlock ( 74 ACPI_PARSE_OBJECT *Op); 75 76 static BOOLEAN 77 AcpiDmIsCaseBlock ( 78 ACPI_PARSE_OBJECT *Op); 79 80 /******************************************************************************* 81 * 82 * FUNCTION: AcpiDmDisplayTargetPathname 83 * 84 * PARAMETERS: Op - Parse object 85 * 86 * RETURN: None 87 * 88 * DESCRIPTION: For AML opcodes that have a target operand, display the full 89 * pathname for the target, in a comment field. Handles Return() 90 * statements also. 91 * 92 ******************************************************************************/ 93 94 void 95 AcpiDmDisplayTargetPathname ( 96 ACPI_PARSE_OBJECT *Op) 97 { 98 ACPI_PARSE_OBJECT *NextOp; 99 ACPI_PARSE_OBJECT *PrevOp = NULL; 100 char *Pathname; 101 const ACPI_OPCODE_INFO *OpInfo; 102 103 104 if (Op->Common.AmlOpcode == AML_RETURN_OP) 105 { 106 PrevOp = Op->Asl.Value.Arg; 107 } 108 else 109 { 110 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 111 if (!(OpInfo->Flags & AML_HAS_TARGET)) 112 { 113 return; 114 } 115 116 /* Target is the last Op in the arg list */ 117 118 NextOp = Op->Asl.Value.Arg; 119 while (NextOp) 120 { 121 PrevOp = NextOp; 122 NextOp = PrevOp->Asl.Next; 123 } 124 } 125 126 if (!PrevOp) 127 { 128 return; 129 } 130 131 /* We must have a namepath AML opcode */ 132 133 if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP) 134 { 135 return; 136 } 137 138 /* A null string is the "no target specified" case */ 139 140 if (!PrevOp->Asl.Value.String) 141 { 142 return; 143 } 144 145 /* No node means "unresolved external reference" */ 146 147 if (!PrevOp->Asl.Node) 148 { 149 AcpiOsPrintf (" /* External reference */"); 150 return; 151 } 152 153 /* Ignore if path is already from the root */ 154 155 if (*PrevOp->Asl.Value.String == '\\') 156 { 157 return; 158 } 159 160 /* Now: we can get the full pathname */ 161 162 Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node); 163 if (!Pathname) 164 { 165 return; 166 } 167 168 AcpiOsPrintf (" /* %s */", Pathname); 169 ACPI_FREE (Pathname); 170 } 171 172 173 /******************************************************************************* 174 * 175 * FUNCTION: AcpiDmNotifyDescription 176 * 177 * PARAMETERS: Op - Name() parse object 178 * 179 * RETURN: None 180 * 181 * DESCRIPTION: Emit a description comment for the value associated with a 182 * Notify() operator. 183 * 184 ******************************************************************************/ 185 186 void 187 AcpiDmNotifyDescription ( 188 ACPI_PARSE_OBJECT *Op) 189 { 190 ACPI_PARSE_OBJECT *NextOp; 191 ACPI_NAMESPACE_NODE *Node; 192 UINT8 NotifyValue; 193 UINT8 Type = ACPI_TYPE_ANY; 194 195 196 /* The notify value is the second argument */ 197 198 NextOp = Op->Asl.Value.Arg; 199 NextOp = NextOp->Asl.Next; 200 201 switch (NextOp->Common.AmlOpcode) 202 { 203 case AML_ZERO_OP: 204 case AML_ONE_OP: 205 206 NotifyValue = (UINT8) NextOp->Common.AmlOpcode; 207 break; 208 209 case AML_BYTE_OP: 210 211 NotifyValue = (UINT8) NextOp->Asl.Value.Integer; 212 break; 213 214 default: 215 return; 216 } 217 218 /* 219 * Attempt to get the namespace node so we can determine the object type. 220 * Some notify values are dependent on the object type (Device, Thermal, 221 * or Processor). 222 */ 223 Node = Op->Asl.Node; 224 if (Node) 225 { 226 Type = Node->Type; 227 } 228 229 AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type)); 230 } 231 232 233 /******************************************************************************* 234 * 235 * FUNCTION: AcpiDmPredefinedDescription 236 * 237 * PARAMETERS: Op - Name() parse object 238 * 239 * RETURN: None 240 * 241 * DESCRIPTION: Emit a description comment for a predefined ACPI name. 242 * Used for iASL compiler only. 243 * 244 ******************************************************************************/ 245 246 void 247 AcpiDmPredefinedDescription ( 248 ACPI_PARSE_OBJECT *Op) 249 { 250 #ifdef ACPI_ASL_COMPILER 251 const AH_PREDEFINED_NAME *Info; 252 char *NameString; 253 int LastCharIsDigit; 254 int LastCharsAreHex; 255 256 257 if (!Op) 258 { 259 return; 260 } 261 262 /* Ensure that the comment field is emitted only once */ 263 264 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED) 265 { 266 return; 267 } 268 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED; 269 270 /* Predefined name must start with an underscore */ 271 272 NameString = ACPI_CAST_PTR (char, &Op->Named.Name); 273 if (NameString[0] != '_') 274 { 275 return; 276 } 277 278 /* 279 * Check for the special ACPI names: 280 * _ACd, _ALd, _EJd, _Exx, _Lxx, _Qxx, _Wxx, _T_a 281 * (where d=decimal_digit, x=hex_digit, a=anything) 282 * 283 * Convert these to the generic name for table lookup. 284 * Note: NameString is guaranteed to be upper case here. 285 */ 286 LastCharIsDigit = 287 (isdigit ((int) NameString[3])); /* d */ 288 LastCharsAreHex = 289 (isxdigit ((int) NameString[2]) && /* xx */ 290 isxdigit ((int) NameString[3])); 291 292 switch (NameString[1]) 293 { 294 case 'A': 295 296 if ((NameString[2] == 'C') && (LastCharIsDigit)) 297 { 298 NameString = "_ACx"; 299 } 300 else if ((NameString[2] == 'L') && (LastCharIsDigit)) 301 { 302 NameString = "_ALx"; 303 } 304 break; 305 306 case 'E': 307 308 if ((NameString[2] == 'J') && (LastCharIsDigit)) 309 { 310 NameString = "_EJx"; 311 } 312 else if (LastCharsAreHex) 313 { 314 NameString = "_Exx"; 315 } 316 break; 317 318 case 'L': 319 320 if (LastCharsAreHex) 321 { 322 NameString = "_Lxx"; 323 } 324 break; 325 326 case 'Q': 327 328 if (LastCharsAreHex) 329 { 330 NameString = "_Qxx"; 331 } 332 break; 333 334 case 'T': 335 336 if (NameString[2] == '_') 337 { 338 NameString = "_T_x"; 339 } 340 break; 341 342 case 'W': 343 344 if (LastCharsAreHex) 345 { 346 NameString = "_Wxx"; 347 } 348 break; 349 350 default: 351 352 break; 353 } 354 355 /* Match the name in the info table */ 356 357 Info = AcpiAhMatchPredefinedName (NameString); 358 if (Info) 359 { 360 AcpiOsPrintf (" // %4.4s: %s", 361 NameString, ACPI_CAST_PTR (char, Info->Description)); 362 } 363 364 #endif 365 return; 366 } 367 368 369 /******************************************************************************* 370 * 371 * FUNCTION: AcpiDmFieldPredefinedDescription 372 * 373 * PARAMETERS: Op - Parse object 374 * 375 * RETURN: None 376 * 377 * DESCRIPTION: Emit a description comment for a resource descriptor tag 378 * (which is a predefined ACPI name.) Used for iASL compiler only. 379 * 380 ******************************************************************************/ 381 382 void 383 AcpiDmFieldPredefinedDescription ( 384 ACPI_PARSE_OBJECT *Op) 385 { 386 #ifdef ACPI_ASL_COMPILER 387 ACPI_PARSE_OBJECT *IndexOp; 388 char *Tag; 389 const ACPI_OPCODE_INFO *OpInfo; 390 const AH_PREDEFINED_NAME *Info; 391 392 393 if (!Op) 394 { 395 return; 396 } 397 398 /* Ensure that the comment field is emitted only once */ 399 400 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED) 401 { 402 return; 403 } 404 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED; 405 406 /* 407 * Op must be one of the Create* operators: CreateField, CreateBitField, 408 * CreateByteField, CreateWordField, CreateDwordField, CreateQwordField 409 */ 410 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 411 if (!(OpInfo->Flags & AML_CREATE)) 412 { 413 return; 414 } 415 416 /* Second argument is the Index argument */ 417 418 IndexOp = Op->Common.Value.Arg; 419 IndexOp = IndexOp->Common.Next; 420 421 /* Index argument must be a namepath */ 422 423 if (IndexOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP) 424 { 425 return; 426 } 427 428 /* Major cheat: We previously put the Tag ptr in the Node field */ 429 430 Tag = ACPI_CAST_PTR (char, IndexOp->Common.Node); 431 if (!Tag) 432 { 433 return; 434 } 435 436 /* Match the name in the info table */ 437 438 Info = AcpiAhMatchPredefinedName (Tag); 439 if (Info) 440 { 441 AcpiOsPrintf (" // %4.4s: %s", Tag, 442 ACPI_CAST_PTR (char, Info->Description)); 443 } 444 445 #endif 446 return; 447 } 448 449 450 /******************************************************************************* 451 * 452 * FUNCTION: AcpiDmMethodFlags 453 * 454 * PARAMETERS: Op - Method Object to be examined 455 * 456 * RETURN: None 457 * 458 * DESCRIPTION: Decode control method flags 459 * 460 ******************************************************************************/ 461 462 void 463 AcpiDmMethodFlags ( 464 ACPI_PARSE_OBJECT *Op) 465 { 466 UINT32 Flags; 467 UINT32 Args; 468 469 470 /* The next Op contains the flags */ 471 472 Op = AcpiPsGetDepthNext (NULL, Op); 473 Flags = (UINT8) Op->Common.Value.Integer; 474 Args = Flags & 0x07; 475 476 /* Mark the Op as completed */ 477 478 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 479 480 /* 1) Method argument count */ 481 482 AcpiOsPrintf (", %u, ", Args); 483 484 /* 2) Serialize rule */ 485 486 if (!(Flags & 0x08)) 487 { 488 AcpiOsPrintf ("Not"); 489 } 490 491 AcpiOsPrintf ("Serialized"); 492 493 /* 3) SyncLevel */ 494 495 if (Flags & 0xF0) 496 { 497 AcpiOsPrintf (", %u", Flags >> 4); 498 } 499 } 500 501 502 /******************************************************************************* 503 * 504 * FUNCTION: AcpiDmFieldFlags 505 * 506 * PARAMETERS: Op - Field Object to be examined 507 * 508 * RETURN: None 509 * 510 * DESCRIPTION: Decode Field definition flags 511 * 512 ******************************************************************************/ 513 514 void 515 AcpiDmFieldFlags ( 516 ACPI_PARSE_OBJECT *Op) 517 { 518 UINT32 Flags; 519 520 521 Op = Op->Common.Next; 522 Flags = (UINT8) Op->Common.Value.Integer; 523 524 /* Mark the Op as completed */ 525 526 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 527 528 AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]); 529 AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]); 530 AcpiOsPrintf ("%s)", AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]); 531 } 532 533 534 /******************************************************************************* 535 * 536 * FUNCTION: AcpiDmAddressSpace 537 * 538 * PARAMETERS: SpaceId - ID to be translated 539 * 540 * RETURN: None 541 * 542 * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword 543 * 544 ******************************************************************************/ 545 546 void 547 AcpiDmAddressSpace ( 548 UINT8 SpaceId) 549 { 550 551 if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS) 552 { 553 if (SpaceId == 0x7F) 554 { 555 AcpiOsPrintf ("FFixedHW, "); 556 } 557 else 558 { 559 AcpiOsPrintf ("0x%.2X, ", SpaceId); 560 } 561 } 562 else 563 { 564 AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]); 565 } 566 } 567 568 569 /******************************************************************************* 570 * 571 * FUNCTION: AcpiDmRegionFlags 572 * 573 * PARAMETERS: Op - Object to be examined 574 * 575 * RETURN: None 576 * 577 * DESCRIPTION: Decode OperationRegion flags 578 * 579 ******************************************************************************/ 580 581 void 582 AcpiDmRegionFlags ( 583 ACPI_PARSE_OBJECT *Op) 584 { 585 586 /* The next Op contains the SpaceId */ 587 588 Op = AcpiPsGetDepthNext (NULL, Op); 589 590 /* Mark the Op as completed */ 591 592 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 593 594 AcpiOsPrintf (", "); 595 AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer); 596 } 597 598 599 /******************************************************************************* 600 * 601 * FUNCTION: AcpiDmMatchOp 602 * 603 * PARAMETERS: Op - Match Object to be examined 604 * 605 * RETURN: None 606 * 607 * DESCRIPTION: Decode Match opcode operands 608 * 609 ******************************************************************************/ 610 611 void 612 AcpiDmMatchOp ( 613 ACPI_PARSE_OBJECT *Op) 614 { 615 ACPI_PARSE_OBJECT *NextOp; 616 617 618 NextOp = AcpiPsGetDepthNext (NULL, Op); 619 NextOp = NextOp->Common.Next; 620 621 if (!NextOp) 622 { 623 /* Handle partial tree during single-step */ 624 625 return; 626 } 627 628 /* Mark the two nodes that contain the encoding for the match keywords */ 629 630 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 631 632 NextOp = NextOp->Common.Next; 633 NextOp = NextOp->Common.Next; 634 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP; 635 } 636 637 638 /******************************************************************************* 639 * 640 * FUNCTION: AcpiDmMatchKeyword 641 * 642 * PARAMETERS: Op - Match Object to be examined 643 * 644 * RETURN: None 645 * 646 * DESCRIPTION: Decode Match opcode operands 647 * 648 ******************************************************************************/ 649 650 static void 651 AcpiDmMatchKeyword ( 652 ACPI_PARSE_OBJECT *Op) 653 { 654 655 if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE) 656 { 657 AcpiOsPrintf ("/* Unknown Match Keyword encoding */"); 658 } 659 else 660 { 661 AcpiOsPrintf ("%s", 662 AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer]); 663 } 664 } 665 666 667 /******************************************************************************* 668 * 669 * FUNCTION: AcpiDmDisassembleOneOp 670 * 671 * PARAMETERS: WalkState - Current walk info 672 * Info - Parse tree walk info 673 * Op - Op that is to be printed 674 * 675 * RETURN: None 676 * 677 * DESCRIPTION: Disassemble a single AML opcode 678 * 679 ******************************************************************************/ 680 681 void 682 AcpiDmDisassembleOneOp ( 683 ACPI_WALK_STATE *WalkState, 684 ACPI_OP_WALK_INFO *Info, 685 ACPI_PARSE_OBJECT *Op) 686 { 687 const ACPI_OPCODE_INFO *OpInfo = NULL; 688 UINT32 Offset; 689 UINT32 Length; 690 ACPI_PARSE_OBJECT *Child; 691 ACPI_STATUS Status; 692 UINT8 *Aml; 693 const AH_DEVICE_ID *IdInfo; 694 695 696 if (!Op) 697 { 698 AcpiOsPrintf ("<NULL OP PTR>"); 699 return; 700 } 701 702 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF) 703 { 704 return; /* ElseIf macro was already emitted */ 705 } 706 707 switch (Op->Common.DisasmOpcode) 708 { 709 case ACPI_DASM_MATCHOP: 710 711 AcpiDmMatchKeyword (Op); 712 return; 713 714 case ACPI_DASM_LNOT_SUFFIX: 715 716 if (!AcpiGbl_CstyleDisassembly) 717 { 718 switch (Op->Common.AmlOpcode) 719 { 720 case AML_LEQUAL_OP: 721 AcpiOsPrintf ("LNotEqual"); 722 break; 723 724 case AML_LGREATER_OP: 725 AcpiOsPrintf ("LLessEqual"); 726 break; 727 728 case AML_LLESS_OP: 729 AcpiOsPrintf ("LGreaterEqual"); 730 break; 731 732 default: 733 break; 734 } 735 } 736 737 Op->Common.DisasmOpcode = 0; 738 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 739 return; 740 741 default: 742 break; 743 } 744 745 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); 746 747 /* The op and arguments */ 748 749 switch (Op->Common.AmlOpcode) 750 { 751 case AML_LNOT_OP: 752 753 Child = Op->Common.Value.Arg; 754 if ((Child->Common.AmlOpcode == AML_LEQUAL_OP) || 755 (Child->Common.AmlOpcode == AML_LGREATER_OP) || 756 (Child->Common.AmlOpcode == AML_LLESS_OP)) 757 { 758 Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX; 759 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 760 } 761 else 762 { 763 AcpiOsPrintf ("%s", OpInfo->Name); 764 } 765 break; 766 767 case AML_BYTE_OP: 768 769 AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer); 770 break; 771 772 case AML_WORD_OP: 773 774 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 775 { 776 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 777 } 778 else 779 { 780 AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer); 781 } 782 break; 783 784 case AML_DWORD_OP: 785 786 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID) 787 { 788 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer); 789 } 790 else 791 { 792 AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer); 793 } 794 break; 795 796 case AML_QWORD_OP: 797 798 AcpiOsPrintf ("0x%8.8X%8.8X", 799 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer)); 800 break; 801 802 case AML_STRING_OP: 803 804 AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX); 805 806 /* For _HID/_CID strings, attempt to output a descriptive comment */ 807 808 if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING) 809 { 810 /* If we know about the ID, emit the description */ 811 812 IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String); 813 if (IdInfo) 814 { 815 AcpiOsPrintf (" /* %s */", IdInfo->Description); 816 } 817 } 818 break; 819 820 case AML_BUFFER_OP: 821 /* 822 * Determine the type of buffer. We can have one of the following: 823 * 824 * 1) ResourceTemplate containing Resource Descriptors. 825 * 2) Unicode String buffer 826 * 3) ASCII String buffer 827 * 4) Raw data buffer (if none of the above) 828 * 829 * Since there are no special AML opcodes to differentiate these 830 * types of buffers, we have to closely look at the data in the 831 * buffer to determine the type. 832 */ 833 if (!AcpiGbl_NoResourceDisassembly) 834 { 835 Status = AcpiDmIsResourceTemplate (WalkState, Op); 836 if (ACPI_SUCCESS (Status)) 837 { 838 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 839 AcpiOsPrintf ("ResourceTemplate"); 840 break; 841 } 842 else if (Status == AE_AML_NO_RESOURCE_END_TAG) 843 { 844 AcpiOsPrintf ( 845 "/**** Is ResourceTemplate, " 846 "but EndTag not at buffer end ****/ "); 847 } 848 } 849 850 if (AcpiDmIsUuidBuffer (Op)) 851 { 852 Op->Common.DisasmOpcode = ACPI_DASM_UUID; 853 AcpiOsPrintf ("ToUUID ("); 854 } 855 else if (AcpiDmIsUnicodeBuffer (Op)) 856 { 857 Op->Common.DisasmOpcode = ACPI_DASM_UNICODE; 858 AcpiOsPrintf ("Unicode ("); 859 } 860 else if (AcpiDmIsStringBuffer (Op)) 861 { 862 Op->Common.DisasmOpcode = ACPI_DASM_STRING; 863 AcpiOsPrintf ("Buffer"); 864 } 865 else if (AcpiDmIsPldBuffer (Op)) 866 { 867 Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD; 868 AcpiOsPrintf ("ToPLD ("); 869 } 870 else 871 { 872 Op->Common.DisasmOpcode = ACPI_DASM_BUFFER; 873 AcpiOsPrintf ("Buffer"); 874 } 875 break; 876 877 case AML_INT_NAMEPATH_OP: 878 879 AcpiDmNamestring (Op->Common.Value.Name); 880 break; 881 882 case AML_INT_NAMEDFIELD_OP: 883 884 Length = AcpiDmDumpName (Op->Named.Name); 885 AcpiOsPrintf (",%*.s %u", (unsigned) (5 - Length), " ", 886 (UINT32) Op->Common.Value.Integer); 887 AcpiDmCommaIfFieldMember (Op); 888 889 Info->BitOffset += (UINT32) Op->Common.Value.Integer; 890 break; 891 892 case AML_INT_RESERVEDFIELD_OP: 893 894 /* Offset() -- Must account for previous offsets */ 895 896 Offset = (UINT32) Op->Common.Value.Integer; 897 Info->BitOffset += Offset; 898 899 if (Info->BitOffset % 8 == 0) 900 { 901 AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset)); 902 } 903 else 904 { 905 AcpiOsPrintf (" , %u", Offset); 906 } 907 908 AcpiDmCommaIfFieldMember (Op); 909 break; 910 911 case AML_INT_ACCESSFIELD_OP: 912 case AML_INT_EXTACCESSFIELD_OP: 913 914 AcpiOsPrintf ("AccessAs (%s, ", 915 AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]); 916 917 AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8)); 918 919 if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP) 920 { 921 AcpiOsPrintf (" (0x%2.2X)", (unsigned) 922 ((Op->Common.Value.Integer >> 16) & 0xFF)); 923 } 924 925 AcpiOsPrintf (")"); 926 AcpiDmCommaIfFieldMember (Op); 927 break; 928 929 case AML_INT_CONNECTION_OP: 930 /* 931 * Two types of Connection() - one with a buffer object, the 932 * other with a namestring that points to a buffer object. 933 */ 934 AcpiOsPrintf ("Connection ("); 935 Child = Op->Common.Value.Arg; 936 937 if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP) 938 { 939 AcpiOsPrintf ("\n"); 940 941 Aml = Child->Named.Data; 942 Length = (UINT32) Child->Common.Value.Integer; 943 944 Info->Level += 1; 945 Info->MappingOp = Op; 946 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE; 947 948 AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length); 949 950 Info->Level -= 1; 951 AcpiDmIndent (Info->Level); 952 } 953 else 954 { 955 AcpiDmNamestring (Child->Common.Value.Name); 956 } 957 958 AcpiOsPrintf (")"); 959 AcpiDmCommaIfFieldMember (Op); 960 AcpiOsPrintf ("\n"); 961 962 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */ 963 Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 964 break; 965 966 case AML_INT_BYTELIST_OP: 967 968 AcpiDmByteList (Info, Op); 969 break; 970 971 case AML_INT_METHODCALL_OP: 972 973 Op = AcpiPsGetDepthNext (NULL, Op); 974 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 975 976 AcpiDmNamestring (Op->Common.Value.Name); 977 break; 978 979 case AML_WHILE_OP: 980 981 if (AcpiDmIsSwitchBlock(Op)) 982 { 983 AcpiOsPrintf ("%s", "Switch"); 984 break; 985 } 986 987 AcpiOsPrintf ("%s", OpInfo->Name); 988 break; 989 990 case AML_IF_OP: 991 992 if (Op->Common.DisasmOpcode == ACPI_DASM_CASE) 993 { 994 AcpiOsPrintf ("%s", "Case"); 995 break; 996 } 997 998 AcpiOsPrintf ("%s", OpInfo->Name); 999 break; 1000 1001 case AML_ELSE_OP: 1002 1003 AcpiDmConvertToElseIf (Op); 1004 break; 1005 1006 case AML_EXTERNAL_OP: 1007 1008 if (AcpiGbl_DmEmitExternalOpcodes) 1009 { 1010 AcpiOsPrintf ("/* Opcode 0x15 */ "); 1011 1012 /* Fallthrough */ 1013 } 1014 else 1015 { 1016 break; 1017 } 1018 1019 default: 1020 1021 /* Just get the opcode name and print it */ 1022 1023 AcpiOsPrintf ("%s", OpInfo->Name); 1024 1025 1026 #ifdef ACPI_DEBUGGER 1027 1028 if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) && 1029 (WalkState) && 1030 (WalkState->Results) && 1031 (WalkState->ResultCount)) 1032 { 1033 AcpiDbDecodeInternalObject ( 1034 WalkState->Results->Results.ObjDesc [ 1035 (WalkState->ResultCount - 1) % 1036 ACPI_RESULTS_FRAME_OBJ_NUM]); 1037 } 1038 #endif 1039 1040 break; 1041 } 1042 } 1043 1044 1045 /******************************************************************************* 1046 * 1047 * FUNCTION: AcpiDmConvertToElseIf 1048 * 1049 * PARAMETERS: OriginalElseOp - ELSE Object to be examined 1050 * 1051 * RETURN: None. Emits either an "Else" or an "ElseIf" ASL operator. 1052 * 1053 * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf 1054 * 1055 * EXAMPLE: 1056 * 1057 * This If..Else..If nested sequence: 1058 * 1059 * If (Arg0 == 1) 1060 * { 1061 * Local0 = 4 1062 * } 1063 * Else 1064 * { 1065 * If (Arg0 == 2) 1066 * { 1067 * Local0 = 5 1068 * } 1069 * } 1070 * 1071 * Is converted to this simpler If..ElseIf sequence: 1072 * 1073 * If (Arg0 == 1) 1074 * { 1075 * Local0 = 4 1076 * } 1077 * ElseIf (Arg0 == 2) 1078 * { 1079 * Local0 = 5 1080 * } 1081 * 1082 * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL 1083 * macro that emits an Else opcode followed by an If opcode. This function 1084 * reverses these AML sequences back to an ElseIf macro where possible. This 1085 * can make the disassembled ASL code simpler and more like the original code. 1086 * 1087 ******************************************************************************/ 1088 1089 static void 1090 AcpiDmConvertToElseIf ( 1091 ACPI_PARSE_OBJECT *OriginalElseOp) 1092 { 1093 ACPI_PARSE_OBJECT *IfOp; 1094 ACPI_PARSE_OBJECT *ElseOp; 1095 1096 1097 /* 1098 * To be able to perform the conversion, two conditions must be satisfied: 1099 * 1) The first child of the Else must be an If statement. 1100 * 2) The If block can only be followed by an Else block and these must 1101 * be the only blocks under the original Else. 1102 */ 1103 IfOp = OriginalElseOp->Common.Value.Arg; 1104 1105 if (!IfOp || 1106 (IfOp->Common.AmlOpcode != AML_IF_OP) || 1107 (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP))) 1108 { 1109 /* Not a proper Else..If sequence, cannot convert to ElseIf */ 1110 1111 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1112 { 1113 AcpiOsPrintf ("%s", "Default"); 1114 return; 1115 } 1116 1117 AcpiOsPrintf ("%s", "Else"); 1118 return; 1119 } 1120 1121 /* Cannot have anything following the If...Else block */ 1122 1123 ElseOp = IfOp->Common.Next; 1124 if (ElseOp && ElseOp->Common.Next) 1125 { 1126 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1127 { 1128 AcpiOsPrintf ("%s", "Default"); 1129 return; 1130 } 1131 1132 AcpiOsPrintf ("%s", "Else"); 1133 return; 1134 } 1135 1136 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT) 1137 { 1138 /* 1139 * There is an ElseIf but in this case the Else is actually 1140 * a Default block for a Switch/Case statement. No conversion. 1141 */ 1142 AcpiOsPrintf ("%s", "Default"); 1143 return; 1144 } 1145 1146 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_CASE) 1147 { 1148 /* 1149 * This ElseIf is actually a Case block for a Switch/Case 1150 * statement. Print Case but do not return so that we can 1151 * promote the subtree and keep the indentation level. 1152 */ 1153 AcpiOsPrintf ("%s", "Case"); 1154 } 1155 else 1156 { 1157 /* Emit ElseIf, mark the IF as now an ELSEIF */ 1158 1159 AcpiOsPrintf ("%s", "ElseIf"); 1160 } 1161 1162 IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF; 1163 1164 /* The IF parent will now be the same as the original ELSE parent */ 1165 1166 IfOp->Common.Parent = OriginalElseOp->Common.Parent; 1167 1168 /* 1169 * Update the NEXT pointers to restructure the parse tree, essentially 1170 * promoting an If..Else block up to the same level as the original 1171 * Else. 1172 * 1173 * Check if the IF has a corresponding ELSE peer 1174 */ 1175 ElseOp = IfOp->Common.Next; 1176 if (ElseOp && 1177 (ElseOp->Common.AmlOpcode == AML_ELSE_OP)) 1178 { 1179 /* If an ELSE matches the IF, promote it also */ 1180 1181 ElseOp->Common.Parent = OriginalElseOp->Common.Parent; 1182 1183 /* Promote the entire block under the ElseIf (All Next OPs) */ 1184 1185 AcpiDmPromoteSubtree (OriginalElseOp); 1186 } 1187 else 1188 { 1189 /* Otherwise, set the IF NEXT to the original ELSE NEXT */ 1190 1191 IfOp->Common.Next = OriginalElseOp->Common.Next; 1192 } 1193 1194 /* Detach the child IF block from the original ELSE */ 1195 1196 OriginalElseOp->Common.Value.Arg = NULL; 1197 1198 /* Ignore the original ELSE from now on */ 1199 1200 OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1201 OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX; 1202 1203 /* Insert IF (now ELSEIF) as next peer of the original ELSE */ 1204 1205 OriginalElseOp->Common.Next = IfOp; 1206 } 1207 1208 1209 /******************************************************************************* 1210 * 1211 * FUNCTION: AcpiDmPromoteSubtree 1212 * 1213 * PARAMETERS: StartOpOp - Original parent of the entire subtree 1214 * 1215 * RETURN: None 1216 * 1217 * DESCRIPTION: Promote an entire parse subtree up one level. 1218 * 1219 ******************************************************************************/ 1220 1221 static void 1222 AcpiDmPromoteSubtree ( 1223 ACPI_PARSE_OBJECT *StartOp) 1224 { 1225 ACPI_PARSE_OBJECT *Op; 1226 ACPI_PARSE_OBJECT *ParentOp; 1227 1228 1229 /* New parent for subtree elements */ 1230 1231 ParentOp = StartOp->Common.Parent; 1232 1233 /* First child starts the subtree */ 1234 1235 Op = StartOp->Common.Value.Arg; 1236 1237 /* Walk the top-level elements of the subtree */ 1238 1239 while (Op) 1240 { 1241 Op->Common.Parent = ParentOp; 1242 if (!Op->Common.Next) 1243 { 1244 /* Last Op in list, update its next field */ 1245 1246 Op->Common.Next = StartOp->Common.Next; 1247 break; 1248 } 1249 Op = Op->Common.Next; 1250 } 1251 } 1252 1253 /******************************************************************************* 1254 * 1255 * FUNCTION: AcpiDmIsTempName 1256 * 1257 * PARAMETERS: Op - Object to be examined 1258 * 1259 * RETURN: TRUE if object is a temporary (_T_x) name 1260 * 1261 * DESCRIPTION: Determine if an object is a temporary name and ignore it. 1262 * Temporary names are only used for Switch statements. This 1263 * function depends on this restriced usage. 1264 * 1265 ******************************************************************************/ 1266 1267 BOOLEAN 1268 AcpiDmIsTempName ( 1269 ACPI_PARSE_OBJECT *Op) 1270 { 1271 char *Temp; 1272 1273 if (Op->Common.AmlOpcode != AML_NAME_OP) 1274 { 1275 return (FALSE); 1276 } 1277 1278 Temp = (char *)(Op->Common.Aml); 1279 ++Temp; 1280 1281 if (strncmp(Temp, "_T_", 3)) 1282 { 1283 return (FALSE); 1284 } 1285 1286 /* Ignore Op */ 1287 1288 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1289 1290 return (TRUE); 1291 } 1292 1293 /******************************************************************************* 1294 * 1295 * FUNCTION: AcpiDmIsSwitchBlock 1296 * 1297 * PARAMETERS: Op - While Object 1298 * 1299 * RETURN: TRUE if While block can be converted to a Switch/Case block 1300 * 1301 * DESCRIPTION: Determines if While block is a Switch/Case statement. Modifies 1302 * parse tree to allow for Switch/Case disassembly during walk. 1303 * 1304 * EXAMPLE: Example of parse tree to be converted 1305 * 1306 * While 1307 * One 1308 * Store 1309 * ByteConst 1310 * -NamePath- 1311 * If 1312 * LEqual 1313 * -NamePath- 1314 * Zero 1315 * Return 1316 * One 1317 * Else 1318 * Return 1319 * WordConst 1320 * Break 1321 * 1322 ******************************************************************************/ 1323 1324 static BOOLEAN 1325 AcpiDmIsSwitchBlock ( 1326 ACPI_PARSE_OBJECT *Op) 1327 { 1328 ACPI_PARSE_OBJECT *OneOp; 1329 ACPI_PARSE_OBJECT *StoreOp; 1330 ACPI_PARSE_OBJECT *NamePathOp; 1331 ACPI_PARSE_OBJECT *PredicateOp; 1332 ACPI_PARSE_OBJECT *CurrentOp; 1333 ACPI_PARSE_OBJECT *TempOp; 1334 1335 /* Check for One Op Predicate */ 1336 1337 OneOp = AcpiPsGetArg (Op, 0); 1338 if (!OneOp || (OneOp->Common.AmlOpcode != AML_ONE_OP)) 1339 { 1340 return (FALSE); 1341 } 1342 1343 /* Check for Store Op */ 1344 1345 StoreOp = OneOp->Common.Next; 1346 if (!StoreOp || (StoreOp->Common.AmlOpcode != AML_STORE_OP)) 1347 { 1348 return (FALSE); 1349 } 1350 1351 /* Check for Name Op with _T_ string */ 1352 1353 NamePathOp = AcpiPsGetArg (StoreOp, 1); 1354 if (!NamePathOp || (NamePathOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP)) 1355 { 1356 return (FALSE); 1357 } 1358 1359 if (strncmp((char *)(NamePathOp->Common.Aml), "_T_", 3)) 1360 { 1361 return (FALSE); 1362 } 1363 1364 /* This is a Switch/Case control block */ 1365 1366 /* Ignore the One Op Predicate */ 1367 1368 OneOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1369 1370 /* Ignore the Store Op, but not the children */ 1371 1372 StoreOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE; 1373 1374 /* 1375 * First arg of Store Op is the Switch condition. 1376 * Mark it as a Switch predicate and as a parameter list for paren 1377 * closing and correct indentation. 1378 */ 1379 PredicateOp = AcpiPsGetArg (StoreOp, 0); 1380 PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE; 1381 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST; 1382 1383 /* Ignore the Name Op */ 1384 1385 NamePathOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE; 1386 1387 /* Remaining opcodes are the Case statements (If/ElseIf's) */ 1388 1389 CurrentOp = StoreOp->Common.Next; 1390 while (AcpiDmIsCaseBlock (CurrentOp)) 1391 { 1392 /* Block is a Case structure */ 1393 1394 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP) 1395 { 1396 /* ElseIf */ 1397 1398 CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE; 1399 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1400 } 1401 1402 /* If */ 1403 1404 CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE; 1405 1406 /* 1407 * Mark the parse tree for Case disassembly. There are two 1408 * types of Case statements. The first type of statement begins with 1409 * an LEqual. The second starts with an LNot and uses a Match statement 1410 * on a Package of constants. 1411 */ 1412 TempOp = AcpiPsGetArg (CurrentOp, 0); 1413 switch (TempOp->Common.AmlOpcode) 1414 { 1415 case (AML_LEQUAL_OP): 1416 1417 /* Ignore just the LEqual Op */ 1418 1419 TempOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE; 1420 1421 /* Ignore the NamePath Op */ 1422 1423 TempOp = AcpiPsGetArg (TempOp, 0); 1424 TempOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE; 1425 1426 /* 1427 * Second arg of LEqual will be the Case predicate. 1428 * Mark it as a predicate and also as a parameter list for paren 1429 * closing and correct indentation. 1430 */ 1431 PredicateOp = TempOp->Common.Next; 1432 PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE; 1433 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST; 1434 1435 break; 1436 1437 case (AML_LNOT_OP): 1438 1439 /* 1440 * The Package will be the predicate of the Case statement. 1441 * It's under: 1442 * LNOT 1443 * LEQUAL 1444 * MATCH 1445 * PACKAGE 1446 */ 1447 1448 /* Get the LEqual Op from LNot */ 1449 1450 TempOp = AcpiPsGetArg (TempOp, 0); 1451 1452 /* Get the Match Op from LEqual */ 1453 1454 TempOp = AcpiPsGetArg (TempOp, 0); 1455 1456 /* Get the Package Op from Match */ 1457 1458 PredicateOp = AcpiPsGetArg (TempOp, 0); 1459 1460 /* Mark as parameter list for paren closing */ 1461 1462 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST; 1463 1464 /* 1465 * The Package list would be too deeply indented if we 1466 * chose to simply ignore the all the parent opcodes, so 1467 * we rearrange the parse tree instead. 1468 */ 1469 1470 /* 1471 * Save the second arg of the If/Else Op which is the 1472 * block code of code for this Case statement. 1473 */ 1474 TempOp = AcpiPsGetArg (CurrentOp, 1); 1475 1476 /* 1477 * Move the Package Op to the child (predicate) of the 1478 * Case statement. 1479 */ 1480 CurrentOp->Common.Value.Arg = PredicateOp; 1481 PredicateOp->Common.Parent = CurrentOp; 1482 1483 /* Add the block code */ 1484 1485 PredicateOp->Common.Next = TempOp; 1486 1487 break; 1488 1489 default: 1490 1491 /* Should never get here */ 1492 1493 break; 1494 } 1495 1496 /* Advance to next Case block */ 1497 1498 CurrentOp = CurrentOp->Common.Next; 1499 } 1500 1501 /* If CurrentOp is now an Else, then this is a Default block */ 1502 1503 if (CurrentOp && CurrentOp->Common.AmlOpcode == AML_ELSE_OP) 1504 { 1505 CurrentOp->Common.DisasmOpcode = ACPI_DASM_DEFAULT; 1506 } 1507 1508 /* 1509 * From the first If advance to the Break op. It's possible to 1510 * have an Else (Default) op here when there is only one Case 1511 * statement, so check for it. 1512 */ 1513 CurrentOp = StoreOp->Common.Next->Common.Next; 1514 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP) 1515 { 1516 CurrentOp = CurrentOp->Common.Next; 1517 } 1518 1519 /* Ignore the Break Op */ 1520 1521 CurrentOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; 1522 1523 return (TRUE); 1524 } 1525 1526 /******************************************************************************* 1527 * 1528 * FUNCTION: AcpiDmIsCaseBlock 1529 * 1530 * PARAMETERS: Op - Object to test 1531 * 1532 * RETURN: TRUE if Object is beginning of a Case block. 1533 * 1534 * DESCRIPTION: Determines if an Object is the beginning of a Case block for a 1535 * Switch/Case statement. Parse tree must be one of the following 1536 * forms: 1537 * 1538 * Else (Optional) 1539 * If 1540 * LEqual 1541 * -NamePath- _T_x 1542 * 1543 * Else (Optional) 1544 * If 1545 * LNot 1546 * LEqual 1547 * Match 1548 * Package 1549 * ByteConst 1550 * -NamePath- _T_x 1551 * 1552 ******************************************************************************/ 1553 1554 static BOOLEAN 1555 AcpiDmIsCaseBlock ( 1556 ACPI_PARSE_OBJECT *Op) 1557 { 1558 ACPI_PARSE_OBJECT *CurrentOp; 1559 1560 if (!Op) 1561 { 1562 return (FALSE); 1563 } 1564 1565 /* Look for an If or ElseIf */ 1566 1567 CurrentOp = Op; 1568 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP) 1569 { 1570 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1571 if (!CurrentOp) 1572 { 1573 return (FALSE); 1574 } 1575 } 1576 1577 if (!CurrentOp || CurrentOp->Common.AmlOpcode != AML_IF_OP) 1578 { 1579 return (FALSE); 1580 } 1581 1582 /* Child must be LEqual or LNot */ 1583 1584 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1585 if (!CurrentOp) 1586 { 1587 return (FALSE); 1588 } 1589 1590 switch (CurrentOp->Common.AmlOpcode) 1591 { 1592 case (AML_LEQUAL_OP): 1593 1594 /* Next child must be NamePath with string _T_ */ 1595 1596 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1597 if (!CurrentOp || !CurrentOp->Common.Value.Name || 1598 strncmp(CurrentOp->Common.Value.Name, "_T_", 3)) 1599 { 1600 return (FALSE); 1601 } 1602 1603 break; 1604 1605 case (AML_LNOT_OP): 1606 1607 /* Child of LNot must be LEqual op */ 1608 1609 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1610 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_LEQUAL_OP)) 1611 { 1612 return (FALSE); 1613 } 1614 1615 /* Child of LNot must be Match op */ 1616 1617 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1618 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_MATCH_OP)) 1619 { 1620 return (FALSE); 1621 } 1622 1623 /* First child of Match must be Package op */ 1624 1625 CurrentOp = AcpiPsGetArg (CurrentOp, 0); 1626 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_PACKAGE_OP)) 1627 { 1628 return (FALSE); 1629 } 1630 1631 /* Third child of Match must be NamePath with string _T_ */ 1632 1633 CurrentOp = AcpiPsGetArg (CurrentOp->Common.Parent, 2); 1634 if (!CurrentOp || !CurrentOp->Common.Value.Name || 1635 strncmp(CurrentOp->Common.Value.Name, "_T_", 3)) 1636 { 1637 return (FALSE); 1638 } 1639 1640 break; 1641 1642 default: 1643 1644 return (FALSE); 1645 } 1646 1647 return (TRUE); 1648 } 1649 1650 #endif /* ACPI_DISASSEMBLER */ 1651