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