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