Home | History | Annotate | Line # | Download | only in common
dmextern.c revision 1.1.1.4.2.5
      1 /******************************************************************************
      2  *
      3  * Module Name: dmextern - Support for External() ASL statements
      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 "acpi.h"
     45 #include "accommon.h"
     46 #include "amlcode.h"
     47 #include "acnamesp.h"
     48 #include "acdisasm.h"
     49 #include "aslcompiler.h"
     50 #include <stdio.h>
     51 #include <errno.h>
     52 
     53 
     54 /*
     55  * This module is used for application-level code (iASL disassembler) only.
     56  *
     57  * It contains the code to create and emit any necessary External() ASL
     58  * statements for the module being disassembled.
     59  */
     60 #define _COMPONENT          ACPI_CA_DISASSEMBLER
     61         ACPI_MODULE_NAME    ("dmextern")
     62 
     63 
     64 /*
     65  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
     66  * ObjectTypeKeyword. Used to generate typed external declarations
     67  */
     68 static const char           *AcpiGbl_DmTypeNames[] =
     69 {
     70     /* 00 */ ", UnknownObj",        /* Type ANY */
     71     /* 01 */ ", IntObj",
     72     /* 02 */ ", StrObj",
     73     /* 03 */ ", BuffObj",
     74     /* 04 */ ", PkgObj",
     75     /* 05 */ ", FieldUnitObj",
     76     /* 06 */ ", DeviceObj",
     77     /* 07 */ ", EventObj",
     78     /* 08 */ ", MethodObj",
     79     /* 09 */ ", MutexObj",
     80     /* 10 */ ", OpRegionObj",
     81     /* 11 */ ", PowerResObj",
     82     /* 12 */ ", ProcessorObj",
     83     /* 13 */ ", ThermalZoneObj",
     84     /* 14 */ ", BuffFieldObj",
     85     /* 15 */ ", DDBHandleObj",
     86     /* 16 */ "",                    /* Debug object */
     87     /* 17 */ ", FieldUnitObj",
     88     /* 18 */ ", FieldUnitObj",
     89     /* 19 */ ", FieldUnitObj"
     90 };
     91 
     92 #define METHOD_SEPARATORS           " \t,()\n"
     93 
     94 
     95 /* Local prototypes */
     96 
     97 static const char *
     98 AcpiDmGetObjectTypeName (
     99     ACPI_OBJECT_TYPE        Type);
    100 
    101 static char *
    102 AcpiDmNormalizeParentPrefix (
    103     ACPI_PARSE_OBJECT       *Op,
    104     char                    *Path);
    105 
    106 static void
    107 AcpiDmAddPathToExternalList (
    108     char                    *Path,
    109     UINT8                   Type,
    110     UINT32                  Value,
    111     UINT16                  Flags);
    112 
    113 static ACPI_STATUS
    114 AcpiDmCreateNewExternal (
    115     char                    *ExternalPath,
    116     char                    *InternalPath,
    117     UINT8                   Type,
    118     UINT32                  Value,
    119     UINT16                  Flags);
    120 
    121 
    122 /*******************************************************************************
    123  *
    124  * FUNCTION:    AcpiDmGetObjectTypeName
    125  *
    126  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
    127  *
    128  * RETURN:      Pointer to a string
    129  *
    130  * DESCRIPTION: Map an object type to the ASL object type string.
    131  *
    132  ******************************************************************************/
    133 
    134 static const char *
    135 AcpiDmGetObjectTypeName (
    136     ACPI_OBJECT_TYPE        Type)
    137 {
    138 
    139     if (Type == ACPI_TYPE_LOCAL_SCOPE)
    140     {
    141         Type = ACPI_TYPE_DEVICE;
    142     }
    143     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
    144     {
    145         return ("");
    146     }
    147 
    148     return (AcpiGbl_DmTypeNames[Type]);
    149 }
    150 
    151 
    152 /*******************************************************************************
    153  *
    154  * FUNCTION:    AcpiDmNormalizeParentPrefix
    155  *
    156  * PARAMETERS:  Op                  - Parse op
    157  *              Path                - Path with parent prefix
    158  *
    159  * RETURN:      The full pathname to the object (from the namespace root)
    160  *
    161  * DESCRIPTION: Returns the full pathname of a path with parent prefix
    162  *              The caller must free the fullpath returned.
    163  *
    164  ******************************************************************************/
    165 
    166 static char *
    167 AcpiDmNormalizeParentPrefix (
    168     ACPI_PARSE_OBJECT       *Op,
    169     char                    *Path)
    170 {
    171     ACPI_NAMESPACE_NODE     *Node;
    172     char                    *Fullpath;
    173     char                    *ParentPath;
    174     ACPI_SIZE               Length;
    175     UINT32                  Index = 0;
    176 
    177 
    178     if (!Op)
    179     {
    180         return (NULL);
    181     }
    182 
    183     /* Search upwards in the parse tree until we reach the next namespace node */
    184 
    185     Op = Op->Common.Parent;
    186     while (Op)
    187     {
    188         if (Op->Common.Node)
    189         {
    190             break;
    191         }
    192 
    193         Op = Op->Common.Parent;
    194     }
    195 
    196     if (!Op)
    197     {
    198         return (NULL);
    199     }
    200 
    201     /*
    202      * Find the actual parent node for the reference:
    203      * Remove all carat prefixes from the input path.
    204      * There may be multiple parent prefixes (For example, ^^^M000)
    205      */
    206     Node = Op->Common.Node;
    207     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
    208     {
    209         Node = Node->Parent;
    210         Path++;
    211     }
    212 
    213     if (!Node)
    214     {
    215         return (NULL);
    216     }
    217 
    218     /* Get the full pathname for the parent node */
    219 
    220     ParentPath = AcpiNsGetExternalPathname (Node);
    221     if (!ParentPath)
    222     {
    223         return (NULL);
    224     }
    225 
    226     Length = (strlen (ParentPath) + strlen (Path) + 1);
    227     if (ParentPath[1])
    228     {
    229         /*
    230          * If ParentPath is not just a simple '\', increment the length
    231          * for the required dot separator (ParentPath.Path)
    232          */
    233         Length++;
    234 
    235         /* For External() statements, we do not want a leading '\' */
    236 
    237         if (*ParentPath == AML_ROOT_PREFIX)
    238         {
    239             Index = 1;
    240         }
    241     }
    242 
    243     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
    244     if (!Fullpath)
    245     {
    246         goto Cleanup;
    247     }
    248 
    249     /*
    250      * Concatenate parent fullpath and path. For example,
    251      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
    252      *
    253      * Copy the parent path
    254      */
    255     strcpy (Fullpath, &ParentPath[Index]);
    256 
    257     /*
    258      * Add dot separator
    259      * (don't need dot if parent fullpath is a single backslash)
    260      */
    261     if (ParentPath[1])
    262     {
    263         strcat (Fullpath, ".");
    264     }
    265 
    266     /* Copy child path (carat parent prefix(es) were skipped above) */
    267 
    268     strcat (Fullpath, Path);
    269 
    270 Cleanup:
    271     ACPI_FREE (ParentPath);
    272     return (Fullpath);
    273 }
    274 
    275 
    276 /*******************************************************************************
    277  *
    278  * FUNCTION:    AcpiDmAddToExternalFileList
    279  *
    280  * PARAMETERS:  PathList            - Single path or list separated by comma
    281  *
    282  * RETURN:      None
    283  *
    284  * DESCRIPTION: Add external files to global list
    285  *
    286  ******************************************************************************/
    287 
    288 ACPI_STATUS
    289 AcpiDmAddToExternalFileList (
    290     char                    *Pathname)
    291 {
    292     ACPI_EXTERNAL_FILE      *ExternalFile;
    293     char                    *LocalPathname;
    294 
    295 
    296     if (!Pathname)
    297     {
    298         return (AE_OK);
    299     }
    300 
    301     LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1);
    302     if (!LocalPathname)
    303     {
    304         return (AE_NO_MEMORY);
    305     }
    306 
    307     ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
    308     if (!ExternalFile)
    309     {
    310         ACPI_FREE (LocalPathname);
    311         return (AE_NO_MEMORY);
    312     }
    313 
    314     /* Take a copy of the file pathname */
    315 
    316     strcpy (LocalPathname, Pathname);
    317     ExternalFile->Path = LocalPathname;
    318 
    319     if (AcpiGbl_ExternalFileList)
    320     {
    321         ExternalFile->Next = AcpiGbl_ExternalFileList;
    322     }
    323 
    324     AcpiGbl_ExternalFileList = ExternalFile;
    325     return (AE_OK);
    326 }
    327 
    328 
    329 /*******************************************************************************
    330  *
    331  * FUNCTION:    AcpiDmClearExternalFileList
    332  *
    333  * PARAMETERS:  None
    334  *
    335  * RETURN:      None
    336  *
    337  * DESCRIPTION: Clear the external file list
    338  *
    339  ******************************************************************************/
    340 
    341 void
    342 AcpiDmClearExternalFileList (
    343     void)
    344 {
    345     ACPI_EXTERNAL_FILE      *NextExternal;
    346 
    347 
    348     while (AcpiGbl_ExternalFileList)
    349     {
    350         NextExternal = AcpiGbl_ExternalFileList->Next;
    351         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
    352         ACPI_FREE (AcpiGbl_ExternalFileList);
    353         AcpiGbl_ExternalFileList = NextExternal;
    354     }
    355 }
    356 
    357 
    358 /*******************************************************************************
    359  *
    360  * FUNCTION:    AcpiDmGetExternalsFromFile
    361  *
    362  * PARAMETERS:  None
    363  *
    364  * RETURN:      None
    365  *
    366  * DESCRIPTION: Process the optional external reference file.
    367  *
    368  * Each line in the file should be of the form:
    369  *      External (<Method namepath>, MethodObj, <ArgCount>)
    370  *
    371  * Example:
    372  *      External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
    373  *
    374  ******************************************************************************/
    375 
    376 void
    377 AcpiDmGetExternalsFromFile (
    378     void)
    379 {
    380     FILE                    *ExternalRefFile;
    381     char                    *Token;
    382     char                    *MethodName;
    383     UINT32                  ArgCount;
    384     UINT32                  ImportCount = 0;
    385 
    386 
    387     if (!Gbl_ExternalRefFilename)
    388     {
    389         return;
    390     }
    391 
    392     /* Open the file */
    393 
    394     ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r");
    395     if (!ExternalRefFile)
    396     {
    397         fprintf (stderr, "Could not open external reference file \"%s\"\n",
    398             Gbl_ExternalRefFilename);
    399         AslAbort ();
    400         return;
    401     }
    402 
    403     /* Each line defines a method */
    404 
    405     while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
    406     {
    407         Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
    408         if (!Token)
    409         {
    410             continue;
    411         }
    412 
    413         if (strcmp (Token, "External"))
    414         {
    415             continue;
    416         }
    417 
    418         MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
    419         if (!MethodName)
    420         {
    421             continue;
    422         }
    423 
    424         Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
    425         if (!Token)
    426         {
    427             continue;
    428         }
    429 
    430         if (strcmp (Token, "MethodObj"))
    431         {
    432             continue;
    433         }
    434 
    435         Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
    436         if (!Token)
    437         {
    438             continue;
    439         }
    440 
    441         /* Convert arg count string to an integer */
    442 
    443         errno = 0;
    444         ArgCount = strtoul (Token, NULL, 0);
    445         if (errno)
    446         {
    447             fprintf (stderr, "Invalid argument count (%s)\n", Token);
    448             continue;
    449         }
    450 
    451         if (ArgCount > 7)
    452         {
    453             fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
    454             continue;
    455         }
    456 
    457         /* Add this external to the global list */
    458 
    459         AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
    460             Gbl_ExternalRefFilename, ArgCount, MethodName);
    461 
    462         AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
    463             ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
    464         ImportCount++;
    465     }
    466 
    467     if (!ImportCount)
    468     {
    469         fprintf (stderr,
    470             "Did not find any external methods in reference file \"%s\"\n",
    471             Gbl_ExternalRefFilename);
    472     }
    473     else
    474     {
    475         /* Add the external(s) to the namespace */
    476 
    477         AcpiDmAddExternalsToNamespace ();
    478 
    479         AcpiOsPrintf ("%s: Imported %u external method definitions\n",
    480             Gbl_ExternalRefFilename, ImportCount);
    481     }
    482 
    483     fclose (ExternalRefFile);
    484 }
    485 
    486 
    487 /*******************************************************************************
    488  *
    489  * FUNCTION:    AcpiDmAddOpToExternalList
    490  *
    491  * PARAMETERS:  Op                  - Current parser Op
    492  *              Path                - Internal (AML) path to the object
    493  *              Type                - ACPI object type to be added
    494  *              Value               - Arg count if adding a Method object
    495  *              Flags               - To be passed to the external object
    496  *
    497  * RETURN:      None
    498  *
    499  * DESCRIPTION: Insert a new name into the global list of Externals which
    500  *              will in turn be later emitted as an External() declaration
    501  *              in the disassembled output.
    502  *
    503  *              This function handles the most common case where the referenced
    504  *              name is simply not found in the constructed namespace.
    505  *
    506  ******************************************************************************/
    507 
    508 void
    509 AcpiDmAddOpToExternalList (
    510     ACPI_PARSE_OBJECT       *Op,
    511     char                    *Path,
    512     UINT8                   Type,
    513     UINT32                  Value,
    514     UINT16                  Flags)
    515 {
    516     char                    *ExternalPath;
    517     char                    *InternalPath = Path;
    518     char                    *Temp;
    519     ACPI_STATUS             Status;
    520 
    521 
    522     ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
    523 
    524 
    525     if (!Path)
    526     {
    527         return_VOID;
    528     }
    529 
    530     /* Remove a root backslash if present */
    531 
    532     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
    533     {
    534         Path++;
    535     }
    536 
    537     /* Externalize the pathname */
    538 
    539     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
    540         NULL, &ExternalPath);
    541     if (ACPI_FAILURE (Status))
    542     {
    543         return_VOID;
    544     }
    545 
    546     /*
    547      * Get the full pathname from the root if "Path" has one or more
    548      * parent prefixes (^). Note: path will not contain a leading '\'.
    549      */
    550     if (*Path == (UINT8) AML_PARENT_PREFIX)
    551     {
    552         Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
    553 
    554         /* Set new external path */
    555 
    556         ACPI_FREE (ExternalPath);
    557         ExternalPath = Temp;
    558         if (!Temp)
    559         {
    560             return_VOID;
    561         }
    562 
    563         /* Create the new internal pathname */
    564 
    565         Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
    566         Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
    567         if (ACPI_FAILURE (Status))
    568         {
    569             ACPI_FREE (ExternalPath);
    570             return_VOID;
    571         }
    572     }
    573 
    574     /* Create the new External() declaration node */
    575 
    576     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
    577         Type, Value, Flags);
    578     if (ACPI_FAILURE (Status))
    579     {
    580         ACPI_FREE (ExternalPath);
    581         if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
    582         {
    583             ACPI_FREE (InternalPath);
    584         }
    585     }
    586 
    587     return_VOID;
    588 }
    589 
    590 
    591 /*******************************************************************************
    592  *
    593  * FUNCTION:    AcpiDmAddNodeToExternalList
    594  *
    595  * PARAMETERS:  Node                - Namespace node for object to be added
    596  *              Type                - ACPI object type to be added
    597  *              Value               - Arg count if adding a Method object
    598  *              Flags               - To be passed to the external object
    599  *
    600  * RETURN:      None
    601  *
    602  * DESCRIPTION: Insert a new name into the global list of Externals which
    603  *              will in turn be later emitted as an External() declaration
    604  *              in the disassembled output.
    605  *
    606  *              This function handles the case where the referenced name has
    607  *              been found in the namespace, but the name originated in a
    608  *              table other than the one that is being disassembled (such
    609  *              as a table that is added via the iASL -e option).
    610  *
    611  ******************************************************************************/
    612 
    613 void
    614 AcpiDmAddNodeToExternalList (
    615     ACPI_NAMESPACE_NODE     *Node,
    616     UINT8                   Type,
    617     UINT32                  Value,
    618     UINT16                  Flags)
    619 {
    620     char                    *ExternalPath;
    621     char                    *InternalPath;
    622     char                    *Temp;
    623     ACPI_STATUS             Status;
    624 
    625 
    626     ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
    627 
    628 
    629     if (!Node)
    630     {
    631         return_VOID;
    632     }
    633 
    634     /* Get the full external and internal pathnames to the node */
    635 
    636     ExternalPath = AcpiNsGetExternalPathname (Node);
    637     if (!ExternalPath)
    638     {
    639         return_VOID;
    640     }
    641 
    642     Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
    643     if (ACPI_FAILURE (Status))
    644     {
    645         ACPI_FREE (ExternalPath);
    646         return_VOID;
    647     }
    648 
    649     /* Remove the root backslash */
    650 
    651     if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1]))
    652     {
    653         Temp = ACPI_ALLOCATE_ZEROED (strlen (ExternalPath) + 1);
    654         if (!Temp)
    655         {
    656             return_VOID;
    657         }
    658 
    659         strcpy (Temp, &ExternalPath[1]);
    660         ACPI_FREE (ExternalPath);
    661         ExternalPath = Temp;
    662     }
    663 
    664     /* Create the new External() declaration node */
    665 
    666     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
    667         Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
    668     if (ACPI_FAILURE (Status))
    669     {
    670         ACPI_FREE (ExternalPath);
    671         ACPI_FREE (InternalPath);
    672     }
    673 
    674     return_VOID;
    675 }
    676 
    677 
    678 /*******************************************************************************
    679  *
    680  * FUNCTION:    AcpiDmAddPathToExternalList
    681  *
    682  * PARAMETERS:  Path                - External name of the object to be added
    683  *              Type                - ACPI object type to be added
    684  *              Value               - Arg count if adding a Method object
    685  *              Flags               - To be passed to the external object
    686  *
    687  * RETURN:      None
    688  *
    689  * DESCRIPTION: Insert a new name into the global list of Externals which
    690  *              will in turn be later emitted as an External() declaration
    691  *              in the disassembled output.
    692  *
    693  *              This function currently is used to add externals via a
    694  *              reference file (via the -fe iASL option).
    695  *
    696  ******************************************************************************/
    697 
    698 static void
    699 AcpiDmAddPathToExternalList (
    700     char                    *Path,
    701     UINT8                   Type,
    702     UINT32                  Value,
    703     UINT16                  Flags)
    704 {
    705     char                    *InternalPath;
    706     char                    *ExternalPath;
    707     ACPI_STATUS             Status;
    708 
    709 
    710     ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
    711 
    712 
    713     if (!Path)
    714     {
    715         return_VOID;
    716     }
    717 
    718     /* Remove a root backslash if present */
    719 
    720     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
    721     {
    722         Path++;
    723     }
    724 
    725     /* Create the internal and external pathnames */
    726 
    727     Status = AcpiNsInternalizeName (Path, &InternalPath);
    728     if (ACPI_FAILURE (Status))
    729     {
    730         return_VOID;
    731     }
    732 
    733     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
    734         NULL, &ExternalPath);
    735     if (ACPI_FAILURE (Status))
    736     {
    737         ACPI_FREE (InternalPath);
    738         return_VOID;
    739     }
    740 
    741     /* Create the new External() declaration node */
    742 
    743     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
    744         Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
    745     if (ACPI_FAILURE (Status))
    746     {
    747         ACPI_FREE (ExternalPath);
    748         ACPI_FREE (InternalPath);
    749     }
    750 
    751     return_VOID;
    752 }
    753 
    754 
    755 /*******************************************************************************
    756  *
    757  * FUNCTION:    AcpiDmCreateNewExternal
    758  *
    759  * PARAMETERS:  ExternalPath        - External path to the object
    760  *              InternalPath        - Internal (AML) path to the object
    761  *              Type                - ACPI object type to be added
    762  *              Value               - Arg count if adding a Method object
    763  *              Flags               - To be passed to the external object
    764  *
    765  * RETURN:      Status
    766  *
    767  * DESCRIPTION: Common low-level function to insert a new name into the global
    768  *              list of Externals which will in turn be later emitted as
    769  *              External() declarations in the disassembled output.
    770  *
    771  *              Note: The external name should not include a root prefix
    772  *              (backslash). We do not want External() statements to contain
    773  *              a leading '\', as this prevents duplicate external statements
    774  *              of the form:
    775  *
    776  *                  External (\ABCD)
    777  *                  External (ABCD)
    778  *
    779  *              This would cause a compile time error when the disassembled
    780  *              output file is recompiled.
    781  *
    782  *              There are two cases that are handled here. For both, we emit
    783  *              an External() statement:
    784  *              1) The name was simply not found in the namespace.
    785  *              2) The name was found, but it originated in a table other than
    786  *              the table that is being disassembled.
    787  *
    788  ******************************************************************************/
    789 
    790 static ACPI_STATUS
    791 AcpiDmCreateNewExternal (
    792     char                    *ExternalPath,
    793     char                    *InternalPath,
    794     UINT8                   Type,
    795     UINT32                  Value,
    796     UINT16                  Flags)
    797 {
    798     ACPI_EXTERNAL_LIST      *NewExternal;
    799     ACPI_EXTERNAL_LIST      *NextExternal;
    800     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
    801 
    802 
    803     ACPI_FUNCTION_TRACE (DmCreateNewExternal);
    804 
    805 
    806     /* Check all existing externals to ensure no duplicates */
    807 
    808     NextExternal = AcpiGbl_ExternalList;
    809     while (NextExternal)
    810     {
    811         /* Check for duplicates */
    812 
    813         if (!strcmp (ExternalPath, NextExternal->Path))
    814         {
    815             /*
    816              * If this external came from an External() opcode, we are
    817              * finished with this one. (No need to check any further).
    818              */
    819             if (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE)
    820             {
    821                 return_ACPI_STATUS (AE_ALREADY_EXISTS);
    822             }
    823 
    824             /* Allow upgrade of type from ANY */
    825 
    826             else if ((NextExternal->Type == ACPI_TYPE_ANY) &&
    827                 (Type != ACPI_TYPE_ANY))
    828             {
    829                 NextExternal->Type = Type;
    830             }
    831 
    832             /* Update the argument count as necessary */
    833 
    834             if (Value < NextExternal->Value)
    835             {
    836                 NextExternal->Value = Value;
    837             }
    838 
    839             /* Update flags. */
    840 
    841             NextExternal->Flags |= Flags;
    842             NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED;
    843 
    844             return_ACPI_STATUS (AE_ALREADY_EXISTS);
    845         }
    846 
    847         NextExternal = NextExternal->Next;
    848     }
    849 
    850     /* Allocate and init a new External() descriptor */
    851 
    852     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
    853     if (!NewExternal)
    854     {
    855         return_ACPI_STATUS (AE_NO_MEMORY);
    856     }
    857 
    858     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
    859         "Adding external reference node (%s) type [%s]\n",
    860         ExternalPath, AcpiUtGetTypeName (Type)));
    861 
    862     NewExternal->Flags = Flags;
    863     NewExternal->Value = Value;
    864     NewExternal->Path = ExternalPath;
    865     NewExternal->Type = Type;
    866     NewExternal->Length = (UINT16) strlen (ExternalPath);
    867     NewExternal->InternalPath = InternalPath;
    868 
    869     /* Link the new descriptor into the global list, alphabetically ordered */
    870 
    871     NextExternal = AcpiGbl_ExternalList;
    872     while (NextExternal)
    873     {
    874         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
    875         {
    876             if (PrevExternal)
    877             {
    878                 PrevExternal->Next = NewExternal;
    879             }
    880             else
    881             {
    882                 AcpiGbl_ExternalList = NewExternal;
    883             }
    884 
    885             NewExternal->Next = NextExternal;
    886             return_ACPI_STATUS (AE_OK);
    887         }
    888 
    889         PrevExternal = NextExternal;
    890         NextExternal = NextExternal->Next;
    891     }
    892 
    893     if (PrevExternal)
    894     {
    895         PrevExternal->Next = NewExternal;
    896     }
    897     else
    898     {
    899         AcpiGbl_ExternalList = NewExternal;
    900     }
    901 
    902     return_ACPI_STATUS (AE_OK);
    903 }
    904 
    905 
    906 /*******************************************************************************
    907  *
    908  * FUNCTION:    AcpiDmAddExternalsToNamespace
    909  *
    910  * PARAMETERS:  None
    911  *
    912  * RETURN:      None
    913  *
    914  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
    915  *              "resolved".
    916  *
    917  ******************************************************************************/
    918 
    919 void
    920 AcpiDmAddExternalsToNamespace (
    921     void)
    922 {
    923     ACPI_STATUS             Status;
    924     ACPI_NAMESPACE_NODE     *Node;
    925     ACPI_OPERAND_OBJECT     *ObjDesc;
    926     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
    927 
    928 
    929     while (External)
    930     {
    931         /* Add the external name (object) into the namespace */
    932 
    933         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
    934             ACPI_IMODE_LOAD_PASS1,
    935             ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
    936             NULL, &Node);
    937 
    938         if (ACPI_FAILURE (Status))
    939         {
    940             ACPI_EXCEPTION ((AE_INFO, Status,
    941                 "while adding external to namespace [%s]",
    942                 External->Path));
    943         }
    944 
    945         else switch (External->Type)
    946         {
    947         case ACPI_TYPE_METHOD:
    948 
    949             /* For methods, we need to save the argument count */
    950 
    951             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
    952             ObjDesc->Method.ParamCount = (UINT8) External->Value;
    953             Node->Object = ObjDesc;
    954             break;
    955 
    956         case ACPI_TYPE_REGION:
    957 
    958             /* Regions require a region sub-object */
    959 
    960             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
    961             ObjDesc->Region.Node = Node;
    962             Node->Object = ObjDesc;
    963             break;
    964 
    965         default:
    966 
    967             break;
    968         }
    969 
    970         External = External->Next;
    971     }
    972 }
    973 
    974 
    975 /*******************************************************************************
    976  *
    977  * FUNCTION:    AcpiDmGetExternalMethodCount
    978  *
    979  * PARAMETERS:  None
    980  *
    981  * RETURN:      The number of control method externals in the external list
    982  *
    983  * DESCRIPTION: Return the number of method externals that have been generated.
    984  *              If any control method externals have been found, we must
    985  *              re-parse the entire definition block with the new information
    986  *              (number of arguments for the methods.) This is limitation of
    987  *              AML, we don't know the number of arguments from the control
    988  *              method invocation itself.
    989  *
    990  ******************************************************************************/
    991 
    992 UINT32
    993 AcpiDmGetExternalMethodCount (
    994     void)
    995 {
    996     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
    997     UINT32                  Count = 0;
    998 
    999 
   1000     while (External)
   1001     {
   1002         if (External->Type == ACPI_TYPE_METHOD)
   1003         {
   1004             Count++;
   1005         }
   1006 
   1007         External = External->Next;
   1008     }
   1009 
   1010     return (Count);
   1011 }
   1012 
   1013 
   1014 /*******************************************************************************
   1015  *
   1016  * FUNCTION:    AcpiDmClearExternalList
   1017  *
   1018  * PARAMETERS:  None
   1019  *
   1020  * RETURN:      None
   1021  *
   1022  * DESCRIPTION: Free the entire External info list
   1023  *
   1024  ******************************************************************************/
   1025 
   1026 void
   1027 AcpiDmClearExternalList (
   1028     void)
   1029 {
   1030     ACPI_EXTERNAL_LIST      *NextExternal;
   1031 
   1032 
   1033     while (AcpiGbl_ExternalList)
   1034     {
   1035         NextExternal = AcpiGbl_ExternalList->Next;
   1036         ACPI_FREE (AcpiGbl_ExternalList->Path);
   1037         ACPI_FREE (AcpiGbl_ExternalList);
   1038         AcpiGbl_ExternalList = NextExternal;
   1039     }
   1040 }
   1041 
   1042 
   1043 /*******************************************************************************
   1044  *
   1045  * FUNCTION:    AcpiDmEmitExternals
   1046  *
   1047  * PARAMETERS:  None
   1048  *
   1049  * RETURN:      None
   1050  *
   1051  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
   1052  *              the global external info list.
   1053  *
   1054  ******************************************************************************/
   1055 
   1056 void
   1057 AcpiDmEmitExternals (
   1058     void)
   1059 {
   1060     ACPI_EXTERNAL_LIST      *NextExternal;
   1061 
   1062 
   1063     if (!AcpiGbl_ExternalList)
   1064     {
   1065         return;
   1066     }
   1067 
   1068     /*
   1069      * Determine the number of control methods in the external list, and
   1070      * also how many of those externals were resolved via the namespace.
   1071      */
   1072     NextExternal = AcpiGbl_ExternalList;
   1073     while (NextExternal)
   1074     {
   1075         if (NextExternal->Type == ACPI_TYPE_METHOD)
   1076         {
   1077             AcpiGbl_NumExternalMethods++;
   1078             if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
   1079             {
   1080                 AcpiGbl_ResolvedExternalMethods++;
   1081             }
   1082         }
   1083 
   1084         NextExternal = NextExternal->Next;
   1085     }
   1086 
   1087     /* Check if any control methods were unresolved */
   1088 
   1089     AcpiDmUnresolvedWarning (1);
   1090 
   1091     if (Gbl_ExternalRefFilename)
   1092     {
   1093         AcpiOsPrintf (
   1094             "    /*\n     * External declarations were imported from\n"
   1095             "     * a reference file -- %s\n     */\n\n",
   1096             Gbl_ExternalRefFilename);
   1097     }
   1098 
   1099     /*
   1100      * Walk and emit the list of externals found during the AML parsing
   1101      */
   1102     while (AcpiGbl_ExternalList)
   1103     {
   1104         if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
   1105         {
   1106             AcpiOsPrintf ("    External (%s%s)",
   1107                 AcpiGbl_ExternalList->Path,
   1108                 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
   1109 
   1110             /* Check for "unresolved" method reference */
   1111 
   1112             if ((AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) &&
   1113                 (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
   1114             {
   1115                 AcpiOsPrintf ("    // Warning: Unknown method, "
   1116                     "guessing %u arguments",
   1117                     AcpiGbl_ExternalList->Value);
   1118             }
   1119 
   1120             /* Check for external from a external references file */
   1121 
   1122             else if (AcpiGbl_ExternalList->Flags & ACPI_EXT_ORIGIN_FROM_FILE)
   1123             {
   1124                 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
   1125                 {
   1126                     AcpiOsPrintf ("    // %u Arguments",
   1127                         AcpiGbl_ExternalList->Value);
   1128                 }
   1129 
   1130                 AcpiOsPrintf ("    // From external reference file");
   1131             }
   1132 
   1133             /* This is the normal external case */
   1134 
   1135             else
   1136             {
   1137                 /* For methods, add a comment with the number of arguments */
   1138 
   1139                 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
   1140                 {
   1141                     AcpiOsPrintf ("    // %u Arguments",
   1142                         AcpiGbl_ExternalList->Value);
   1143                 }
   1144             }
   1145 
   1146             AcpiOsPrintf ("\n");
   1147         }
   1148 
   1149         /* Free this external info block and move on to next external */
   1150 
   1151         NextExternal = AcpiGbl_ExternalList->Next;
   1152         if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
   1153         {
   1154             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
   1155         }
   1156 
   1157         ACPI_FREE (AcpiGbl_ExternalList->Path);
   1158         ACPI_FREE (AcpiGbl_ExternalList);
   1159         AcpiGbl_ExternalList = NextExternal;
   1160     }
   1161 
   1162     AcpiOsPrintf ("\n");
   1163 }
   1164 
   1165 
   1166 /*******************************************************************************
   1167  *
   1168  * FUNCTION:    AcpiDmUnresolvedWarning
   1169  *
   1170  * PARAMETERS:  Type                - Where to output the warning.
   1171  *                                    0 means write to stderr
   1172  *                                    1 means write to AcpiOsPrintf
   1173  *
   1174  * RETURN:      None
   1175  *
   1176  * DESCRIPTION: Issue warning message if there are unresolved external control
   1177  *              methods within the disassembly.
   1178  *
   1179  ******************************************************************************/
   1180 
   1181 #if 0
   1182 Summary of the external control method problem:
   1183 
   1184 When the -e option is used with disassembly, the various SSDTs are simply
   1185 loaded into a global namespace for the disassembler to use in order to
   1186 resolve control method references (invocations).
   1187 
   1188 The disassembler tracks any such references, and will emit an External()
   1189 statement for these types of methods, with the proper number of arguments .
   1190 
   1191 Without the SSDTs, the AML does not contain enough information to properly
   1192 disassemble the control method invocation -- because the disassembler does
   1193 not know how many arguments to parse.
   1194 
   1195 An example: Assume we have two control methods. ABCD has one argument, and
   1196 EFGH has zero arguments. Further, we have two additional control methods
   1197 that invoke ABCD and EFGH, named T1 and T2:
   1198 
   1199     Method (ABCD, 1)
   1200     {
   1201     }
   1202     Method (EFGH, 0)
   1203     {
   1204     }
   1205     Method (T1)
   1206     {
   1207         ABCD (Add (2, 7, Local0))
   1208     }
   1209     Method (T2)
   1210     {
   1211         EFGH ()
   1212         Add (2, 7, Local0)
   1213     }
   1214 
   1215 Here is the AML code that is generated for T1 and T2:
   1216 
   1217      185:      Method (T1)
   1218 
   1219 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
   1220 
   1221      186:      {
   1222      187:          ABCD (Add (2, 7, Local0))
   1223 
   1224 00000353:  41 42 43 44 ............    "ABCD"
   1225 00000357:  72 0A 02 0A 07 60 ......    "r....`"
   1226 
   1227      188:      }
   1228 
   1229      190:      Method (T2)
   1230 
   1231 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
   1232 
   1233      191:      {
   1234      192:          EFGH ()
   1235 
   1236 00000364:  45 46 47 48 ............    "EFGH"
   1237 
   1238      193:          Add (2, 7, Local0)
   1239 
   1240 00000368:  72 0A 02 0A 07 60 ......    "r....`"
   1241      194:      }
   1242 
   1243 Note that the AML code for T1 and T2 is essentially identical. When
   1244 disassembling this code, the methods ABCD and EFGH must be known to the
   1245 disassembler, otherwise it does not know how to handle the method invocations.
   1246 
   1247 In other words, if ABCD and EFGH are actually external control methods
   1248 appearing in an SSDT, the disassembler does not know what to do unless
   1249 the owning SSDT has been loaded via the -e option.
   1250 #endif
   1251 
   1252 static char             ExternalWarningPart1[600];
   1253 static char             ExternalWarningPart2[400];
   1254 static char             ExternalWarningPart3[400];
   1255 static char             ExternalWarningPart4[200];
   1256 
   1257 void
   1258 AcpiDmUnresolvedWarning (
   1259     UINT8                   Type)
   1260 {
   1261     char                    *Format;
   1262     char                    Pad[] = "     *";
   1263     char                    NoPad[] = "";
   1264 
   1265 
   1266     if (!AcpiGbl_NumExternalMethods)
   1267     {
   1268         return;
   1269     }
   1270 
   1271     if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
   1272     {
   1273         return;
   1274     }
   1275 
   1276     Format = Type ? Pad : NoPad;
   1277 
   1278     sprintf (ExternalWarningPart1,
   1279         "%s iASL Warning: There %s %u external control method%s found during\n"
   1280         "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
   1281         "%s ACPI tables may be required to properly disassemble the code. This\n"
   1282         "%s resulting disassembler output file may not compile because the\n"
   1283         "%s disassembler did not know how many arguments to assign to the\n"
   1284         "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
   1285         "%s runtime and may or may not be available via the host OS.\n",
   1286         Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
   1287         AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
   1288         Format, AcpiGbl_ResolvedExternalMethods,
   1289         (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
   1290         (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
   1291         Format, Format, Format, Format, Format);
   1292 
   1293     sprintf (ExternalWarningPart2,
   1294         "%s To specify the tables needed to resolve external control method\n"
   1295         "%s references, the -e option can be used to specify the filenames.\n"
   1296         "%s Example iASL invocations:\n"
   1297         "%s     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
   1298         "%s     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
   1299         "%s     iasl -e ssdt*.aml -d dsdt.aml\n",
   1300         Format, Format, Format, Format, Format, Format);
   1301 
   1302     sprintf (ExternalWarningPart3,
   1303         "%s In addition, the -fe option can be used to specify a file containing\n"
   1304         "%s control method external declarations with the associated method\n"
   1305         "%s argument counts. Each line of the file must be of the form:\n"
   1306         "%s     External (<method pathname>, MethodObj, <argument count>)\n"
   1307         "%s Invocation:\n"
   1308         "%s     iasl -fe refs.txt -d dsdt.aml\n",
   1309         Format, Format, Format, Format, Format, Format);
   1310 
   1311     sprintf (ExternalWarningPart4,
   1312         "%s The following methods were unresolved and many not compile properly\n"
   1313         "%s because the disassembler had to guess at the number of arguments\n"
   1314         "%s required for each:\n",
   1315         Format, Format, Format);
   1316 
   1317     if (Type)
   1318     {
   1319         if (!AcpiGbl_ExternalFileList)
   1320         {
   1321             /* The -e option was not specified */
   1322 
   1323            AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     *\n%s     */\n",
   1324                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
   1325                ExternalWarningPart4);
   1326         }
   1327         else
   1328         {
   1329             /* The -e option was specified, but there are still some unresolved externals */
   1330 
   1331             AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     */\n",
   1332                ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
   1333         }
   1334     }
   1335     else
   1336     {
   1337         if (!AcpiGbl_ExternalFileList)
   1338         {
   1339             /* The -e option was not specified */
   1340 
   1341             fprintf (stderr, "\n%s\n%s\n%s\n",
   1342                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
   1343         }
   1344         else
   1345         {
   1346             /* The -e option was specified, but there are still some unresolved externals */
   1347 
   1348             fprintf (stderr, "\n%s\n%s\n",
   1349                ExternalWarningPart1, ExternalWarningPart3);
   1350         }
   1351     }
   1352 }
   1353