Home | History | Annotate | Line # | Download | only in common
dmextern.c revision 1.1.1.2.8.2
      1 /******************************************************************************
      2  *
      3  * Module Name: dmextern - Support for External() ASL statements
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2011, 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 "acpi.h"
     45 #include "accommon.h"
     46 #include "amlcode.h"
     47 #include "acnamesp.h"
     48 #include "acdisasm.h"
     49 
     50 
     51 /*
     52  * This module is used for application-level code (iASL disassembler) only.
     53  *
     54  * It contains the code to create and emit any necessary External() ASL
     55  * statements for the module being disassembled.
     56  */
     57 #define _COMPONENT          ACPI_CA_DISASSEMBLER
     58         ACPI_MODULE_NAME    ("dmextern")
     59 
     60 
     61 /*
     62  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
     63  * ObjectTypeKeyword. Used to generate typed external declarations
     64  */
     65 static const char           *AcpiGbl_DmTypeNames[] =
     66 {
     67     /* 00 */ "",                    /* Type ANY */
     68     /* 01 */ ", IntObj",
     69     /* 02 */ ", StrObj",
     70     /* 03 */ ", BuffObj",
     71     /* 04 */ ", PkgObj",
     72     /* 05 */ ", FieldUnitObj",
     73     /* 06 */ ", DeviceObj",
     74     /* 07 */ ", EventObj",
     75     /* 08 */ ", MethodObj",
     76     /* 09 */ ", MutexObj",
     77     /* 10 */ ", OpRegionObj",
     78     /* 11 */ ", PowerResObj",
     79     /* 12 */ ", ProcessorObj",
     80     /* 13 */ ", ThermalZoneObj",
     81     /* 14 */ ", BuffFieldObj",
     82     /* 15 */ ", DDBHandleObj",
     83     /* 16 */ "",                    /* Debug object */
     84     /* 17 */ ", FieldUnitObj",
     85     /* 18 */ ", FieldUnitObj",
     86     /* 19 */ ", FieldUnitObj"
     87 };
     88 
     89 
     90 /* Local prototypes */
     91 
     92 static const char *
     93 AcpiDmGetObjectTypeName (
     94     ACPI_OBJECT_TYPE        Type);
     95 
     96 static char *
     97 AcpiDmNormalizeParentPrefix (
     98     ACPI_PARSE_OBJECT       *Op,
     99     char                    *Path);
    100 
    101 
    102 /*******************************************************************************
    103  *
    104  * FUNCTION:    AcpiDmGetObjectTypeName
    105  *
    106  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
    107  *
    108  * RETURN:      Pointer to a string
    109  *
    110  * DESCRIPTION: Map an object type to the ASL object type string.
    111  *
    112  ******************************************************************************/
    113 
    114 static const char *
    115 AcpiDmGetObjectTypeName (
    116     ACPI_OBJECT_TYPE        Type)
    117 {
    118 
    119     if (Type == ACPI_TYPE_LOCAL_SCOPE)
    120     {
    121         Type = ACPI_TYPE_DEVICE;
    122     }
    123 
    124     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
    125     {
    126         return ("");
    127     }
    128 
    129     return (AcpiGbl_DmTypeNames[Type]);
    130 }
    131 
    132 
    133 /*******************************************************************************
    134  *
    135  * FUNCTION:    AcpiDmNormalizeParentPrefix
    136  *
    137  * PARAMETERS:  Op                  - Parse op
    138  *              Path                - Path with parent prefix
    139  *
    140  * RETURN:      The full pathname to the object (from the namespace root)
    141  *
    142  * DESCRIPTION: Returns the full pathname of a path with parent prefix
    143  *              The caller must free the fullpath returned.
    144  *
    145  ******************************************************************************/
    146 
    147 static char *
    148 AcpiDmNormalizeParentPrefix (
    149     ACPI_PARSE_OBJECT       *Op,
    150     char                    *Path)
    151 {
    152     ACPI_NAMESPACE_NODE     *Node;
    153     char                    *Fullpath;
    154     char                    *ParentPath;
    155     ACPI_SIZE               Length;
    156 
    157 
    158     /* Search upwards in the parse tree until we reach a namespace node */
    159 
    160     while (Op)
    161     {
    162         if (Op->Common.Node)
    163         {
    164             break;
    165         }
    166 
    167         Op = Op->Common.Parent;
    168     }
    169 
    170     if (!Op)
    171     {
    172         return (NULL);
    173     }
    174 
    175     /*
    176      * Find the actual parent node for the reference:
    177      * Remove all carat prefixes from the input path.
    178      * There may be multiple parent prefixes (For example, ^^^M000)
    179      */
    180     Node = Op->Common.Node;
    181     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
    182     {
    183         Node = Node->Parent;
    184         Path++;
    185     }
    186 
    187     if (!Node)
    188     {
    189         return (NULL);
    190     }
    191 
    192     /* Get the full pathname for the parent node */
    193 
    194     ParentPath = AcpiNsGetExternalPathname (Node);
    195     if (!ParentPath)
    196     {
    197         return (NULL);
    198     }
    199 
    200     Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
    201     if (ParentPath[1])
    202     {
    203         /*
    204          * If ParentPath is not just a simple '\', increment the length
    205          * for the required dot separator (ParentPath.Path)
    206          */
    207         Length++;
    208     }
    209 
    210     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
    211     if (!Fullpath)
    212     {
    213         goto Cleanup;
    214     }
    215 
    216     /*
    217      * Concatenate parent fullpath and path. For example,
    218      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
    219      *
    220      * Copy the parent path
    221      */
    222     ACPI_STRCAT (Fullpath, ParentPath);
    223 
    224     /* Add dot separator (don't need dot if parent fullpath is a single "\") */
    225 
    226     if (ParentPath[1])
    227     {
    228         ACPI_STRCAT (Fullpath, ".");
    229     }
    230 
    231     /* Copy child path (carat parent prefix(es) were skipped above) */
    232 
    233     ACPI_STRCAT (Fullpath, Path);
    234 
    235 Cleanup:
    236     ACPI_FREE (ParentPath);
    237     return (Fullpath);
    238 }
    239 
    240 
    241 /*******************************************************************************
    242  *
    243  * FUNCTION:    AcpiDmAddToExternalFileList
    244  *
    245  * PARAMETERS:  PathList            - Single path or list separated by comma
    246  *
    247  * RETURN:      None
    248  *
    249  * DESCRIPTION: Add external files to global list
    250  *
    251  ******************************************************************************/
    252 
    253 ACPI_STATUS
    254 AcpiDmAddToExternalFileList (
    255     char                    *PathList)
    256 {
    257     ACPI_EXTERNAL_FILE      *ExternalFile;
    258     char                    *Path;
    259     char                    *TmpPath;
    260 
    261 
    262     if (!PathList)
    263     {
    264         return (AE_OK);
    265     }
    266 
    267     Path = strtok (PathList, ",");
    268 
    269     while (Path)
    270     {
    271         TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
    272         if (!TmpPath)
    273         {
    274             return (AE_NO_MEMORY);
    275         }
    276 
    277         ACPI_STRCPY (TmpPath, Path);
    278 
    279         ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
    280         if (!ExternalFile)
    281         {
    282             ACPI_FREE (TmpPath);
    283             return (AE_NO_MEMORY);
    284         }
    285 
    286         ExternalFile->Path = TmpPath;
    287 
    288         if (AcpiGbl_ExternalFileList)
    289         {
    290             ExternalFile->Next = AcpiGbl_ExternalFileList;
    291         }
    292 
    293         AcpiGbl_ExternalFileList = ExternalFile;
    294         Path = strtok (NULL, ",");
    295     }
    296 
    297     return (AE_OK);
    298 }
    299 
    300 
    301 /*******************************************************************************
    302  *
    303  * FUNCTION:    AcpiDmClearExternalFileList
    304  *
    305  * PARAMETERS:  None
    306  *
    307  * RETURN:      None
    308  *
    309  * DESCRIPTION: Clear the external file list
    310  *
    311  ******************************************************************************/
    312 
    313 void
    314 AcpiDmClearExternalFileList (
    315     void)
    316 {
    317     ACPI_EXTERNAL_FILE      *NextExternal;
    318 
    319 
    320     while (AcpiGbl_ExternalFileList)
    321     {
    322         NextExternal = AcpiGbl_ExternalFileList->Next;
    323         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
    324         ACPI_FREE (AcpiGbl_ExternalFileList);
    325         AcpiGbl_ExternalFileList = NextExternal;
    326     }
    327 }
    328 
    329 
    330 /*******************************************************************************
    331  *
    332  * FUNCTION:    AcpiDmAddToExternalList
    333  *
    334  * PARAMETERS:  Op                  - Current parser Op
    335  *              Path                - Internal (AML) path to the object
    336  *              Type                - ACPI object type to be added
    337  *              Value               - Arg count if adding a Method object
    338  *
    339  * RETURN:      None
    340  *
    341  * DESCRIPTION: Insert a new name into the global list of Externals which
    342  *              will in turn be later emitted as an External() declaration
    343  *              in the disassembled output.
    344  *
    345  ******************************************************************************/
    346 
    347 void
    348 AcpiDmAddToExternalList (
    349     ACPI_PARSE_OBJECT       *Op,
    350     char                    *Path,
    351     UINT8                   Type,
    352     UINT32                  Value)
    353 {
    354     char                    *ExternalPath;
    355     char                    *Fullpath = NULL;
    356     ACPI_EXTERNAL_LIST      *NewExternal;
    357     ACPI_EXTERNAL_LIST      *NextExternal;
    358     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
    359     ACPI_STATUS             Status;
    360 
    361 
    362     if (!Path)
    363     {
    364         return;
    365     }
    366 
    367     /* Externalize the ACPI path */
    368 
    369     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
    370                 NULL, &ExternalPath);
    371     if (ACPI_FAILURE (Status))
    372     {
    373         return;
    374     }
    375 
    376     /* Get the full pathname from root if "Path" has a parent prefix */
    377 
    378     if (*Path == (UINT8) AML_PARENT_PREFIX)
    379     {
    380         Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
    381         if (Fullpath)
    382         {
    383             /* Set new external path */
    384 
    385             ACPI_FREE (ExternalPath);
    386             ExternalPath = Fullpath;
    387         }
    388     }
    389 
    390     /* Check all existing externals to ensure no duplicates */
    391 
    392     NextExternal = AcpiGbl_ExternalList;
    393     while (NextExternal)
    394     {
    395         if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
    396         {
    397             /* Duplicate method, check that the Value (ArgCount) is the same */
    398 
    399             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
    400                 (NextExternal->Value != Value))
    401             {
    402                 ACPI_ERROR ((AE_INFO,
    403                     "Argument count mismatch for method %s %u %u",
    404                     NextExternal->Path, NextExternal->Value, Value));
    405             }
    406 
    407             /* Allow upgrade of type from ANY */
    408 
    409             else if (NextExternal->Type == ACPI_TYPE_ANY)
    410             {
    411                 NextExternal->Type = Type;
    412                 NextExternal->Value = Value;
    413             }
    414 
    415             ACPI_FREE (ExternalPath);
    416             return;
    417         }
    418 
    419         NextExternal = NextExternal->Next;
    420     }
    421 
    422     /* Allocate and init a new External() descriptor */
    423 
    424     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
    425     if (!NewExternal)
    426     {
    427         ACPI_FREE (ExternalPath);
    428         return;
    429     }
    430 
    431     NewExternal->Path = ExternalPath;
    432     NewExternal->Type = Type;
    433     NewExternal->Value = Value;
    434     NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
    435 
    436     /* Was the external path with parent prefix normalized to a fullpath? */
    437 
    438     if (Fullpath == ExternalPath)
    439     {
    440         /* Get new internal path */
    441 
    442         Status = AcpiNsInternalizeName (ExternalPath, &Path);
    443         if (ACPI_FAILURE (Status))
    444         {
    445             ACPI_FREE (ExternalPath);
    446             ACPI_FREE (NewExternal);
    447             return;
    448         }
    449 
    450         /* Set flag to indicate External->InternalPath need to be freed */
    451 
    452         NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
    453     }
    454 
    455     NewExternal->InternalPath = Path;
    456 
    457     /* Link the new descriptor into the global list, ordered by string length */
    458 
    459     NextExternal = AcpiGbl_ExternalList;
    460     while (NextExternal)
    461     {
    462         if (NewExternal->Length <= NextExternal->Length)
    463         {
    464             if (PrevExternal)
    465             {
    466                 PrevExternal->Next = NewExternal;
    467             }
    468             else
    469             {
    470                 AcpiGbl_ExternalList = NewExternal;
    471             }
    472 
    473             NewExternal->Next = NextExternal;
    474             return;
    475         }
    476 
    477         PrevExternal = NextExternal;
    478         NextExternal = NextExternal->Next;
    479     }
    480 
    481     if (PrevExternal)
    482     {
    483         PrevExternal->Next = NewExternal;
    484     }
    485     else
    486     {
    487         AcpiGbl_ExternalList = NewExternal;
    488     }
    489 }
    490 
    491 
    492 /*******************************************************************************
    493  *
    494  * FUNCTION:    AcpiDmAddExternalsToNamespace
    495  *
    496  * PARAMETERS:  None
    497  *
    498  * RETURN:      None
    499  *
    500  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
    501  *              "resolved".
    502  *
    503  ******************************************************************************/
    504 
    505 void
    506 AcpiDmAddExternalsToNamespace (
    507     void)
    508 {
    509     ACPI_STATUS             Status;
    510     ACPI_NAMESPACE_NODE     *Node;
    511     ACPI_OPERAND_OBJECT     *MethodDesc;
    512     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
    513 
    514 
    515     while (External)
    516     {
    517         /* Add the external name (object) into the namespace */
    518 
    519         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
    520                    ACPI_IMODE_LOAD_PASS1,
    521                    ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
    522                    NULL, &Node);
    523 
    524         if (ACPI_FAILURE (Status))
    525         {
    526             ACPI_EXCEPTION ((AE_INFO, Status,
    527                 "while adding external to namespace [%s]",
    528                 External->Path));
    529         }
    530         else if (External->Type == ACPI_TYPE_METHOD)
    531         {
    532             /* For methods, we need to save the argument count */
    533 
    534             MethodDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
    535             MethodDesc->Method.ParamCount = (UINT8) External->Value;
    536             Node->Object = MethodDesc;
    537         }
    538 
    539         External = External->Next;
    540     }
    541 }
    542 
    543 
    544 /*******************************************************************************
    545  *
    546  * FUNCTION:    AcpiDmGetExternalMethodCount
    547  *
    548  * PARAMETERS:  None
    549  *
    550  * RETURN:      The number of control method externals in the external list
    551  *
    552  * DESCRIPTION: Return the number of method externals that have been generated.
    553  *              If any control method externals have been found, we must
    554  *              re-parse the entire definition block with the new information
    555  *              (number of arguments for the methods.) This is limitation of
    556  *              AML, we don't know the number of arguments from the control
    557  *              method invocation itself.
    558  *
    559  ******************************************************************************/
    560 
    561 UINT32
    562 AcpiDmGetExternalMethodCount (
    563     void)
    564 {
    565     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
    566     UINT32                  Count = 0;
    567 
    568 
    569     while (External)
    570     {
    571         if (External->Type == ACPI_TYPE_METHOD)
    572         {
    573             Count++;
    574         }
    575 
    576         External = External->Next;
    577     }
    578 
    579     return (Count);
    580 }
    581 
    582 
    583 /*******************************************************************************
    584  *
    585  * FUNCTION:    AcpiDmClearExternalList
    586  *
    587  * PARAMETERS:  None
    588  *
    589  * RETURN:      None
    590  *
    591  * DESCRIPTION: Free the entire External info list
    592  *
    593  ******************************************************************************/
    594 
    595 void
    596 AcpiDmClearExternalList (
    597     void)
    598 {
    599     ACPI_EXTERNAL_LIST      *NextExternal;
    600 
    601 
    602     while (AcpiGbl_ExternalList)
    603     {
    604         NextExternal = AcpiGbl_ExternalList->Next;
    605         ACPI_FREE (AcpiGbl_ExternalList->Path);
    606         ACPI_FREE (AcpiGbl_ExternalList);
    607         AcpiGbl_ExternalList = NextExternal;
    608     }
    609 }
    610 
    611 
    612 /*******************************************************************************
    613  *
    614  * FUNCTION:    AcpiDmEmitExternals
    615  *
    616  * PARAMETERS:  None
    617  *
    618  * RETURN:      None
    619  *
    620  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
    621  *              the global external info list.
    622  *
    623  ******************************************************************************/
    624 
    625 void
    626 AcpiDmEmitExternals (
    627     void)
    628 {
    629     ACPI_EXTERNAL_LIST      *NextExternal;
    630 
    631 
    632     if (!AcpiGbl_ExternalList)
    633     {
    634         return;
    635     }
    636 
    637     /*
    638      * Walk the list of externals (unresolved references)
    639      * found during the AML parsing
    640      */
    641     while (AcpiGbl_ExternalList)
    642     {
    643         AcpiOsPrintf ("    External (%s%s",
    644             AcpiGbl_ExternalList->Path,
    645             AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
    646 
    647         if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
    648         {
    649             AcpiOsPrintf (")    // %u Arguments\n",
    650                 AcpiGbl_ExternalList->Value);
    651         }
    652         else
    653         {
    654             AcpiOsPrintf (")\n");
    655         }
    656 
    657         /* Free this external info block and move on to next external */
    658 
    659         NextExternal = AcpiGbl_ExternalList->Next;
    660         if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
    661         {
    662             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
    663         }
    664 
    665         ACPI_FREE (AcpiGbl_ExternalList->Path);
    666         ACPI_FREE (AcpiGbl_ExternalList);
    667         AcpiGbl_ExternalList = NextExternal;
    668     }
    669 
    670     AcpiOsPrintf ("\n");
    671 }
    672 
    673