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