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