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