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