Home | History | Annotate | Line # | Download | only in compiler
asltransform.c revision 1.1.1.15
      1 /******************************************************************************
      2  *
      3  * Module Name: asltransform - Parse tree transforms
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2019, Intel Corp.
      9  * All rights reserved.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions, and the following disclaimer,
     16  *    without modification.
     17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  *    including a substantially similar Disclaimer requirement for further
     21  *    binary redistribution.
     22  * 3. Neither the names of the above-listed copyright holders nor the names
     23  *    of any contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * Alternatively, this software may be distributed under the terms of the
     27  * GNU General Public License ("GPL") version 2 as published by the Free
     28  * Software Foundation.
     29  *
     30  * NO WARRANTY
     31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  * POSSIBILITY OF SUCH DAMAGES.
     42  */
     43 
     44 #include "aslcompiler.h"
     45 #include "aslcompiler.y.h"
     46 #include "acnamesp.h"
     47 
     48 #define _COMPONENT          ACPI_COMPILER
     49         ACPI_MODULE_NAME    ("asltransform")
     50 
     51 /* Local prototypes */
     52 
     53 static void
     54 TrTransformSubtree (
     55     ACPI_PARSE_OBJECT       *Op);
     56 
     57 static char *
     58 TrAmlGetNextTempName (
     59     ACPI_PARSE_OBJECT       *Op,
     60     UINT8                   *TempCount);
     61 
     62 static void
     63 TrAmlInitLineNumbers (
     64     ACPI_PARSE_OBJECT       *Op,
     65     ACPI_PARSE_OBJECT       *Neighbor);
     66 
     67 static void
     68 TrAmlInitNode (
     69     ACPI_PARSE_OBJECT       *Op,
     70     UINT16                  ParseOpcode);
     71 
     72 static void
     73 TrAmlSetSubtreeParent (
     74     ACPI_PARSE_OBJECT       *Op,
     75     ACPI_PARSE_OBJECT       *Parent);
     76 
     77 static void
     78 TrAmlInsertPeer (
     79     ACPI_PARSE_OBJECT       *Op,
     80     ACPI_PARSE_OBJECT       *NewPeer);
     81 
     82 static void
     83 TrDoDefinitionBlock (
     84     ACPI_PARSE_OBJECT       *Op);
     85 
     86 static void
     87 TrDoSwitch (
     88     ACPI_PARSE_OBJECT       *StartNode);
     89 
     90 static void
     91 TrCheckForDuplicateCase (
     92     ACPI_PARSE_OBJECT       *CaseOp,
     93     ACPI_PARSE_OBJECT       *Predicate1);
     94 
     95 static BOOLEAN
     96 TrCheckForBufferMatch (
     97     ACPI_PARSE_OBJECT       *Next1,
     98     ACPI_PARSE_OBJECT       *Next2);
     99 
    100 
    101 /*******************************************************************************
    102  *
    103  * FUNCTION:    TrAmlGetNextTempName
    104  *
    105  * PARAMETERS:  Op              - Current parse op
    106  *              TempCount       - Current temporary counter. Was originally
    107  *                                per-module; Currently per method, could be
    108  *                                expanded to per-scope.
    109  *
    110  * RETURN:      A pointer to name (allocated here).
    111  *
    112  * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are
    113  *              reserved for use by the ASL compiler. (_T_0 through _T_Z)
    114  *
    115  ******************************************************************************/
    116 
    117 static char *
    118 TrAmlGetNextTempName (
    119     ACPI_PARSE_OBJECT       *Op,
    120     UINT8                   *TempCount)
    121 {
    122     char                    *TempName;
    123 
    124 
    125     if (*TempCount >= (10 + 26))  /* 0-35 valid: 0-9 and A-Z for TempName[3] */
    126     {
    127         /* Too many temps */
    128 
    129         AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL);
    130         return (NULL);
    131     }
    132 
    133     TempName = UtLocalCalloc (5);
    134 
    135     if (*TempCount < 10)    /* 0-9 */
    136     {
    137         TempName[3] = (char) (*TempCount + '0');
    138     }
    139     else                    /* 10-35: A-Z */
    140     {
    141         TempName[3] = (char) (*TempCount + ('A' - 10));
    142     }
    143 
    144     (*TempCount)++;
    145 
    146     /* First three characters are always "_T_" */
    147 
    148     TempName[0] = '_';
    149     TempName[1] = 'T';
    150     TempName[2] = '_';
    151 
    152     return (TempName);
    153 }
    154 
    155 
    156 /*******************************************************************************
    157  *
    158  * FUNCTION:    TrAmlInitLineNumbers
    159  *
    160  * PARAMETERS:  Op              - Op to be initialized
    161  *              Neighbor        - Op used for initialization values
    162  *
    163  * RETURN:      None
    164  *
    165  * DESCRIPTION: Initialized the various line numbers for a parse node.
    166  *
    167  ******************************************************************************/
    168 
    169 static void
    170 TrAmlInitLineNumbers (
    171     ACPI_PARSE_OBJECT       *Op,
    172     ACPI_PARSE_OBJECT       *Neighbor)
    173 {
    174 
    175     Op->Asl.EndLine           = Neighbor->Asl.EndLine;
    176     Op->Asl.EndLogicalLine    = Neighbor->Asl.EndLogicalLine;
    177     Op->Asl.LineNumber        = Neighbor->Asl.LineNumber;
    178     Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset;
    179     Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber;
    180 }
    181 
    182 
    183 /*******************************************************************************
    184  *
    185  * FUNCTION:    TrAmlInitNode
    186  *
    187  * PARAMETERS:  Op              - Op to be initialized
    188  *              ParseOpcode     - Opcode for this node
    189  *
    190  * RETURN:      None
    191  *
    192  * DESCRIPTION: Initialize a node with the parse opcode and opcode name.
    193  *
    194  ******************************************************************************/
    195 
    196 static void
    197 TrAmlInitNode (
    198     ACPI_PARSE_OBJECT       *Op,
    199     UINT16                  ParseOpcode)
    200 {
    201 
    202     Op->Asl.ParseOpcode = ParseOpcode;
    203     UtSetParseOpName (Op);
    204 }
    205 
    206 
    207 /*******************************************************************************
    208  *
    209  * FUNCTION:    TrAmlSetSubtreeParent
    210  *
    211  * PARAMETERS:  Op              - First node in a list of peer nodes
    212  *              Parent          - Parent of the subtree
    213  *
    214  * RETURN:      None
    215  *
    216  * DESCRIPTION: Set the parent for all peer nodes in a subtree
    217  *
    218  ******************************************************************************/
    219 
    220 static void
    221 TrAmlSetSubtreeParent (
    222     ACPI_PARSE_OBJECT       *Op,
    223     ACPI_PARSE_OBJECT       *Parent)
    224 {
    225     ACPI_PARSE_OBJECT       *Next;
    226 
    227 
    228     Next = Op;
    229     while (Next)
    230     {
    231         Next->Asl.Parent = Parent;
    232         Next = Next->Asl.Next;
    233     }
    234 }
    235 
    236 
    237 /*******************************************************************************
    238  *
    239  * FUNCTION:    TrAmlInsertPeer
    240  *
    241  * PARAMETERS:  Op              - First node in a list of peer nodes
    242  *              NewPeer         - Peer node to insert
    243  *
    244  * RETURN:      None
    245  *
    246  * DESCRIPTION: Insert a new peer node into a list of peers.
    247  *
    248  ******************************************************************************/
    249 
    250 static void
    251 TrAmlInsertPeer (
    252     ACPI_PARSE_OBJECT       *Op,
    253     ACPI_PARSE_OBJECT       *NewPeer)
    254 {
    255 
    256     NewPeer->Asl.Next = Op->Asl.Next;
    257     Op->Asl.Next = NewPeer;
    258 }
    259 
    260 
    261 /*******************************************************************************
    262  *
    263  * FUNCTION:    TrAmlTransformWalkBegin
    264  *
    265  * PARAMETERS:  ASL_WALK_CALLBACK
    266  *
    267  * RETURN:      None
    268  *
    269  * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
    270  *              operands.
    271  *
    272  ******************************************************************************/
    273 
    274 ACPI_STATUS
    275 TrAmlTransformWalkBegin (
    276     ACPI_PARSE_OBJECT       *Op,
    277     UINT32                  Level,
    278     void                    *Context)
    279 {
    280 
    281     TrTransformSubtree (Op);
    282     return (AE_OK);
    283 }
    284 
    285 
    286 /*******************************************************************************
    287  *
    288  * FUNCTION:    TrAmlTransformWalkEnd
    289  *
    290  * PARAMETERS:  ASL_WALK_CALLBACK
    291  *
    292  * RETURN:      None
    293  *
    294  * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
    295  *              operands.
    296  *
    297  ******************************************************************************/
    298 
    299 ACPI_STATUS
    300 TrAmlTransformWalkEnd (
    301     ACPI_PARSE_OBJECT       *Op,
    302     UINT32                  Level,
    303     void                    *Context)
    304 {
    305 
    306     /* Save possible Externals list in the DefintionBlock Op */
    307 
    308     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
    309     {
    310         Op->Asl.Value.Arg = AslGbl_ExternalsListHead;
    311         AslGbl_ExternalsListHead = NULL;
    312     }
    313 
    314     return (AE_OK);
    315 }
    316 
    317 
    318 /*******************************************************************************
    319  *
    320  * FUNCTION:    TrTransformSubtree
    321  *
    322  * PARAMETERS:  Op        - The parent parse node
    323  *
    324  * RETURN:      None
    325  *
    326  * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more
    327  *              complex AML opcodes require processing of the child nodes
    328  *              (arguments/operands).
    329  *
    330  ******************************************************************************/
    331 
    332 static void
    333 TrTransformSubtree (
    334     ACPI_PARSE_OBJECT           *Op)
    335 {
    336     ACPI_PARSE_OBJECT           *MethodOp;
    337     ACPI_NAMESTRING_INFO        Info;
    338 
    339 
    340     if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE)
    341     {
    342         return;
    343     }
    344 
    345     switch (Op->Asl.ParseOpcode)
    346     {
    347     case PARSEOP_DEFINITION_BLOCK:
    348 
    349         TrDoDefinitionBlock (Op);
    350         break;
    351 
    352     case PARSEOP_SWITCH:
    353 
    354         TrDoSwitch (Op);
    355         break;
    356 
    357     case PARSEOP_METHOD:
    358         /*
    359          * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global,
    360          * however
    361          */
    362         AslGbl_TempCount = 0;
    363         break;
    364 
    365     case PARSEOP_EXTERNAL:
    366 
    367         ExDoExternal (Op);
    368         break;
    369 
    370     case PARSEOP___METHOD__:
    371 
    372         /* Transform to a string op containing the parent method name */
    373 
    374         Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
    375         UtSetParseOpName (Op);
    376 
    377         /* Find the parent control method op */
    378 
    379         MethodOp = Op;
    380         while (MethodOp)
    381         {
    382             if (MethodOp->Asl.ParseOpcode == PARSEOP_METHOD)
    383             {
    384                 /* First child contains the method name */
    385 
    386                 MethodOp = MethodOp->Asl.Child;
    387                 Op->Asl.Value.String = MethodOp->Asl.Value.String;
    388                 return;
    389             }
    390 
    391             MethodOp = MethodOp->Asl.Parent;
    392         }
    393 
    394         /* At the root, invocation not within a control method */
    395 
    396         Op->Asl.Value.String = "\\";
    397         break;
    398 
    399     case PARSEOP_NAMESTRING:
    400         /*
    401          * A NameString can be up to 255 (0xFF) individual NameSegs maximum
    402          * (with 254 dot separators) - as per the ACPI specification. Note:
    403          * Cannot check for NumSegments == 0 because things like
    404          * Scope(\) are legal and OK.
    405          */
    406         Info.ExternalName = Op->Asl.Value.String;
    407         AcpiNsGetInternalNameLength (&Info);
    408 
    409         if (Info.NumSegments > 255)
    410         {
    411             AslError (ASL_ERROR, ASL_MSG_NAMESTRING_LENGTH, Op, NULL);
    412         }
    413         break;
    414 
    415     case PARSEOP_UNLOAD:
    416 
    417         AslError (ASL_WARNING, ASL_MSG_UNLOAD, Op, NULL);
    418         break;
    419 
    420     case PARSEOP_SLEEP:
    421 
    422         /* Remark for very long sleep values */
    423 
    424         if (Op->Asl.Child->Asl.Value.Integer > 1000)
    425         {
    426             AslError (ASL_REMARK, ASL_MSG_LONG_SLEEP, Op, NULL);
    427         }
    428         break;
    429 
    430     case PARSEOP_PROCESSOR:
    431 
    432         AslError (ASL_WARNING, ASL_MSG_LEGACY_PROCESSOR_OP, Op, Op->Asl.ExternalName);
    433         break;
    434 
    435     default:
    436 
    437         /* Nothing to do here for other opcodes */
    438 
    439         break;
    440     }
    441 }
    442 
    443 
    444 /*******************************************************************************
    445  *
    446  * FUNCTION:    TrDoDefinitionBlock
    447  *
    448  * PARAMETERS:  Op        - Parse node
    449  *
    450  * RETURN:      None
    451  *
    452  * DESCRIPTION: Find the end of the definition block and set a global to this
    453  *              node. It is used by the compiler to insert compiler-generated
    454  *              names at the root level of the namespace.
    455  *
    456  ******************************************************************************/
    457 
    458 static void
    459 TrDoDefinitionBlock (
    460     ACPI_PARSE_OBJECT       *Op)
    461 {
    462     ACPI_PARSE_OBJECT       *Next;
    463     UINT32                  i;
    464 
    465 
    466     /* Reset external list when starting a definition block */
    467 
    468     AslGbl_ExternalsListHead = NULL;
    469 
    470     Next = Op->Asl.Child;
    471     for (i = 0; i < 5; i++)
    472     {
    473         Next = Next->Asl.Next;
    474         if (i == 0)
    475         {
    476             /*
    477              * This is the table signature. Only the DSDT can be assumed
    478              * to be at the root of the namespace;  Therefore, namepath
    479              * optimization can only be performed on the DSDT.
    480              */
    481             if (!ACPI_COMPARE_NAMESEG (Next->Asl.Value.String, ACPI_SIG_DSDT))
    482             {
    483                 AslGbl_ReferenceOptimizationFlag = FALSE;
    484             }
    485         }
    486     }
    487 
    488     AslGbl_FirstLevelInsertionNode = Next;
    489 }
    490 
    491 
    492 /*******************************************************************************
    493  *
    494  * FUNCTION:    TrDoSwitch
    495  *
    496  * PARAMETERS:  StartNode        - Parse node for SWITCH
    497  *
    498  * RETURN:      None
    499  *
    500  * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is
    501  *              no actual AML opcode for SWITCH -- it must be simulated.
    502  *
    503  ******************************************************************************/
    504 
    505 static void
    506 TrDoSwitch (
    507     ACPI_PARSE_OBJECT       *StartNode)
    508 {
    509     ACPI_PARSE_OBJECT       *Next;
    510     ACPI_PARSE_OBJECT       *CaseOp = NULL;
    511     ACPI_PARSE_OBJECT       *CaseBlock = NULL;
    512     ACPI_PARSE_OBJECT       *DefaultOp = NULL;
    513     ACPI_PARSE_OBJECT       *CurrentParentNode;
    514     ACPI_PARSE_OBJECT       *Conditional = NULL;
    515     ACPI_PARSE_OBJECT       *Predicate;
    516     ACPI_PARSE_OBJECT       *Peer;
    517     ACPI_PARSE_OBJECT       *NewOp;
    518     ACPI_PARSE_OBJECT       *NewOp2;
    519     ACPI_PARSE_OBJECT       *MethodOp;
    520     ACPI_PARSE_OBJECT       *StoreOp;
    521     ACPI_PARSE_OBJECT       *BreakOp;
    522     ACPI_PARSE_OBJECT       *BufferOp;
    523     char                    *PredicateValueName;
    524     UINT16                  Index;
    525     UINT32                  Btype;
    526 
    527 
    528     /* Start node is the Switch() node */
    529 
    530     CurrentParentNode  = StartNode;
    531 
    532     /* Create a new temp name of the form _T_x */
    533 
    534     PredicateValueName = TrAmlGetNextTempName (StartNode, &AslGbl_TempCount);
    535     if (!PredicateValueName)
    536     {
    537         return;
    538     }
    539 
    540     /* First child is the Switch() predicate */
    541 
    542     Next = StartNode->Asl.Child;
    543 
    544     /*
    545      * Examine the return type of the Switch Value -
    546      * must be Integer/Buffer/String
    547      */
    548     Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE);
    549     Btype = AslKeywordMapping[Index].AcpiBtype;
    550     if ((Btype != ACPI_BTYPE_INTEGER) &&
    551         (Btype != ACPI_BTYPE_STRING)  &&
    552         (Btype != ACPI_BTYPE_BUFFER))
    553     {
    554         AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL);
    555         Btype = ACPI_BTYPE_INTEGER;
    556     }
    557 
    558     /* CASE statements start at next child */
    559 
    560     Peer = Next->Asl.Next;
    561     while (Peer)
    562     {
    563         Next = Peer;
    564         Peer = Next->Asl.Next;
    565 
    566         if (Next->Asl.ParseOpcode == PARSEOP_CASE)
    567         {
    568             TrCheckForDuplicateCase (Next, Next->Asl.Child);
    569 
    570             if (CaseOp)
    571             {
    572                 /* Add an ELSE to complete the previous CASE */
    573 
    574                 NewOp = TrCreateLeafOp (PARSEOP_ELSE);
    575                 NewOp->Asl.Parent = Conditional->Asl.Parent;
    576                 TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent);
    577 
    578                 /* Link ELSE node as a peer to the previous IF */
    579 
    580                 TrAmlInsertPeer (Conditional, NewOp);
    581                 CurrentParentNode = NewOp;
    582             }
    583 
    584             CaseOp = Next;
    585             Conditional = CaseOp;
    586             CaseBlock = CaseOp->Asl.Child->Asl.Next;
    587             Conditional->Asl.Child->Asl.Next = NULL;
    588             Predicate = CaseOp->Asl.Child;
    589 
    590             if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
    591                 (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
    592             {
    593                 /*
    594                  * Convert the package declaration to this form:
    595                  *
    596                  * If (LNotEqual (Match (Package(<size>){<data>},
    597                  *                       MEQ, _T_x, MTR, Zero, Zero), Ones))
    598                  */
    599                 NewOp2              = TrCreateLeafOp (PARSEOP_MATCHTYPE_MEQ);
    600                 Predicate->Asl.Next = NewOp2;
    601                 TrAmlInitLineNumbers (NewOp2, Conditional);
    602 
    603                 NewOp               = NewOp2;
    604                 NewOp2              = TrCreateValuedLeafOp (PARSEOP_NAMESTRING,
    605                                         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
    606                 NewOp->Asl.Next     = NewOp2;
    607                 TrAmlInitLineNumbers (NewOp2, Predicate);
    608 
    609                 NewOp               = NewOp2;
    610                 NewOp2              = TrCreateLeafOp (PARSEOP_MATCHTYPE_MTR);
    611                 NewOp->Asl.Next     = NewOp2;
    612                 TrAmlInitLineNumbers (NewOp2, Predicate);
    613 
    614                 NewOp               = NewOp2;
    615                 NewOp2              = TrCreateLeafOp (PARSEOP_ZERO);
    616                 NewOp->Asl.Next     = NewOp2;
    617                 TrAmlInitLineNumbers (NewOp2, Predicate);
    618 
    619                 NewOp               = NewOp2;
    620                 NewOp2              = TrCreateLeafOp (PARSEOP_ZERO);
    621                 NewOp->Asl.Next     = NewOp2;
    622                 TrAmlInitLineNumbers (NewOp2, Predicate);
    623 
    624                 NewOp2              = TrCreateLeafOp (PARSEOP_MATCH);
    625                 NewOp2->Asl.Child   = Predicate;  /* PARSEOP_PACKAGE */
    626                 TrAmlInitLineNumbers (NewOp2, Conditional);
    627                 TrAmlSetSubtreeParent (Predicate, NewOp2);
    628 
    629                 NewOp               = NewOp2;
    630                 NewOp2              = TrCreateLeafOp (PARSEOP_ONES);
    631                 NewOp->Asl.Next     = NewOp2;
    632                 TrAmlInitLineNumbers (NewOp2, Conditional);
    633 
    634                 NewOp2              = TrCreateLeafOp (PARSEOP_LEQUAL);
    635                 NewOp2->Asl.Child   = NewOp;
    636                 NewOp->Asl.Parent   = NewOp2;
    637                 TrAmlInitLineNumbers (NewOp2, Conditional);
    638                 TrAmlSetSubtreeParent (NewOp, NewOp2);
    639 
    640                 NewOp               = NewOp2;
    641                 NewOp2              = TrCreateLeafOp (PARSEOP_LNOT);
    642                 NewOp2->Asl.Child   = NewOp;
    643                 NewOp2->Asl.Parent  = Conditional;
    644                 NewOp->Asl.Parent   = NewOp2;
    645                 TrAmlInitLineNumbers (NewOp2, Conditional);
    646 
    647                 Conditional->Asl.Child = NewOp2;
    648                 NewOp2->Asl.Next = CaseBlock;
    649             }
    650             else
    651             {
    652                 /*
    653                  * Integer and Buffer case.
    654                  *
    655                  * Change CaseOp() to:  If (LEqual (SwitchValue, CaseValue)) {...}
    656                  * Note: SwitchValue is first to allow the CaseValue to be implicitly
    657                  * converted to the type of SwitchValue if necessary.
    658                  *
    659                  * CaseOp->Child is the case value
    660                  * CaseOp->Child->Peer is the beginning of the case block
    661                  */
    662                 NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESTRING,
    663                     (UINT64) ACPI_TO_INTEGER (PredicateValueName));
    664                 NewOp->Asl.Next = Predicate;
    665                 TrAmlInitLineNumbers (NewOp, Predicate);
    666 
    667                 NewOp2              = TrCreateLeafOp (PARSEOP_LEQUAL);
    668                 NewOp2->Asl.Parent  = Conditional;
    669                 NewOp2->Asl.Child   = NewOp;
    670                 TrAmlInitLineNumbers (NewOp2, Conditional);
    671 
    672                 TrAmlSetSubtreeParent (NewOp, NewOp2);
    673 
    674                 Predicate           = NewOp2;
    675                 Predicate->Asl.Next = CaseBlock;
    676 
    677                 TrAmlSetSubtreeParent (Predicate, Conditional);
    678                 Conditional->Asl.Child = Predicate;
    679             }
    680 
    681             /* Reinitialize the CASE node to an IF node */
    682 
    683             TrAmlInitNode (Conditional, PARSEOP_IF);
    684 
    685             /*
    686              * The first CASE(IF) is not nested under an ELSE.
    687              * All other CASEs are children of a parent ELSE.
    688              */
    689             if (CurrentParentNode == StartNode)
    690             {
    691                 Conditional->Asl.Next = NULL;
    692             }
    693             else
    694             {
    695                 /*
    696                  * The IF is a child of previous IF/ELSE. It
    697                  * is therefore without peer.
    698                  */
    699                 CurrentParentNode->Asl.Child = Conditional;
    700                 Conditional->Asl.Parent      = CurrentParentNode;
    701                 Conditional->Asl.Next        = NULL;
    702             }
    703         }
    704         else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT)
    705         {
    706             if (DefaultOp)
    707             {
    708                 /*
    709                  * More than one Default
    710                  * (Parser does not catch this, must check here)
    711                  */
    712                 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL);
    713             }
    714             else
    715             {
    716                 /* Save the DEFAULT node for later, after CASEs */
    717 
    718                 DefaultOp = Next;
    719             }
    720         }
    721         else
    722         {
    723             /* Unknown peer opcode */
    724 
    725             AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n",
    726                 Next->Asl.ParseOpName, Next->Asl.ParseOpcode);
    727         }
    728     }
    729 
    730     /* Add the default case at the end of the if/else construct */
    731 
    732     if (DefaultOp)
    733     {
    734         /* If no CASE statements, this is an error - see below */
    735 
    736         if (CaseOp)
    737         {
    738             /* Convert the DEFAULT node to an ELSE */
    739 
    740             TrAmlInitNode (DefaultOp, PARSEOP_ELSE);
    741             DefaultOp->Asl.Parent = Conditional->Asl.Parent;
    742 
    743             /* Link ELSE node as a peer to the previous IF */
    744 
    745             TrAmlInsertPeer (Conditional, DefaultOp);
    746         }
    747     }
    748 
    749     if (!CaseOp)
    750     {
    751         AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL);
    752     }
    753 
    754 
    755     /*
    756      * Create a Name(_T_x, ...) statement. This statement must appear at the
    757      * method level, in case a loop surrounds the switch statement and could
    758      * cause the name to be created twice (error).
    759      */
    760 
    761     /* Create the Name node */
    762 
    763     Predicate = StartNode->Asl.Child;
    764     NewOp = TrCreateLeafOp (PARSEOP_NAME);
    765     TrAmlInitLineNumbers (NewOp, StartNode);
    766 
    767     /* Find the parent method */
    768 
    769     Next = StartNode;
    770     while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) &&
    771            (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK))
    772     {
    773         Next = Next->Asl.Parent;
    774     }
    775     MethodOp = Next;
    776 
    777     NewOp->Asl.CompileFlags |= OP_COMPILER_EMITTED;
    778     NewOp->Asl.Parent = Next;
    779 
    780     /* Insert name after the method name and arguments */
    781 
    782     Next = Next->Asl.Child; /* Name */
    783     Next = Next->Asl.Next;  /* NumArgs */
    784     Next = Next->Asl.Next;  /* SerializeRule */
    785 
    786     /*
    787      * If method is not Serialized, we must make is so, because of the way
    788      * that Switch() must be implemented -- we cannot allow multiple threads
    789      * to execute this method concurrently since we need to create local
    790      * temporary name(s).
    791      */
    792     if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL)
    793     {
    794         AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp,
    795             "Due to use of Switch operator");
    796         Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL;
    797     }
    798 
    799     Next = Next->Asl.Next;  /* SyncLevel */
    800     Next = Next->Asl.Next;  /* ReturnType */
    801     Next = Next->Asl.Next;  /* ParameterTypes */
    802 
    803     TrAmlInsertPeer (Next, NewOp);
    804     TrAmlInitLineNumbers (NewOp, Next);
    805 
    806     /* Create the NameSeg child for the Name node */
    807 
    808     NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESEG,
    809         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
    810     TrAmlInitLineNumbers (NewOp2, NewOp);
    811     NewOp2->Asl.CompileFlags |= OP_IS_NAME_DECLARATION;
    812     NewOp->Asl.Child  = NewOp2;
    813 
    814     /* Create the initial value for the Name. Btype was already validated above */
    815 
    816     switch (Btype)
    817     {
    818     case ACPI_BTYPE_INTEGER:
    819 
    820         NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_ZERO,
    821             (UINT64) 0);
    822         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
    823         break;
    824 
    825     case ACPI_BTYPE_STRING:
    826 
    827         NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_STRING_LITERAL,
    828             (UINT64) ACPI_TO_INTEGER (""));
    829         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
    830         break;
    831 
    832     case ACPI_BTYPE_BUFFER:
    833 
    834         (void) TrLinkPeerOp (NewOp2, TrCreateValuedLeafOp (PARSEOP_BUFFER,
    835             (UINT64) 0));
    836         Next = NewOp2->Asl.Next;
    837         TrAmlInitLineNumbers (Next, NewOp2);
    838 
    839         (void) TrLinkOpChildren (Next, 1, TrCreateValuedLeafOp (PARSEOP_ZERO,
    840             (UINT64) 1));
    841         TrAmlInitLineNumbers (Next->Asl.Child, Next);
    842 
    843         BufferOp = TrCreateValuedLeafOp (PARSEOP_DEFAULT_ARG, (UINT64) 0);
    844         TrAmlInitLineNumbers (BufferOp, Next->Asl.Child);
    845         (void) TrLinkPeerOp (Next->Asl.Child, BufferOp);
    846 
    847         TrAmlSetSubtreeParent (Next->Asl.Child, Next);
    848         break;
    849 
    850     default:
    851 
    852         break;
    853     }
    854 
    855     TrAmlSetSubtreeParent (NewOp2, NewOp);
    856 
    857     /*
    858      * Transform the Switch() into a While(One)-Break node.
    859      * And create a Store() node which will be used to save the
    860      * Switch() value. The store is of the form: Store (Value, _T_x)
    861      * where _T_x is the temp variable.
    862      */
    863     TrAmlInitNode (StartNode, PARSEOP_WHILE);
    864     NewOp = TrCreateLeafOp (PARSEOP_ONE);
    865     TrAmlInitLineNumbers (NewOp, StartNode);
    866     NewOp->Asl.Next = Predicate->Asl.Next;
    867     NewOp->Asl.Parent = StartNode;
    868     StartNode->Asl.Child = NewOp;
    869 
    870     /* Create a Store() node */
    871 
    872     StoreOp = TrCreateLeafOp (PARSEOP_STORE);
    873     TrAmlInitLineNumbers (StoreOp, NewOp);
    874     StoreOp->Asl.Parent = StartNode;
    875     TrAmlInsertPeer (NewOp, StoreOp);
    876 
    877     /* Complete the Store subtree */
    878 
    879     StoreOp->Asl.Child = Predicate;
    880     Predicate->Asl.Parent = StoreOp;
    881 
    882     NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESEG,
    883         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
    884     TrAmlInitLineNumbers (NewOp, StoreOp);
    885     NewOp->Asl.Parent    = StoreOp;
    886     Predicate->Asl.Next  = NewOp;
    887 
    888     /* Create a Break() node and insert it into the end of While() */
    889 
    890     Conditional = StartNode->Asl.Child;
    891     while (Conditional->Asl.Next)
    892     {
    893         Conditional = Conditional->Asl.Next;
    894     }
    895 
    896     BreakOp = TrCreateLeafOp (PARSEOP_BREAK);
    897     TrAmlInitLineNumbers (BreakOp, NewOp);
    898     BreakOp->Asl.Parent = StartNode;
    899     TrAmlInsertPeer (Conditional, BreakOp);
    900 }
    901 
    902 
    903 /*******************************************************************************
    904  *
    905  * FUNCTION:    TrCheckForDuplicateCase
    906  *
    907  * PARAMETERS:  CaseOp          - Parse node for first Case statement in list
    908  *              Predicate1      - Case value for the input CaseOp
    909  *
    910  * RETURN:      None
    911  *
    912  * DESCRIPTION: Check for duplicate case values. Currently, only handles
    913  *              Integers, Strings and Buffers. No support for Package objects.
    914  *
    915  ******************************************************************************/
    916 
    917 static void
    918 TrCheckForDuplicateCase (
    919     ACPI_PARSE_OBJECT       *CaseOp,
    920     ACPI_PARSE_OBJECT       *Predicate1)
    921 {
    922     ACPI_PARSE_OBJECT       *Next;
    923     ACPI_PARSE_OBJECT       *Predicate2;
    924 
    925 
    926     /* Walk the list of CASE opcodes */
    927 
    928     Next = CaseOp->Asl.Next;
    929     while (Next)
    930     {
    931         if (Next->Asl.ParseOpcode == PARSEOP_CASE)
    932         {
    933             /* Emit error only once */
    934 
    935             if (Next->Asl.CompileFlags & OP_IS_DUPLICATE)
    936             {
    937                 goto NextCase;
    938             }
    939 
    940             /* Check for a duplicate plain integer */
    941 
    942             Predicate2 = Next->Asl.Child;
    943             if ((Predicate1->Asl.ParseOpcode == PARSEOP_INTEGER) &&
    944                 (Predicate2->Asl.ParseOpcode == PARSEOP_INTEGER))
    945             {
    946                 if (Predicate1->Asl.Value.Integer == Predicate2->Asl.Value.Integer)
    947                 {
    948                     goto FoundDuplicate;
    949                 }
    950             }
    951 
    952             /* Check for pairs of the constants ZERO, ONE, ONES */
    953 
    954             else if (((Predicate1->Asl.ParseOpcode == PARSEOP_ZERO) &&
    955                 (Predicate2->Asl.ParseOpcode == PARSEOP_ZERO)) ||
    956                 ((Predicate1->Asl.ParseOpcode == PARSEOP_ONE) &&
    957                 (Predicate2->Asl.ParseOpcode == PARSEOP_ONE)) ||
    958                 ((Predicate1->Asl.ParseOpcode == PARSEOP_ONES) &&
    959                 (Predicate2->Asl.ParseOpcode == PARSEOP_ONES)))
    960             {
    961                 goto FoundDuplicate;
    962             }
    963 
    964             /* Check for a duplicate string constant (literal) */
    965 
    966             else if ((Predicate1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) &&
    967                 (Predicate2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL))
    968             {
    969                 if (!strcmp (Predicate1->Asl.Value.String,
    970                         Predicate2->Asl.Value.String))
    971                 {
    972                     goto FoundDuplicate;
    973                 }
    974             }
    975 
    976             /* Check for a duplicate buffer constant */
    977 
    978             else if ((Predicate1->Asl.ParseOpcode == PARSEOP_BUFFER) &&
    979                 (Predicate2->Asl.ParseOpcode == PARSEOP_BUFFER))
    980             {
    981                 if (TrCheckForBufferMatch (Predicate1->Asl.Child,
    982                         Predicate2->Asl.Child))
    983                 {
    984                     goto FoundDuplicate;
    985                 }
    986             }
    987         }
    988         goto NextCase;
    989 
    990 FoundDuplicate:
    991         /* Emit error message only once */
    992 
    993         Next->Asl.CompileFlags |= OP_IS_DUPLICATE;
    994 
    995         AslDualParseOpError (ASL_ERROR, ASL_MSG_DUPLICATE_CASE, Next,
    996             Next->Asl.Value.String, ASL_MSG_CASE_FOUND_HERE, CaseOp,
    997             CaseOp->Asl.ExternalName);
    998 
    999 NextCase:
   1000         Next = Next->Asl.Next;
   1001     }
   1002 }
   1003 
   1004 
   1005 /*******************************************************************************
   1006  *
   1007  * FUNCTION:    TrCheckForBufferMatch
   1008  *
   1009  * PARAMETERS:  Next1       - Parse node for first opcode in first buffer list
   1010  *                              (The DEFAULT_ARG or INTEGER node)
   1011  *              Next2       - Parse node for first opcode in second buffer list
   1012  *                              (The DEFAULT_ARG or INTEGER node)
   1013  *
   1014  * RETURN:      TRUE if buffers match, FALSE otherwise
   1015  *
   1016  * DESCRIPTION: Check for duplicate Buffer case values.
   1017  *
   1018  ******************************************************************************/
   1019 
   1020 static BOOLEAN
   1021 TrCheckForBufferMatch (
   1022     ACPI_PARSE_OBJECT       *NextOp1,
   1023     ACPI_PARSE_OBJECT       *NextOp2)
   1024 {
   1025 
   1026     if (NextOp1->Asl.Value.Integer != NextOp2->Asl.Value.Integer)
   1027     {
   1028         return (FALSE);
   1029     }
   1030 
   1031     /* Start at the BYTECONST initializer node list */
   1032 
   1033     NextOp1 = NextOp1->Asl.Next;
   1034     NextOp2 = NextOp2->Asl.Next;
   1035 
   1036     /*
   1037      * Walk both lists until either a mismatch is found, or one or more
   1038      * end-of-lists are found
   1039      */
   1040     while (NextOp1 && NextOp2)
   1041     {
   1042         if ((NextOp1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) &&
   1043             (NextOp2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL))
   1044         {
   1045             if (!strcmp (NextOp1->Asl.Value.String, NextOp2->Asl.Value.String))
   1046             {
   1047                 return (TRUE);
   1048             }
   1049             else
   1050             {
   1051                 return (FALSE);
   1052             }
   1053         }
   1054         if ((UINT8) NextOp1->Asl.Value.Integer != (UINT8) NextOp2->Asl.Value.Integer)
   1055         {
   1056             return (FALSE);
   1057         }
   1058 
   1059         NextOp1 = NextOp1->Asl.Next;
   1060         NextOp2 = NextOp2->Asl.Next;
   1061     }
   1062 
   1063     /* Not a match if one of the lists is not at end-of-list */
   1064 
   1065     if (NextOp1 || NextOp2)
   1066     {
   1067         return (FALSE);
   1068     }
   1069 
   1070     /* Otherwise, the buffers match */
   1071 
   1072     return (TRUE);
   1073 }
   1074