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