dmopcode.c revision 298714
1189251Ssam/*******************************************************************************
2189251Ssam *
3189251Ssam * Module Name: dmopcode - AML disassembler, specific AML opcodes
4189251Ssam *
5252726Srpaulo ******************************************************************************/
6252726Srpaulo
7189251Ssam/*
8189251Ssam * Copyright (C) 2000 - 2016, Intel Corp.
9189251Ssam * All rights reserved.
10189251Ssam *
11189251Ssam * Redistribution and use in source and binary forms, with or without
12214734Srpaulo * modification, are permitted provided that the following conditions
13189251Ssam * are met:
14189251Ssam * 1. Redistributions of source code must retain the above copyright
15189251Ssam *    notice, this list of conditions, and the following disclaimer,
16189251Ssam *    without modification.
17189251Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18189251Ssam *    substantially similar to the "NO WARRANTY" disclaimer below
19189251Ssam *    ("Disclaimer") and any redistribution must be conditioned upon
20189251Ssam *    including a substantially similar Disclaimer requirement for further
21189251Ssam *    binary redistribution.
22189251Ssam * 3. Neither the names of the above-listed copyright holders nor the names
23189251Ssam *    of any contributors may be used to endorse or promote products derived
24189251Ssam *    from this software without specific prior written permission.
25189251Ssam *
26189251Ssam * Alternatively, this software may be distributed under the terms of the
27189251Ssam * GNU General Public License ("GPL") version 2 as published by the Free
28189251Ssam * Software Foundation.
29189251Ssam *
30189251Ssam * NO WARRANTY
31189251Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32189251Ssam * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33189251Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34189251Ssam * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35189251Ssam * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36189251Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37189251Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38189251Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39189251Ssam * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40189251Ssam * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41189251Ssam * POSSIBILITY OF SUCH DAMAGES.
42189251Ssam */
43189251Ssam
44189251Ssam#include <contrib/dev/acpica/include/acpi.h>
45189251Ssam#include <contrib/dev/acpica/include/accommon.h>
46189251Ssam#include <contrib/dev/acpica/include/acparser.h>
47189251Ssam#include <contrib/dev/acpica/include/amlcode.h>
48189251Ssam#include <contrib/dev/acpica/include/acinterp.h>
49189251Ssam#include <contrib/dev/acpica/include/acnamesp.h>
50189251Ssam#include <contrib/dev/acpica/include/acdebug.h>
51189251Ssam
52189251Ssam
53189251Ssam#define _COMPONENT          ACPI_CA_DEBUGGER
54189251Ssam        ACPI_MODULE_NAME    ("dmopcode")
55189251Ssam
56189251Ssam
57189251Ssam/* Local prototypes */
58189251Ssam
59189251Ssamstatic void
60189251SsamAcpiDmMatchKeyword (
61189251Ssam    ACPI_PARSE_OBJECT       *Op);
62189251Ssam
63189251Ssamstatic void
64189251SsamAcpiDmConvertToElseIf (
65189251Ssam    ACPI_PARSE_OBJECT       *Op);
66189251Ssam
67189251Ssam
68189251Ssam/*******************************************************************************
69189251Ssam *
70189251Ssam * FUNCTION:    AcpiDmDisplayTargetPathname
71189251Ssam *
72189251Ssam * PARAMETERS:  Op              - Parse object
73189251Ssam *
74189251Ssam * RETURN:      None
75189251Ssam *
76189251Ssam * DESCRIPTION: For AML opcodes that have a target operand, display the full
77189251Ssam *              pathname for the target, in a comment field. Handles Return()
78189251Ssam *              statements also.
79189251Ssam *
80189251Ssam ******************************************************************************/
81189251Ssam
82189251Ssamvoid
83189251SsamAcpiDmDisplayTargetPathname (
84189251Ssam    ACPI_PARSE_OBJECT       *Op)
85189251Ssam{
86189251Ssam    ACPI_PARSE_OBJECT       *NextOp;
87189251Ssam    ACPI_PARSE_OBJECT       *PrevOp = NULL;
88189251Ssam    char                    *Pathname;
89189251Ssam    const ACPI_OPCODE_INFO  *OpInfo;
90189251Ssam
91189251Ssam
92189251Ssam    if (Op->Common.AmlOpcode == AML_RETURN_OP)
93189251Ssam    {
94189251Ssam        PrevOp = Op->Asl.Value.Arg;
95189251Ssam    }
96189251Ssam    else
97189251Ssam    {
98189251Ssam        OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
99189251Ssam        if (!(OpInfo->Flags & AML_HAS_TARGET))
100189251Ssam        {
101189251Ssam            return;
102189251Ssam        }
103189251Ssam
104189251Ssam        /* Target is the last Op in the arg list */
105189251Ssam
106189251Ssam        NextOp = Op->Asl.Value.Arg;
107189251Ssam        while (NextOp)
108189251Ssam        {
109189251Ssam            PrevOp = NextOp;
110189251Ssam            NextOp = PrevOp->Asl.Next;
111189251Ssam        }
112189251Ssam    }
113189251Ssam
114189251Ssam    if (!PrevOp)
115189251Ssam    {
116189251Ssam        return;
117189251Ssam    }
118189251Ssam
119189251Ssam    /* We must have a namepath AML opcode */
120189251Ssam
121189251Ssam    if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP)
122189251Ssam    {
123189251Ssam        return;
124189251Ssam    }
125189251Ssam
126189251Ssam    /* A null string is the "no target specified" case */
127189251Ssam
128189251Ssam    if (!PrevOp->Asl.Value.String)
129189251Ssam    {
130189251Ssam        return;
131189251Ssam    }
132189251Ssam
133189251Ssam    /* No node means "unresolved external reference" */
134189251Ssam
135189251Ssam    if (!PrevOp->Asl.Node)
136189251Ssam    {
137189251Ssam        AcpiOsPrintf (" /* External reference */");
138189251Ssam        return;
139189251Ssam    }
140189251Ssam
141189251Ssam    /* Ignore if path is already from the root */
142189251Ssam
143189251Ssam    if (*PrevOp->Asl.Value.String == '\\')
144189251Ssam    {
145189251Ssam        return;
146189251Ssam    }
147189251Ssam
148189251Ssam    /* Now: we can get the full pathname */
149189251Ssam
150189251Ssam    Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node);
151189251Ssam    if (!Pathname)
152189251Ssam    {
153189251Ssam        return;
154189251Ssam    }
155189251Ssam
156189251Ssam    AcpiOsPrintf (" /* %s */", Pathname);
157189251Ssam    ACPI_FREE (Pathname);
158189251Ssam}
159189251Ssam
160189251Ssam
161189251Ssam/*******************************************************************************
162189251Ssam *
163189251Ssam * FUNCTION:    AcpiDmNotifyDescription
164189251Ssam *
165189251Ssam * PARAMETERS:  Op              - Name() parse object
166189251Ssam *
167189251Ssam * RETURN:      None
168189251Ssam *
169189251Ssam * DESCRIPTION: Emit a description comment for the value associated with a
170189251Ssam *              Notify() operator.
171189251Ssam *
172189251Ssam ******************************************************************************/
173189251Ssam
174214734Srpaulovoid
175214734SrpauloAcpiDmNotifyDescription (
176214734Srpaulo    ACPI_PARSE_OBJECT       *Op)
177214734Srpaulo{
178214734Srpaulo    ACPI_PARSE_OBJECT       *NextOp;
179214734Srpaulo    ACPI_NAMESPACE_NODE     *Node;
180214734Srpaulo    UINT8                   NotifyValue;
181189251Ssam    UINT8                   Type = ACPI_TYPE_ANY;
182189251Ssam
183189251Ssam
184189251Ssam    /* The notify value is the second argument */
185189251Ssam
186189251Ssam    NextOp = Op->Asl.Value.Arg;
187189251Ssam    NextOp = NextOp->Asl.Next;
188189251Ssam
189189251Ssam    switch (NextOp->Common.AmlOpcode)
190189251Ssam    {
191189251Ssam    case AML_ZERO_OP:
192189251Ssam    case AML_ONE_OP:
193189251Ssam
194189251Ssam        NotifyValue = (UINT8) NextOp->Common.AmlOpcode;
195189251Ssam        break;
196189251Ssam
197189251Ssam    case AML_BYTE_OP:
198189251Ssam
199189251Ssam        NotifyValue = (UINT8) NextOp->Asl.Value.Integer;
200189251Ssam        break;
201189251Ssam
202189251Ssam    default:
203189251Ssam        return;
204189251Ssam    }
205189251Ssam
206189251Ssam    /*
207189251Ssam     * Attempt to get the namespace node so we can determine the object type.
208189251Ssam     * Some notify values are dependent on the object type (Device, Thermal,
209189251Ssam     * or Processor).
210189251Ssam     */
211189251Ssam    Node = Op->Asl.Node;
212189251Ssam    if (Node)
213189251Ssam    {
214189251Ssam        Type = Node->Type;
215189251Ssam    }
216189251Ssam
217189251Ssam    AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type));
218189251Ssam}
219189251Ssam
220189251Ssam
221189251Ssam/*******************************************************************************
222189251Ssam *
223189251Ssam * FUNCTION:    AcpiDmPredefinedDescription
224189251Ssam *
225189251Ssam * PARAMETERS:  Op              - Name() parse object
226189251Ssam *
227189251Ssam * RETURN:      None
228189251Ssam *
229189251Ssam * DESCRIPTION: Emit a description comment for a predefined ACPI name.
230189251Ssam *              Used for iASL compiler only.
231189251Ssam *
232189251Ssam ******************************************************************************/
233189251Ssam
234189251Ssamvoid
235189251SsamAcpiDmPredefinedDescription (
236189251Ssam    ACPI_PARSE_OBJECT       *Op)
237189251Ssam{
238189251Ssam#ifdef ACPI_ASL_COMPILER
239189251Ssam    const AH_PREDEFINED_NAME    *Info;
240189251Ssam    char                        *NameString;
241189251Ssam    int                         LastCharIsDigit;
242189251Ssam    int                         LastCharsAreHex;
243189251Ssam
244189251Ssam
245189251Ssam    if (!Op)
246189251Ssam    {
247189251Ssam        return;
248189251Ssam    }
249189251Ssam
250189251Ssam    /* Ensure that the comment field is emitted only once */
251189251Ssam
252189251Ssam    if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED)
253189251Ssam    {
254189251Ssam        return;
255189251Ssam    }
256189251Ssam    Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED;
257189251Ssam
258189251Ssam    /* Predefined name must start with an underscore */
259189251Ssam
260189251Ssam    NameString = ACPI_CAST_PTR (char, &Op->Named.Name);
261252726Srpaulo    if (NameString[0] != '_')
262252726Srpaulo    {
263189251Ssam        return;
264252726Srpaulo    }
265252726Srpaulo
266252726Srpaulo    /*
267252726Srpaulo     * Check for the special ACPI names:
268252726Srpaulo     * _ACd, _ALd, _EJd, _Exx, _Lxx, _Qxx, _Wxx, _T_a
269252726Srpaulo     * (where d=decimal_digit, x=hex_digit, a=anything)
270252726Srpaulo     *
271252726Srpaulo     * Convert these to the generic name for table lookup.
272252726Srpaulo     * Note: NameString is guaranteed to be upper case here.
273252726Srpaulo     */
274252726Srpaulo    LastCharIsDigit =
275252726Srpaulo        (isdigit ((int) NameString[3]));    /* d */
276189251Ssam    LastCharsAreHex =
277189251Ssam        (isxdigit ((int) NameString[2]) &&  /* xx */
278189251Ssam         isxdigit ((int) NameString[3]));
279252726Srpaulo
280252726Srpaulo    switch (NameString[1])
281252726Srpaulo    {
282252726Srpaulo    case 'A':
283252726Srpaulo
284252726Srpaulo        if ((NameString[2] == 'C') && (LastCharIsDigit))
285252726Srpaulo        {
286189251Ssam            NameString = "_ACx";
287189251Ssam        }
288189251Ssam        else if ((NameString[2] == 'L') && (LastCharIsDigit))
289189251Ssam        {
290189251Ssam            NameString = "_ALx";
291189251Ssam        }
292189251Ssam        break;
293189251Ssam
294252726Srpaulo    case 'E':
295189251Ssam
296252726Srpaulo        if ((NameString[2] == 'J') && (LastCharIsDigit))
297189251Ssam        {
298189251Ssam            NameString = "_EJx";
299189251Ssam        }
300189251Ssam        else if (LastCharsAreHex)
301189251Ssam        {
302189251Ssam            NameString = "_Exx";
303189251Ssam        }
304189251Ssam        break;
305189251Ssam
306189251Ssam    case 'L':
307189251Ssam
308189251Ssam        if (LastCharsAreHex)
309189251Ssam        {
310189251Ssam            NameString = "_Lxx";
311189251Ssam        }
312189251Ssam        break;
313189251Ssam
314189251Ssam    case 'Q':
315189251Ssam
316189251Ssam        if (LastCharsAreHex)
317189251Ssam        {
318189251Ssam            NameString = "_Qxx";
319252726Srpaulo        }
320252726Srpaulo        break;
321189251Ssam
322189251Ssam    case 'T':
323252726Srpaulo
324189251Ssam        if (NameString[2] == '_')
325189251Ssam        {
326189251Ssam            NameString = "_T_x";
327189251Ssam        }
328189251Ssam        break;
329189251Ssam
330189251Ssam    case 'W':
331189251Ssam
332189251Ssam        if (LastCharsAreHex)
333189251Ssam        {
334189251Ssam            NameString = "_Wxx";
335189251Ssam        }
336189251Ssam        break;
337189251Ssam
338189251Ssam    default:
339189251Ssam
340189251Ssam        break;
341189251Ssam    }
342252726Srpaulo
343189251Ssam    /* 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
370void
371AcpiDmFieldPredefinedDescription (
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
450void
451AcpiDmMethodFlags (
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
502void
503AcpiDmFieldFlags (
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
534void
535AcpiDmAddressSpace (
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
569void
570AcpiDmRegionFlags (
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
599void
600AcpiDmMatchOp (
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
638static void
639AcpiDmMatchKeyword (
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
669void
670AcpiDmDisassembleOneOp (
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        break;
975
976    default:
977
978        /* Just get the opcode name and print it */
979
980        AcpiOsPrintf ("%s", OpInfo->Name);
981
982
983#ifdef ACPI_DEBUGGER
984
985        if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) &&
986            (WalkState) &&
987            (WalkState->Results) &&
988            (WalkState->ResultCount))
989        {
990            AcpiDbDecodeInternalObject (
991                WalkState->Results->Results.ObjDesc [
992                    (WalkState->ResultCount - 1) %
993                        ACPI_RESULTS_FRAME_OBJ_NUM]);
994        }
995#endif
996
997        break;
998    }
999}
1000
1001
1002/*******************************************************************************
1003 *
1004 * FUNCTION:    AcpiDmConvertToElseIf
1005 *
1006 * PARAMETERS:  OriginalElseOp          - ELSE Object to be examined
1007 *
1008 * RETURN:      None. Emits either an "Else" or an "ElseIf" ASL operator.
1009 *
1010 * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf
1011 *
1012 * EXAMPLE:
1013 *
1014 * This If..Else..If nested sequence:
1015 *
1016 *        If (Arg0 == 1)
1017 *        {
1018 *            Local0 = 4
1019 *        }
1020 *        Else
1021 *        {
1022 *            If (Arg0 == 2)
1023 *            {
1024 *                Local0 = 5
1025 *            }
1026 *        }
1027 *
1028 * Is converted to this simpler If..ElseIf sequence:
1029 *
1030 *        If (Arg0 == 1)
1031 *        {
1032 *            Local0 = 4
1033 *        }
1034 *        ElseIf (Arg0 == 2)
1035 *        {
1036 *            Local0 = 5
1037 *        }
1038 *
1039 * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL
1040 * macro that emits an Else opcode followed by an If opcode. This function
1041 * reverses these AML sequences back to an ElseIf macro where possible. This
1042 * can make the disassembled ASL code simpler and more like the original code.
1043 *
1044 ******************************************************************************/
1045
1046static void
1047AcpiDmConvertToElseIf (
1048    ACPI_PARSE_OBJECT       *OriginalElseOp)
1049{
1050    ACPI_PARSE_OBJECT       *IfOp;
1051    ACPI_PARSE_OBJECT       *ElseOp;
1052
1053
1054    /*
1055     * To be able to perform the conversion, two conditions must be satisfied:
1056     * 1) The first child of the Else must be an If statement.
1057     * 2) The If block can only be followed by an Else block and these must
1058     *    be the only blocks under the original Else.
1059     */
1060    IfOp = OriginalElseOp->Common.Value.Arg;
1061    if (!IfOp ||
1062        (IfOp->Common.AmlOpcode != AML_IF_OP) ||
1063        (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP)))
1064    {
1065        /* Not an Else..If sequence, cannot convert to ElseIf */
1066
1067        AcpiOsPrintf ("%s", "Else");
1068        return;
1069    }
1070
1071    /* Emit ElseIf, mark the IF as now an ELSEIF */
1072
1073    AcpiOsPrintf ("%s", "ElseIf");
1074    IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF;
1075
1076    /* The IF parent will now be the same as the original ELSE parent */
1077
1078    IfOp->Common.Parent = OriginalElseOp->Common.Parent;
1079
1080    /*
1081     * Update the NEXT pointers to restructure the parse tree, essentially
1082     * promoting an If..Else block up to the same level as the original
1083     * Else.
1084     *
1085     * Check if the IF has a corresponding ELSE peer
1086     */
1087    ElseOp = IfOp->Common.Next;
1088    if (ElseOp &&
1089        (ElseOp->Common.AmlOpcode == AML_ELSE_OP))
1090    {
1091        /* If an ELSE matches the IF, promote it also */
1092
1093        ElseOp->Common.Parent = OriginalElseOp->Common.Parent;
1094        ElseOp->Common.Next = OriginalElseOp->Common.Next;
1095    }
1096    else
1097    {
1098        /* Otherwise, set the IF NEXT to the original ELSE NEXT */
1099
1100        IfOp->Common.Next = OriginalElseOp->Common.Next;
1101    }
1102
1103    /* Detach the child IF block from the original ELSE */
1104
1105    OriginalElseOp->Common.Value.Arg = NULL;
1106
1107    /* Ignore the original ELSE from now on */
1108
1109    OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1110    OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
1111
1112    /* Insert IF (now ELSEIF) as next peer of the original ELSE */
1113
1114    OriginalElseOp->Common.Next = IfOp;
1115}
1116