Home | History | Annotate | Line # | Download | only in common
dmextern.c revision 1.1.1.4.2.6
      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:    AcpiDmEmitExternal
   1169  *
   1170  * PARAMETERS:  Op                  External Parse Object
   1171  *
   1172  * RETURN:      None
   1173  *
   1174  * DESCRIPTION: Emit an External() ASL statement for the current External
   1175  *              parse object
   1176  *
   1177  ******************************************************************************/
   1178 
   1179 void
   1180 AcpiDmEmitExternal (
   1181     ACPI_PARSE_OBJECT       *NameOp,
   1182     ACPI_PARSE_OBJECT       *TypeOp)
   1183 {
   1184     AcpiOsPrintf ("External (");
   1185     AcpiDmNamestring (NameOp->Common.Value.Name);
   1186     AcpiOsPrintf ("%s)\n",
   1187         AcpiDmGetObjectTypeName ((ACPI_OBJECT_TYPE) TypeOp->Common.Value.Integer));
   1188 }
   1189 
   1190 
   1191 /*******************************************************************************
   1192  *
   1193  * FUNCTION:    AcpiDmUnresolvedWarning
   1194  *
   1195  * PARAMETERS:  Type                - Where to output the warning.
   1196  *                                    0 means write to stderr
   1197  *                                    1 means write to AcpiOsPrintf
   1198  *
   1199  * RETURN:      None
   1200  *
   1201  * DESCRIPTION: Issue warning message if there are unresolved external control
   1202  *              methods within the disassembly.
   1203  *
   1204  ******************************************************************************/
   1205 
   1206 #if 0
   1207 Summary of the external control method problem:
   1208 
   1209 When the -e option is used with disassembly, the various SSDTs are simply
   1210 loaded into a global namespace for the disassembler to use in order to
   1211 resolve control method references (invocations).
   1212 
   1213 The disassembler tracks any such references, and will emit an External()
   1214 statement for these types of methods, with the proper number of arguments .
   1215 
   1216 Without the SSDTs, the AML does not contain enough information to properly
   1217 disassemble the control method invocation -- because the disassembler does
   1218 not know how many arguments to parse.
   1219 
   1220 An example: Assume we have two control methods. ABCD has one argument, and
   1221 EFGH has zero arguments. Further, we have two additional control methods
   1222 that invoke ABCD and EFGH, named T1 and T2:
   1223 
   1224     Method (ABCD, 1)
   1225     {
   1226     }
   1227     Method (EFGH, 0)
   1228     {
   1229     }
   1230     Method (T1)
   1231     {
   1232         ABCD (Add (2, 7, Local0))
   1233     }
   1234     Method (T2)
   1235     {
   1236         EFGH ()
   1237         Add (2, 7, Local0)
   1238     }
   1239 
   1240 Here is the AML code that is generated for T1 and T2:
   1241 
   1242      185:      Method (T1)
   1243 
   1244 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
   1245 
   1246      186:      {
   1247      187:          ABCD (Add (2, 7, Local0))
   1248 
   1249 00000353:  41 42 43 44 ............    "ABCD"
   1250 00000357:  72 0A 02 0A 07 60 ......    "r....`"
   1251 
   1252      188:      }
   1253 
   1254      190:      Method (T2)
   1255 
   1256 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
   1257 
   1258      191:      {
   1259      192:          EFGH ()
   1260 
   1261 00000364:  45 46 47 48 ............    "EFGH"
   1262 
   1263      193:          Add (2, 7, Local0)
   1264 
   1265 00000368:  72 0A 02 0A 07 60 ......    "r....`"
   1266      194:      }
   1267 
   1268 Note that the AML code for T1 and T2 is essentially identical. When
   1269 disassembling this code, the methods ABCD and EFGH must be known to the
   1270 disassembler, otherwise it does not know how to handle the method invocations.
   1271 
   1272 In other words, if ABCD and EFGH are actually external control methods
   1273 appearing in an SSDT, the disassembler does not know what to do unless
   1274 the owning SSDT has been loaded via the -e option.
   1275 #endif
   1276 
   1277 static char             ExternalWarningPart1[600];
   1278 static char             ExternalWarningPart2[400];
   1279 static char             ExternalWarningPart3[400];
   1280 static char             ExternalWarningPart4[200];
   1281 
   1282 void
   1283 AcpiDmUnresolvedWarning (
   1284     UINT8                   Type)
   1285 {
   1286     char                    *Format;
   1287     char                    Pad[] = "     *";
   1288     char                    NoPad[] = "";
   1289 
   1290 
   1291     if (!AcpiGbl_NumExternalMethods)
   1292     {
   1293         return;
   1294     }
   1295 
   1296     if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
   1297     {
   1298         return;
   1299     }
   1300 
   1301     Format = Type ? Pad : NoPad;
   1302 
   1303     sprintf (ExternalWarningPart1,
   1304         "%s iASL Warning: There %s %u external control method%s found during\n"
   1305         "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
   1306         "%s ACPI tables may be required to properly disassemble the code. This\n"
   1307         "%s resulting disassembler output file may not compile because the\n"
   1308         "%s disassembler did not know how many arguments to assign to the\n"
   1309         "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
   1310         "%s runtime and may or may not be available via the host OS.\n",
   1311         Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
   1312         AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
   1313         Format, AcpiGbl_ResolvedExternalMethods,
   1314         (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
   1315         (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
   1316         Format, Format, Format, Format, Format);
   1317 
   1318     sprintf (ExternalWarningPart2,
   1319         "%s To specify the tables needed to resolve external control method\n"
   1320         "%s references, the -e option can be used to specify the filenames.\n"
   1321         "%s Example iASL invocations:\n"
   1322         "%s     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
   1323         "%s     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
   1324         "%s     iasl -e ssdt*.aml -d dsdt.aml\n",
   1325         Format, Format, Format, Format, Format, Format);
   1326 
   1327     sprintf (ExternalWarningPart3,
   1328         "%s In addition, the -fe option can be used to specify a file containing\n"
   1329         "%s control method external declarations with the associated method\n"
   1330         "%s argument counts. Each line of the file must be of the form:\n"
   1331         "%s     External (<method pathname>, MethodObj, <argument count>)\n"
   1332         "%s Invocation:\n"
   1333         "%s     iasl -fe refs.txt -d dsdt.aml\n",
   1334         Format, Format, Format, Format, Format, Format);
   1335 
   1336     sprintf (ExternalWarningPart4,
   1337         "%s The following methods were unresolved and many not compile properly\n"
   1338         "%s because the disassembler had to guess at the number of arguments\n"
   1339         "%s required for each:\n",
   1340         Format, Format, Format);
   1341 
   1342     if (Type)
   1343     {
   1344         if (!AcpiGbl_ExternalFileList)
   1345         {
   1346             /* The -e option was not specified */
   1347 
   1348            AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     *\n%s     */\n",
   1349                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
   1350                ExternalWarningPart4);
   1351         }
   1352         else
   1353         {
   1354             /* The -e option was specified, but there are still some unresolved externals */
   1355 
   1356             AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     */\n",
   1357                ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
   1358         }
   1359     }
   1360     else
   1361     {
   1362         if (!AcpiGbl_ExternalFileList)
   1363         {
   1364             /* The -e option was not specified */
   1365 
   1366             fprintf (stderr, "\n%s\n%s\n%s\n",
   1367                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
   1368         }
   1369         else
   1370         {
   1371             /* The -e option was specified, but there are still some unresolved externals */
   1372 
   1373             fprintf (stderr, "\n%s\n%s\n",
   1374                ExternalWarningPart1, ExternalWarningPart3);
   1375         }
   1376     }
   1377 }
   1378