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