1 /*******************************************************************************
3 * Module Name: dmopcode - AML disassembler, specific AML opcodes
5 ******************************************************************************/
8 * Copyright (C) 2000 - 2016, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
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>
53 #define _COMPONENT ACPI_CA_DEBUGGER
54 ACPI_MODULE_NAME ("dmopcode")
57 /* Local prototypes */
61 ACPI_PARSE_OBJECT *Op);
64 AcpiDmConvertToElseIf (
65 ACPI_PARSE_OBJECT *Op);
68 AcpiDmPromoteSubtree (
69 ACPI_PARSE_OBJECT *StartOp);
73 ACPI_PARSE_OBJECT *Op);
77 ACPI_PARSE_OBJECT *Op);
79 /*******************************************************************************
81 * FUNCTION: AcpiDmDisplayTargetPathname
83 * PARAMETERS: Op - Parse object
87 * DESCRIPTION: For AML opcodes that have a target operand, display the full
88 * pathname for the target, in a comment field. Handles Return()
91 ******************************************************************************/
94 AcpiDmDisplayTargetPathname (
95 ACPI_PARSE_OBJECT *Op)
97 ACPI_PARSE_OBJECT *NextOp;
98 ACPI_PARSE_OBJECT *PrevOp = NULL;
100 const ACPI_OPCODE_INFO *OpInfo;
103 if (Op->Common.AmlOpcode == AML_RETURN_OP)
105 PrevOp = Op->Asl.Value.Arg;
109 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
110 if (!(OpInfo->Flags & AML_HAS_TARGET))
115 /* Target is the last Op in the arg list */
117 NextOp = Op->Asl.Value.Arg;
121 NextOp = PrevOp->Asl.Next;
130 /* We must have a namepath AML opcode */
132 if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP)
137 /* A null string is the "no target specified" case */
139 if (!PrevOp->Asl.Value.String)
144 /* No node means "unresolved external reference" */
146 if (!PrevOp->Asl.Node)
148 AcpiOsPrintf (" /* External reference */");
152 /* Ignore if path is already from the root */
154 if (*PrevOp->Asl.Value.String == '\\')
159 /* Now: we can get the full pathname */
161 Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node);
167 AcpiOsPrintf (" /* %s */", Pathname);
168 ACPI_FREE (Pathname);
172 /*******************************************************************************
174 * FUNCTION: AcpiDmNotifyDescription
176 * PARAMETERS: Op - Name() parse object
180 * DESCRIPTION: Emit a description comment for the value associated with a
183 ******************************************************************************/
186 AcpiDmNotifyDescription (
187 ACPI_PARSE_OBJECT *Op)
189 ACPI_PARSE_OBJECT *NextOp;
190 ACPI_NAMESPACE_NODE *Node;
192 UINT8 Type = ACPI_TYPE_ANY;
195 /* The notify value is the second argument */
197 NextOp = Op->Asl.Value.Arg;
198 NextOp = NextOp->Asl.Next;
200 switch (NextOp->Common.AmlOpcode)
205 NotifyValue = (UINT8) NextOp->Common.AmlOpcode;
210 NotifyValue = (UINT8) NextOp->Asl.Value.Integer;
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,
228 AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type));
232 /*******************************************************************************
234 * FUNCTION: AcpiDmPredefinedDescription
236 * PARAMETERS: Op - Name() parse object
240 * DESCRIPTION: Emit a description comment for a predefined ACPI name.
241 * Used for iASL compiler only.
243 ******************************************************************************/
246 AcpiDmPredefinedDescription (
247 ACPI_PARSE_OBJECT *Op)
249 #ifdef ACPI_ASL_COMPILER
250 const AH_PREDEFINED_NAME *Info;
261 /* Ensure that the comment field is emitted only once */
263 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED)
267 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED;
269 /* Predefined name must start with an underscore */
271 NameString = ACPI_CAST_PTR (char, &Op->Named.Name);
272 if (NameString[0] != '_')
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)
282 * Convert these to the generic name for table lookup.
283 * Note: NameString is guaranteed to be upper case here.
286 (isdigit ((int) NameString[3])); /* d */
288 (isxdigit ((int) NameString[2]) && /* xx */
289 isxdigit ((int) NameString[3]));
291 switch (NameString[1])
295 if ((NameString[2] == 'C') && (LastCharIsDigit))
299 else if ((NameString[2] == 'L') && (LastCharIsDigit))
307 if ((NameString[2] == 'J') && (LastCharIsDigit))
311 else if (LastCharsAreHex)
335 if (NameString[2] == '_')
354 /* Match the name in the info table */
356 Info = AcpiAhMatchPredefinedName (NameString);
359 AcpiOsPrintf (" // %4.4s: %s",
360 NameString, ACPI_CAST_PTR (char, Info->Description));
368 /*******************************************************************************
370 * FUNCTION: AcpiDmFieldPredefinedDescription
372 * PARAMETERS: Op - Parse object
376 * DESCRIPTION: Emit a description comment for a resource descriptor tag
377 * (which is a predefined ACPI name.) Used for iASL compiler only.
379 ******************************************************************************/
382 AcpiDmFieldPredefinedDescription (
383 ACPI_PARSE_OBJECT *Op)
385 #ifdef ACPI_ASL_COMPILER
386 ACPI_PARSE_OBJECT *IndexOp;
388 const ACPI_OPCODE_INFO *OpInfo;
389 const AH_PREDEFINED_NAME *Info;
397 /* Ensure that the comment field is emitted only once */
399 if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED)
403 Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED;
406 * Op must be one of the Create* operators: CreateField, CreateBitField,
407 * CreateByteField, CreateWordField, CreateDwordField, CreateQwordField
409 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
410 if (!(OpInfo->Flags & AML_CREATE))
415 /* Second argument is the Index argument */
417 IndexOp = Op->Common.Value.Arg;
418 IndexOp = IndexOp->Common.Next;
420 /* Index argument must be a namepath */
422 if (IndexOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP)
427 /* Major cheat: We previously put the Tag ptr in the Node field */
429 Tag = ACPI_CAST_PTR (char, IndexOp->Common.Node);
435 /* Match the name in the info table */
437 Info = AcpiAhMatchPredefinedName (Tag);
440 AcpiOsPrintf (" // %4.4s: %s", Tag,
441 ACPI_CAST_PTR (char, Info->Description));
449 /*******************************************************************************
451 * FUNCTION: AcpiDmMethodFlags
453 * PARAMETERS: Op - Method Object to be examined
457 * DESCRIPTION: Decode control method flags
459 ******************************************************************************/
463 ACPI_PARSE_OBJECT *Op)
469 /* The next Op contains the flags */
471 Op = AcpiPsGetDepthNext (NULL, Op);
472 Flags = (UINT8) Op->Common.Value.Integer;
475 /* Mark the Op as completed */
477 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
479 /* 1) Method argument count */
481 AcpiOsPrintf (", %u, ", Args);
483 /* 2) Serialize rule */
487 AcpiOsPrintf ("Not");
490 AcpiOsPrintf ("Serialized");
496 AcpiOsPrintf (", %u", Flags >> 4);
501 /*******************************************************************************
503 * FUNCTION: AcpiDmFieldFlags
505 * PARAMETERS: Op - Field Object to be examined
509 * DESCRIPTION: Decode Field definition flags
511 ******************************************************************************/
515 ACPI_PARSE_OBJECT *Op)
520 Op = Op->Common.Next;
521 Flags = (UINT8) Op->Common.Value.Integer;
523 /* Mark the Op as completed */
525 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
527 AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]);
528 AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]);
529 AcpiOsPrintf ("%s)", AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]);
533 /*******************************************************************************
535 * FUNCTION: AcpiDmAddressSpace
537 * PARAMETERS: SpaceId - ID to be translated
541 * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword
543 ******************************************************************************/
550 if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS)
554 AcpiOsPrintf ("FFixedHW, ");
558 AcpiOsPrintf ("0x%.2X, ", SpaceId);
563 AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]);
568 /*******************************************************************************
570 * FUNCTION: AcpiDmRegionFlags
572 * PARAMETERS: Op - Object to be examined
576 * DESCRIPTION: Decode OperationRegion flags
578 ******************************************************************************/
582 ACPI_PARSE_OBJECT *Op)
585 /* The next Op contains the SpaceId */
587 Op = AcpiPsGetDepthNext (NULL, Op);
589 /* Mark the Op as completed */
591 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
594 AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer);
598 /*******************************************************************************
600 * FUNCTION: AcpiDmMatchOp
602 * PARAMETERS: Op - Match Object to be examined
606 * DESCRIPTION: Decode Match opcode operands
608 ******************************************************************************/
612 ACPI_PARSE_OBJECT *Op)
614 ACPI_PARSE_OBJECT *NextOp;
617 NextOp = AcpiPsGetDepthNext (NULL, Op);
618 NextOp = NextOp->Common.Next;
622 /* Handle partial tree during single-step */
627 /* Mark the two nodes that contain the encoding for the match keywords */
629 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP;
631 NextOp = NextOp->Common.Next;
632 NextOp = NextOp->Common.Next;
633 NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP;
637 /*******************************************************************************
639 * FUNCTION: AcpiDmMatchKeyword
641 * PARAMETERS: Op - Match Object to be examined
645 * DESCRIPTION: Decode Match opcode operands
647 ******************************************************************************/
651 ACPI_PARSE_OBJECT *Op)
654 if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE)
656 AcpiOsPrintf ("/* Unknown Match Keyword encoding */");
661 AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer]);
666 /*******************************************************************************
668 * FUNCTION: AcpiDmDisassembleOneOp
670 * PARAMETERS: WalkState - Current walk info
671 * Info - Parse tree walk info
672 * Op - Op that is to be printed
676 * DESCRIPTION: Disassemble a single AML opcode
678 ******************************************************************************/
681 AcpiDmDisassembleOneOp (
682 ACPI_WALK_STATE *WalkState,
683 ACPI_OP_WALK_INFO *Info,
684 ACPI_PARSE_OBJECT *Op)
686 const ACPI_OPCODE_INFO *OpInfo = NULL;
689 ACPI_PARSE_OBJECT *Child;
692 const AH_DEVICE_ID *IdInfo;
697 AcpiOsPrintf ("<NULL OP PTR>");
701 if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)
703 return; /* ElseIf macro was already emitted */
706 switch (Op->Common.DisasmOpcode)
708 case ACPI_DASM_MATCHOP:
710 AcpiDmMatchKeyword (Op);
713 case ACPI_DASM_LNOT_SUFFIX:
715 if (!AcpiGbl_CstyleDisassembly)
717 switch (Op->Common.AmlOpcode)
720 AcpiOsPrintf ("LNotEqual");
723 case AML_LGREATER_OP:
724 AcpiOsPrintf ("LLessEqual");
728 AcpiOsPrintf ("LGreaterEqual");
736 Op->Common.DisasmOpcode = 0;
737 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
744 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
746 /* The op and arguments */
748 switch (Op->Common.AmlOpcode)
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))
757 Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
758 Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
762 AcpiOsPrintf ("%s", OpInfo->Name);
768 AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer);
773 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID)
775 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer);
779 AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer);
785 if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID)
787 AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer);
791 AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer);
797 AcpiOsPrintf ("0x%8.8X%8.8X",
798 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
803 AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX);
805 /* For _HID/_CID strings, attempt to output a descriptive comment */
807 if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING)
809 /* If we know about the ID, emit the description */
811 IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String);
814 AcpiOsPrintf (" /* %s */", IdInfo->Description);
821 * Determine the type of buffer. We can have one of the following:
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)
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.
832 if (!AcpiGbl_NoResourceDisassembly)
834 Status = AcpiDmIsResourceTemplate (WalkState, Op);
835 if (ACPI_SUCCESS (Status))
837 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE;
838 AcpiOsPrintf ("ResourceTemplate");
841 else if (Status == AE_AML_NO_RESOURCE_END_TAG)
844 "/**** Is ResourceTemplate, "
845 "but EndTag not at buffer end ****/ ");
849 if (AcpiDmIsUuidBuffer (Op))
851 Op->Common.DisasmOpcode = ACPI_DASM_UUID;
852 AcpiOsPrintf ("ToUUID (");
854 else if (AcpiDmIsUnicodeBuffer (Op))
856 Op->Common.DisasmOpcode = ACPI_DASM_UNICODE;
857 AcpiOsPrintf ("Unicode (");
859 else if (AcpiDmIsStringBuffer (Op))
861 Op->Common.DisasmOpcode = ACPI_DASM_STRING;
862 AcpiOsPrintf ("Buffer");
864 else if (AcpiDmIsPldBuffer (Op))
866 Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD;
867 AcpiOsPrintf ("ToPLD (");
871 Op->Common.DisasmOpcode = ACPI_DASM_BUFFER;
872 AcpiOsPrintf ("Buffer");
876 case AML_INT_NAMEPATH_OP:
878 AcpiDmNamestring (Op->Common.Value.Name);
881 case AML_INT_NAMEDFIELD_OP:
883 Length = AcpiDmDumpName (Op->Named.Name);
884 AcpiOsPrintf (",%*.s %u", (unsigned) (5 - Length), " ",
885 (UINT32) Op->Common.Value.Integer);
886 AcpiDmCommaIfFieldMember (Op);
888 Info->BitOffset += (UINT32) Op->Common.Value.Integer;
891 case AML_INT_RESERVEDFIELD_OP:
893 /* Offset() -- Must account for previous offsets */
895 Offset = (UINT32) Op->Common.Value.Integer;
896 Info->BitOffset += Offset;
898 if (Info->BitOffset % 8 == 0)
900 AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset));
904 AcpiOsPrintf (" , %u", Offset);
907 AcpiDmCommaIfFieldMember (Op);
910 case AML_INT_ACCESSFIELD_OP:
911 case AML_INT_EXTACCESSFIELD_OP:
913 AcpiOsPrintf ("AccessAs (%s, ",
914 AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]);
916 AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8));
918 if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP)
920 AcpiOsPrintf (" (0x%2.2X)", (unsigned)
921 ((Op->Common.Value.Integer >> 16) & 0xFF));
925 AcpiDmCommaIfFieldMember (Op);
928 case AML_INT_CONNECTION_OP:
930 * Two types of Connection() - one with a buffer object, the
931 * other with a namestring that points to a buffer object.
933 AcpiOsPrintf ("Connection (");
934 Child = Op->Common.Value.Arg;
936 if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP)
940 Aml = Child->Named.Data;
941 Length = (UINT32) Child->Common.Value.Integer;
944 Info->MappingOp = Op;
945 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE;
947 AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length);
950 AcpiDmIndent (Info->Level);
954 AcpiDmNamestring (Child->Common.Value.Name);
958 AcpiDmCommaIfFieldMember (Op);
961 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */
962 Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
965 case AML_INT_BYTELIST_OP:
967 AcpiDmByteList (Info, Op);
970 case AML_INT_METHODCALL_OP:
972 Op = AcpiPsGetDepthNext (NULL, Op);
973 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
975 AcpiDmNamestring (Op->Common.Value.Name);
980 if (AcpiDmIsSwitchBlock(Op))
982 AcpiOsPrintf ("%s", "Switch");
986 AcpiOsPrintf ("%s", OpInfo->Name);
991 if (Op->Common.DisasmOpcode == ACPI_DASM_CASE)
993 AcpiOsPrintf ("%s", "Case");
997 AcpiOsPrintf ("%s", OpInfo->Name);
1002 AcpiDmConvertToElseIf (Op);
1005 case AML_EXTERNAL_OP:
1007 if (AcpiGbl_DmEmitExternalOpcodes)
1009 AcpiOsPrintf ("/* Opcode 0x15 */ ");
1020 /* Just get the opcode name and print it */
1022 AcpiOsPrintf ("%s", OpInfo->Name);
1025 #ifdef ACPI_DEBUGGER
1027 if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) &&
1029 (WalkState->Results) &&
1030 (WalkState->ResultCount))
1032 AcpiDbDecodeInternalObject (
1033 WalkState->Results->Results.ObjDesc [
1034 (WalkState->ResultCount - 1) %
1035 ACPI_RESULTS_FRAME_OBJ_NUM]);
1044 /*******************************************************************************
1046 * FUNCTION: AcpiDmConvertToElseIf
1048 * PARAMETERS: OriginalElseOp - ELSE Object to be examined
1050 * RETURN: None. Emits either an "Else" or an "ElseIf" ASL operator.
1052 * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf
1056 * This If..Else..If nested sequence:
1070 * Is converted to this simpler If..ElseIf sequence:
1076 * ElseIf (Arg0 == 2)
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.
1086 ******************************************************************************/
1089 AcpiDmConvertToElseIf (
1090 ACPI_PARSE_OBJECT *OriginalElseOp)
1092 ACPI_PARSE_OBJECT *IfOp;
1093 ACPI_PARSE_OBJECT *ElseOp;
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.
1102 IfOp = OriginalElseOp->Common.Value.Arg;
1105 (IfOp->Common.AmlOpcode != AML_IF_OP) ||
1106 (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP)))
1108 /* Not a proper Else..If sequence, cannot convert to ElseIf */
1110 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1112 AcpiOsPrintf ("%s", "Default");
1116 AcpiOsPrintf ("%s", "Else");
1120 /* Cannot have anything following the If...Else block */
1122 ElseOp = IfOp->Common.Next;
1123 if (ElseOp && ElseOp->Common.Next)
1125 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1127 AcpiOsPrintf ("%s", "Default");
1131 AcpiOsPrintf ("%s", "Else");
1135 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1138 * There is an ElseIf but in this case the Else is actually
1139 * a Default block for a Switch/Case statement. No conversion.
1141 AcpiOsPrintf ("%s", "Default");
1145 if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_CASE)
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.
1152 AcpiOsPrintf ("%s", "Case");
1156 /* Emit ElseIf, mark the IF as now an ELSEIF */
1158 AcpiOsPrintf ("%s", "ElseIf");
1161 IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF;
1163 /* The IF parent will now be the same as the original ELSE parent */
1165 IfOp->Common.Parent = OriginalElseOp->Common.Parent;
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
1172 * Check if the IF has a corresponding ELSE peer
1174 ElseOp = IfOp->Common.Next;
1176 (ElseOp->Common.AmlOpcode == AML_ELSE_OP))
1178 /* If an ELSE matches the IF, promote it also */
1180 ElseOp->Common.Parent = OriginalElseOp->Common.Parent;
1182 /* Promote the entire block under the ElseIf (All Next OPs) */
1184 AcpiDmPromoteSubtree (OriginalElseOp);
1188 /* Otherwise, set the IF NEXT to the original ELSE NEXT */
1190 IfOp->Common.Next = OriginalElseOp->Common.Next;
1193 /* Detach the child IF block from the original ELSE */
1195 OriginalElseOp->Common.Value.Arg = NULL;
1197 /* Ignore the original ELSE from now on */
1199 OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1200 OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
1202 /* Insert IF (now ELSEIF) as next peer of the original ELSE */
1204 OriginalElseOp->Common.Next = IfOp;
1208 /*******************************************************************************
1210 * FUNCTION: AcpiDmPromoteSubtree
1212 * PARAMETERS: StartOpOp - Original parent of the entire subtree
1216 * DESCRIPTION: Promote an entire parse subtree up one level.
1218 ******************************************************************************/
1221 AcpiDmPromoteSubtree (
1222 ACPI_PARSE_OBJECT *StartOp)
1224 ACPI_PARSE_OBJECT *Op;
1225 ACPI_PARSE_OBJECT *ParentOp;
1228 /* New parent for subtree elements */
1230 ParentOp = StartOp->Common.Parent;
1232 /* First child starts the subtree */
1234 Op = StartOp->Common.Value.Arg;
1236 /* Walk the top-level elements of the subtree */
1240 Op->Common.Parent = ParentOp;
1241 if (!Op->Common.Next)
1243 /* Last Op in list, update its next field */
1245 Op->Common.Next = StartOp->Common.Next;
1248 Op = Op->Common.Next;
1252 /*******************************************************************************
1254 * FUNCTION: AcpiDmIsTempName
1256 * PARAMETERS: Op - Object to be examined
1258 * RETURN: TRUE if object is a temporary (_T_x) name
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.
1264 ******************************************************************************/
1268 ACPI_PARSE_OBJECT *Op)
1272 if (Op->Common.AmlOpcode != AML_NAME_OP)
1277 Temp = (char *)(Op->Common.Aml);
1280 if (strncmp(Temp, "_T_", 3))
1287 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1292 /*******************************************************************************
1294 * FUNCTION: AcpiDmIsSwitchBlock
1296 * PARAMETERS: Op - While Object
1298 * RETURN: TRUE if While block can be converted to a Switch/Case block
1300 * DESCRIPTION: Determines if While block is a Switch/Case statement. Modifies
1301 * parse tree to allow for Switch/Case disassembly during walk.
1303 * EXAMPLE: Example of parse tree to be converted
1321 ******************************************************************************/
1324 AcpiDmIsSwitchBlock (
1325 ACPI_PARSE_OBJECT *Op)
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;
1334 /* Check for One Op Predicate */
1336 OneOp = AcpiPsGetArg (Op, 0);
1337 if (!OneOp || (OneOp->Common.AmlOpcode != AML_ONE_OP))
1342 /* Check for Store Op */
1344 StoreOp = OneOp->Common.Next;
1345 if (!StoreOp || (StoreOp->Common.AmlOpcode != AML_STORE_OP))
1350 /* Check for Name Op with _T_ string */
1352 NamePathOp = AcpiPsGetArg (StoreOp, 1);
1353 if (!NamePathOp || (NamePathOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP))
1358 if (strncmp((char *)(NamePathOp->Common.Aml), "_T_", 3))
1363 /* This is a Switch/Case control block */
1365 /* Ignore the One Op Predicate */
1367 OneOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1369 /* Ignore the Store Op, but not the children */
1371 StoreOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE;
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.
1378 PredicateOp = AcpiPsGetArg (StoreOp, 0);
1379 PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE;
1380 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
1382 /* Ignore the Name Op */
1384 NamePathOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE;
1386 /* Remaining opcodes are the Case statements (If/ElseIf's) */
1388 CurrentOp = StoreOp->Common.Next;
1389 while (AcpiDmIsCaseBlock (CurrentOp))
1391 /* Block is a Case structure */
1393 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1397 CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE;
1398 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1403 CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE;
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.
1411 TempOp = AcpiPsGetArg (CurrentOp, 0);
1412 switch (TempOp->Common.AmlOpcode)
1414 case (AML_LEQUAL_OP):
1416 /* Ignore just the LEqual Op */
1418 TempOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE;
1420 /* Ignore the NamePath Op */
1422 TempOp = AcpiPsGetArg (TempOp, 0);
1423 TempOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE;
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.
1430 PredicateOp = TempOp->Common.Next;
1431 PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE;
1432 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
1439 * The Package will be the predicate of the Case statement.
1447 /* Get the LEqual Op from LNot */
1449 TempOp = AcpiPsGetArg (TempOp, 0);
1451 /* Get the Match Op from LEqual */
1453 TempOp = AcpiPsGetArg (TempOp, 0);
1455 /* Get the Package Op from Match */
1457 PredicateOp = AcpiPsGetArg (TempOp, 0);
1459 /* Mark as parameter list for paren closing */
1461 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
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.
1470 * Save the second arg of the If/Else Op which is the
1471 * block code of code for this Case statement.
1473 TempOp = AcpiPsGetArg (CurrentOp, 1);
1476 * Move the Package Op to the child (predicate) of the
1479 CurrentOp->Common.Value.Arg = PredicateOp;
1480 PredicateOp->Common.Parent = CurrentOp;
1482 /* Add the block code */
1484 PredicateOp->Common.Next = TempOp;
1490 /* Should never get here */
1495 /* Advance to next Case block */
1497 CurrentOp = CurrentOp->Common.Next;
1500 /* If CurrentOp is now an Else, then this is a Default block */
1502 if (CurrentOp && CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1504 CurrentOp->Common.DisasmOpcode = ACPI_DASM_DEFAULT;
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.
1512 CurrentOp = StoreOp->Common.Next->Common.Next;
1513 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1515 CurrentOp = CurrentOp->Common.Next;
1518 /* Ignore the Break Op */
1520 CurrentOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1525 /*******************************************************************************
1527 * FUNCTION: AcpiDmIsCaseBlock
1529 * PARAMETERS: Op - Object to test
1531 * RETURN: TRUE if Object is beginning of a Case block.
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
1551 ******************************************************************************/
1555 ACPI_PARSE_OBJECT *Op)
1557 ACPI_PARSE_OBJECT *CurrentOp;
1564 /* Look for an If or ElseIf */
1567 if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1569 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1576 if (!CurrentOp || CurrentOp->Common.AmlOpcode != AML_IF_OP)
1581 /* Child must be LEqual or LNot */
1583 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1589 switch (CurrentOp->Common.AmlOpcode)
1591 case (AML_LEQUAL_OP):
1593 /* Next child must be NamePath with string _T_ */
1595 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1596 if (!CurrentOp || !CurrentOp->Common.Value.Name ||
1597 strncmp(CurrentOp->Common.Value.Name, "_T_", 3))
1606 /* Child of LNot must be LEqual op */
1608 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1609 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_LEQUAL_OP))
1614 /* Child of LNot must be Match op */
1616 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1617 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_MATCH_OP))
1622 /* First child of Match must be Package op */
1624 CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1625 if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_PACKAGE_OP))
1630 /* Third child of Match must be NamePath with string _T_ */
1632 CurrentOp = AcpiPsGetArg (CurrentOp->Common.Parent, 2);
1633 if (!CurrentOp || !CurrentOp->Common.Value.Name ||
1634 strncmp(CurrentOp->Common.Value.Name, "_T_", 3))