Home | History | Annotate | Line # | Download | only in compiler
aslexternal.c revision 1.1
      1 /******************************************************************************
      2  *
      3  * Module Name: aslexternal - ASL External opcode compiler support
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2016, 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 "acparser.h"
     47 #include "amlcode.h"
     48 #include "acnamesp.h"
     49 
     50 
     51 #define _COMPONENT          ACPI_COMPILER
     52         ACPI_MODULE_NAME    ("aslexternal")
     53 
     54 
     55 /* Local prototypes */
     56 
     57 static void
     58 ExInsertArgCount (
     59     ACPI_PARSE_OBJECT       *Op);
     60 
     61 static void
     62 ExMoveExternals (
     63     ACPI_PARSE_OBJECT       *DefinitionBlockOp);
     64 
     65 
     66 /*******************************************************************************
     67  *
     68  * FUNCTION:    ExDoExternal
     69  *
     70  * PARAMETERS:  Op                  - Current Parse node
     71  *
     72  * RETURN:      None
     73  *
     74  * DESCRIPTION: Add an External() definition to the global list. This list
     75  *              is used to generate External opcodes.
     76  *
     77  ******************************************************************************/
     78 
     79 void
     80 ExDoExternal (
     81     ACPI_PARSE_OBJECT       *Op)
     82 {
     83     ACPI_PARSE_OBJECT       *ListOp;
     84     ACPI_PARSE_OBJECT       *Prev;
     85     ACPI_PARSE_OBJECT       *Next;
     86     ACPI_PARSE_OBJECT       *ArgCountOp;
     87 
     88 
     89     ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next;
     90     ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
     91     ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
     92     ArgCountOp->Asl.Value.Integer = 0;
     93     UtSetParseOpName (ArgCountOp);
     94 
     95     /* Create new list node of arbitrary type */
     96 
     97     ListOp = TrAllocateNode (PARSEOP_DEFAULT_ARG);
     98 
     99     /* Store External node as child */
    100 
    101     ListOp->Asl.Child = Op;
    102     ListOp->Asl.Next = NULL;
    103 
    104     if (Gbl_ExternalsListHead)
    105     {
    106         /* Link new External to end of list */
    107 
    108         Prev = Gbl_ExternalsListHead;
    109         Next = Prev;
    110         while (Next)
    111         {
    112             Prev = Next;
    113             Next = Next->Asl.Next;
    114         }
    115 
    116         Prev->Asl.Next = ListOp;
    117     }
    118     else
    119     {
    120         Gbl_ExternalsListHead = ListOp;
    121     }
    122 }
    123 
    124 
    125 /*******************************************************************************
    126  *
    127  * FUNCTION:    ExInsertArgCount
    128  *
    129  * PARAMETERS:  Op              - Op for a method invocation
    130  *
    131  * RETURN:      None
    132  *
    133  * DESCRIPTION: Obtain the number of arguments for a control method -- from
    134  *              the actual invocation.
    135  *
    136  ******************************************************************************/
    137 
    138 static void
    139 ExInsertArgCount (
    140     ACPI_PARSE_OBJECT       *Op)
    141 {
    142     ACPI_PARSE_OBJECT       *Next;
    143     ACPI_PARSE_OBJECT       *NameOp;
    144     ACPI_PARSE_OBJECT       *Child;
    145     ACPI_PARSE_OBJECT       *ArgCountOp;
    146     char *                  ExternalName;
    147     char *                  CallName;
    148     UINT16                  ArgCount = 0;
    149     ACPI_STATUS             Status;
    150 
    151 
    152     CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
    153 
    154     Next = Gbl_ExternalsListHead;
    155     while (Next)
    156     {
    157         ArgCount = 0;
    158 
    159         /* Skip if External node already handled */
    160 
    161         if (Next->Asl.Child->Asl.CompileFlags & NODE_VISITED)
    162         {
    163             Next = Next->Asl.Next;
    164             continue;
    165         }
    166 
    167         NameOp = Next->Asl.Child->Asl.Child;
    168         ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
    169 
    170         if (strcmp (CallName, ExternalName))
    171         {
    172             ACPI_FREE (ExternalName);
    173             Next = Next->Asl.Next;
    174             continue;
    175         }
    176 
    177         Next->Asl.Child->Asl.CompileFlags |= NODE_VISITED;
    178 
    179         /*
    180          * Since we will reposition Externals to the Root, set Namepath
    181          * to the fully qualified name and recalculate the aml length
    182          */
    183         Status = UtInternalizeName (ExternalName,
    184             &NameOp->Asl.Value.String);
    185 
    186         ACPI_FREE (ExternalName);
    187         if (ACPI_FAILURE (Status))
    188         {
    189             AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
    190                 NULL, "- Could not Internalize External");
    191             break;
    192         }
    193 
    194         NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
    195 
    196         /* Get argument count */
    197 
    198         Child = Op->Asl.Child;
    199         while (Child)
    200         {
    201             ArgCount++;
    202             Child = Child->Asl.Next;
    203         }
    204 
    205         /* Setup ArgCount operand */
    206 
    207         ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
    208         ArgCountOp->Asl.Value.Integer = ArgCount;
    209         break;
    210     }
    211 
    212     ACPI_FREE (CallName);
    213 }
    214 
    215 
    216 /*******************************************************************************
    217  *
    218  * FUNCTION:    ExAmlExternalWalkBegin
    219  *
    220  * PARAMETERS:  ASL_WALK_CALLBACK
    221  *
    222  * RETURN:      None
    223  *
    224  * DESCRIPTION: Parse tree walk to create external opcode list for methods.
    225  *
    226  ******************************************************************************/
    227 
    228 ACPI_STATUS
    229 ExAmlExternalWalkBegin (
    230     ACPI_PARSE_OBJECT       *Op,
    231     UINT32                  Level,
    232     void                    *Context)
    233 {
    234 
    235     /* External list head saved in the definition block op */
    236 
    237     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
    238     {
    239         Gbl_ExternalsListHead = Op->Asl.Value.Arg;
    240     }
    241 
    242     if (!Gbl_ExternalsListHead)
    243     {
    244         return (AE_OK);
    245     }
    246 
    247     if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
    248     {
    249         return (AE_OK);
    250     }
    251 
    252     /*
    253      * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
    254      * by XfNamespaceLocateBegin(). Ignore these.
    255      */
    256     if (Op->Asl.Parent &&
    257         Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
    258     {
    259         return (AE_OK);
    260     }
    261 
    262     ExInsertArgCount (Op);
    263     return (AE_OK);
    264 }
    265 
    266 
    267 /*******************************************************************************
    268  *
    269  * FUNCTION:    ExAmlExternalWalkEnd
    270  *
    271  * PARAMETERS:  ASL_WALK_CALLBACK
    272  *
    273  * RETURN:      None
    274  *
    275  * DESCRIPTION: Parse tree walk to create external opcode list for methods.
    276  *              Here, we just want to catch the case where a definition block
    277  *              has been completed. Then we move all of the externals into
    278  *              a single block in the parse tree and thus the AML code.
    279  *
    280  ******************************************************************************/
    281 
    282 ACPI_STATUS
    283 ExAmlExternalWalkEnd (
    284     ACPI_PARSE_OBJECT       *Op,
    285     UINT32                  Level,
    286     void                    *Context)
    287 {
    288 
    289     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
    290     {
    291         /*
    292          * Process any existing external list. (Support for
    293          * multiple definition blocks in a single file/compile)
    294          */
    295         ExMoveExternals (Op);
    296         Gbl_ExternalsListHead = NULL;
    297     }
    298 
    299     return (AE_OK);
    300 }
    301 
    302 
    303 /*******************************************************************************
    304  *
    305  * FUNCTION:    ExMoveExternals
    306  *
    307  * PARAMETERS:  DefinitionBlockOp       - Op for current definition block
    308  *
    309  * RETURN:      None
    310  *
    311  * DESCRIPTION: Move all externals present in the source file into a single
    312  *              block of AML code, surrounded by an "If (0)" to prevent
    313  *              AML interpreters from attempting to execute the External
    314  *              opcodes.
    315  *
    316  ******************************************************************************/
    317 
    318 static void
    319 ExMoveExternals (
    320     ACPI_PARSE_OBJECT       *DefinitionBlockOp)
    321 {
    322     ACPI_PARSE_OBJECT       *ParentOp;
    323     ACPI_PARSE_OBJECT       *ExternalOp;
    324     ACPI_PARSE_OBJECT       *PredicateOp;
    325     ACPI_PARSE_OBJECT       *NextOp;
    326     ACPI_PARSE_OBJECT       *Prev;
    327     ACPI_PARSE_OBJECT       *Next;
    328     ACPI_OBJECT_TYPE        ObjType;
    329     UINT32                  i;
    330 
    331 
    332     if (!Gbl_ExternalsListHead)
    333     {
    334         return;
    335     }
    336 
    337     /* Remove the External nodes from the tree */
    338 
    339     NextOp = Gbl_ExternalsListHead;
    340     while (NextOp)
    341     {
    342         /*
    343          * The External is stored in child pointer of each node in the
    344          * list
    345          */
    346         ExternalOp = NextOp->Asl.Child;
    347 
    348         /* Set line numbers (for listings, etc.) */
    349 
    350         ExternalOp->Asl.LineNumber = 0;
    351         ExternalOp->Asl.LogicalLineNumber = 0;
    352 
    353         Next = ExternalOp->Asl.Child;
    354         Next->Asl.LineNumber = 0;
    355         Next->Asl.LogicalLineNumber = 0;
    356 
    357         Next = Next->Asl.Next;
    358         Next->Asl.LineNumber = 0;
    359         Next->Asl.LogicalLineNumber = 0;
    360 
    361         Next = Next->Asl.Next;
    362         Next->Asl.LineNumber = 0;
    363         Next->Asl.LogicalLineNumber = 0;
    364 
    365         Next = Next->Asl.Next;
    366         Next->Asl.LineNumber = 0;
    367         Next->Asl.LogicalLineNumber = 0;
    368 
    369         ParentOp = ExternalOp->Asl.Parent;
    370         Prev = Next = ParentOp->Asl.Child;
    371 
    372         /* Now find the External node's position in parse tree */
    373 
    374         while (Next != ExternalOp)
    375         {
    376             Prev = Next;
    377             Next = Next->Asl.Next;
    378         }
    379 
    380         /* Remove the External from the parse tree */
    381 
    382         if (Prev == ExternalOp)
    383         {
    384             /* External was the first child node */
    385 
    386             ParentOp->Asl.Child = ExternalOp->Asl.Next;
    387         }
    388 
    389         Prev->Asl.Next = ExternalOp->Asl.Next;
    390         ExternalOp->Asl.Next = NULL;
    391         ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
    392 
    393         /* Point the External to the next in the list */
    394 
    395         if (NextOp->Asl.Next)
    396         {
    397             ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
    398         }
    399 
    400         NextOp = NextOp->Asl.Next;
    401     }
    402 
    403     /*
    404      * Loop again to remove MethodObj Externals for which
    405      * a MethodCall was not found (dead external reference)
    406      */
    407     Prev = Gbl_ExternalsListHead->Asl.Child;
    408     Next = Prev;
    409     while (Next)
    410     {
    411         ObjType = (ACPI_OBJECT_TYPE)
    412             Next->Asl.Child->Asl.Next->Asl.Value.Integer;
    413 
    414         if (ObjType == ACPI_TYPE_METHOD &&
    415             !(Next->Asl.CompileFlags & NODE_VISITED))
    416         {
    417             if (Next == Prev)
    418             {
    419                 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
    420                 Next->Asl.Next = NULL;
    421                 Prev = Gbl_ExternalsListHead->Asl.Child;
    422                 Next = Prev;
    423                 continue;
    424             }
    425             else
    426             {
    427                 Prev->Asl.Next = Next->Asl.Next;
    428                 Next->Asl.Next = NULL;
    429                 Next = Prev->Asl.Next;
    430                 continue;
    431             }
    432         }
    433 
    434         Prev = Next;
    435         Next = Next->Asl.Next;
    436     }
    437 
    438     /* If list is now empty, don't bother to make If (0) block */
    439 
    440     if (!Gbl_ExternalsListHead->Asl.Child)
    441     {
    442         return;
    443     }
    444 
    445     /* Convert Gbl_ExternalsListHead parent to If(). */
    446 
    447     Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
    448     Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
    449     Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
    450     UtSetParseOpName (Gbl_ExternalsListHead);
    451 
    452     /* Create a Zero op for the If predicate */
    453 
    454     PredicateOp = TrAllocateNode (PARSEOP_ZERO);
    455     PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
    456 
    457     PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
    458     PredicateOp->Asl.Child = NULL;
    459     PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
    460     Gbl_ExternalsListHead->Asl.Child = PredicateOp;
    461 
    462     /* Set line numbers (for listings, etc.) */
    463 
    464     Gbl_ExternalsListHead->Asl.LineNumber = 0;
    465     Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
    466 
    467     PredicateOp->Asl.LineNumber = 0;
    468     PredicateOp->Asl.LogicalLineNumber = 0;
    469 
    470     /* Insert block back in the list */
    471 
    472     Prev = DefinitionBlockOp->Asl.Child;
    473     Next = Prev;
    474 
    475     /* Find last default arg */
    476 
    477     for (i = 0; i < 6; i++)
    478     {
    479         Prev = Next;
    480         Next = Prev->Asl.Next;
    481     }
    482 
    483     if (Next)
    484     {
    485         /* Definition Block is not empty */
    486 
    487         Gbl_ExternalsListHead->Asl.Next = Next;
    488     }
    489     else
    490     {
    491         /* Definition Block is empty. */
    492 
    493         Gbl_ExternalsListHead->Asl.Next = NULL;
    494     }
    495 
    496     Prev->Asl.Next = Gbl_ExternalsListHead;
    497     Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
    498 }
    499