Home | History | Annotate | Line # | Download | only in compiler
aslexternal.c revision 1.1.1.2
      1 /******************************************************************************
      2  *
      3  * Module Name: aslexternal - ASL External opcode compiler support
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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     char                    *ExternalName;
    329     ACPI_OBJECT_TYPE        ObjType;
    330     UINT32                  i;
    331 
    332 
    333     if (!Gbl_ExternalsListHead)
    334     {
    335         return;
    336     }
    337 
    338     /* Remove the External nodes from the tree */
    339 
    340     NextOp = Gbl_ExternalsListHead;
    341     while (NextOp)
    342     {
    343         /*
    344          * The External is stored in child pointer of each node in the
    345          * list
    346          */
    347         ExternalOp = NextOp->Asl.Child;
    348 
    349         /* Get/set the fully qualified name */
    350 
    351         ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE);
    352         ExternalOp->Asl.ExternalName = ExternalName;
    353         ExternalOp->Asl.Namepath = ExternalName;
    354 
    355         /* Set line numbers (for listings, etc.) */
    356 
    357         ExternalOp->Asl.LineNumber = 0;
    358         ExternalOp->Asl.LogicalLineNumber = 0;
    359 
    360         Next = ExternalOp->Asl.Child;
    361         Next->Asl.LineNumber = 0;
    362         Next->Asl.LogicalLineNumber = 0;
    363 
    364         if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG)
    365         {
    366             Next->Asl.ParseOpcode = PARSEOP_NAMESTRING;
    367         }
    368         Next->Asl.ExternalName = ExternalName;
    369         UtInternalizeName (ExternalName, &Next->Asl.Value.String);
    370         Next->Asl.AmlLength = strlen (Next->Asl.Value.String);
    371 
    372         Next = Next->Asl.Next;
    373         Next->Asl.LineNumber = 0;
    374         Next->Asl.LogicalLineNumber = 0;
    375 
    376         Next = Next->Asl.Next;
    377         Next->Asl.LineNumber = 0;
    378         Next->Asl.LogicalLineNumber = 0;
    379 
    380         Next = Next->Asl.Next;
    381         Next->Asl.LineNumber = 0;
    382         Next->Asl.LogicalLineNumber = 0;
    383 
    384         ParentOp = ExternalOp->Asl.Parent;
    385         Prev = Next = ParentOp->Asl.Child;
    386 
    387         /* Now find the External node's position in parse tree */
    388 
    389         while (Next != ExternalOp)
    390         {
    391             Prev = Next;
    392             Next = Next->Asl.Next;
    393         }
    394 
    395         /* Remove the External from the parse tree */
    396 
    397         if (Prev == ExternalOp)
    398         {
    399             /* External was the first child node */
    400 
    401             ParentOp->Asl.Child = ExternalOp->Asl.Next;
    402         }
    403 
    404         Prev->Asl.Next = ExternalOp->Asl.Next;
    405         ExternalOp->Asl.Next = NULL;
    406         ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
    407 
    408         /* Point the External to the next in the list */
    409 
    410         if (NextOp->Asl.Next)
    411         {
    412             ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
    413         }
    414 
    415         NextOp = NextOp->Asl.Next;
    416     }
    417 
    418     /*
    419      * Loop again to remove MethodObj Externals for which
    420      * a MethodCall was not found (dead external reference)
    421      */
    422     Prev = Gbl_ExternalsListHead->Asl.Child;
    423     Next = Prev;
    424     while (Next)
    425     {
    426         ObjType = (ACPI_OBJECT_TYPE)
    427             Next->Asl.Child->Asl.Next->Asl.Value.Integer;
    428 
    429         if (ObjType == ACPI_TYPE_METHOD &&
    430             !(Next->Asl.CompileFlags & NODE_VISITED))
    431         {
    432             if (Next == Prev)
    433             {
    434                 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
    435                 Next->Asl.Next = NULL;
    436                 Prev = Gbl_ExternalsListHead->Asl.Child;
    437                 Next = Prev;
    438                 continue;
    439             }
    440             else
    441             {
    442                 Prev->Asl.Next = Next->Asl.Next;
    443                 Next->Asl.Next = NULL;
    444                 Next = Prev->Asl.Next;
    445                 continue;
    446             }
    447         }
    448 
    449         Prev = Next;
    450         Next = Next->Asl.Next;
    451     }
    452 
    453     /* If list is now empty, don't bother to make If (0) block */
    454 
    455     if (!Gbl_ExternalsListHead->Asl.Child)
    456     {
    457         return;
    458     }
    459 
    460     /* Convert Gbl_ExternalsListHead parent to If(). */
    461 
    462     Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
    463     Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
    464     Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
    465     UtSetParseOpName (Gbl_ExternalsListHead);
    466 
    467     /* Create a Zero op for the If predicate */
    468 
    469     PredicateOp = TrAllocateNode (PARSEOP_ZERO);
    470     PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
    471 
    472     PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
    473     PredicateOp->Asl.Child = NULL;
    474     PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
    475     Gbl_ExternalsListHead->Asl.Child = PredicateOp;
    476 
    477     /* Set line numbers (for listings, etc.) */
    478 
    479     Gbl_ExternalsListHead->Asl.LineNumber = 0;
    480     Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
    481 
    482     PredicateOp->Asl.LineNumber = 0;
    483     PredicateOp->Asl.LogicalLineNumber = 0;
    484 
    485     /* Insert block back in the list */
    486 
    487     Prev = DefinitionBlockOp->Asl.Child;
    488     Next = Prev;
    489 
    490     /* Find last default arg */
    491 
    492     for (i = 0; i < 6; i++)
    493     {
    494         Prev = Next;
    495         Next = Prev->Asl.Next;
    496     }
    497 
    498     if (Next)
    499     {
    500         /* Definition Block is not empty */
    501 
    502         Gbl_ExternalsListHead->Asl.Next = Next;
    503     }
    504     else
    505     {
    506         /* Definition Block is empty. */
    507 
    508         Gbl_ExternalsListHead->Asl.Next = NULL;
    509     }
    510 
    511     Prev->Asl.Next = Gbl_ExternalsListHead;
    512     Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
    513 }
    514