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