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