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 */ ", 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 
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         AslAbort ();
401         return;
402     }
403 
404     /* Each line defines a method */
405 
406     while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
407     {
408         Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
409         if (!Token) continue;
410         if (strcmp (Token, "External")) continue;
411 
412         MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
413         if (!MethodName) continue;
414 
415         Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
416         if (!Token) continue;
417         if (strcmp (Token, "MethodObj")) continue;
418 
419         Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
420         if (!Token) continue;
421 
422         /* Convert arg count string to an integer */
423 
424         errno = 0;
425         ArgCount = strtoul (Token, NULL, 0);
426         if (errno)
427         {
428             fprintf (stderr, "Invalid argument count (%s)\n", Token);
429             continue;
430         }
431         if (ArgCount > 7)
432         {
433             fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
434             continue;
435         }
436 
437         /* Add this external to the global list */
438 
439         AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
440             Gbl_ExternalRefFilename, ArgCount, MethodName);
441 
442         AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
443             ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
444         ImportCount++;
445     }
446 
447     if (!ImportCount)
448     {
449         fprintf (stderr, "Did not find any external methods in reference file \"%s\"\n",
450             Gbl_ExternalRefFilename);
451     }
452     else
453     {
454         /* Add the external(s) to the namespace */
455 
456         AcpiDmAddExternalsToNamespace ();
457 
458         AcpiOsPrintf ("%s: Imported %u external method definitions\n",
459             Gbl_ExternalRefFilename, ImportCount);
460     }
461 
462     fclose (ExternalRefFile);
463 }
464 
465 
466 /*******************************************************************************
467  *
468  * FUNCTION:    AcpiDmAddOpToExternalList
469  *
470  * PARAMETERS:  Op                  - Current parser Op
471  *              Path                - Internal (AML) path to the object
472  *              Type                - ACPI object type to be added
473  *              Value               - Arg count if adding a Method object
474  *              Flags               - To be passed to the external object
475  *
476  * RETURN:      None
477  *
478  * DESCRIPTION: Insert a new name into the global list of Externals which
479  *              will in turn be later emitted as an External() declaration
480  *              in the disassembled output.
481  *
482  *              This function handles the most common case where the referenced
483  *              name is simply not found in the constructed namespace.
484  *
485  ******************************************************************************/
486 
487 void
488 AcpiDmAddOpToExternalList (
489     ACPI_PARSE_OBJECT       *Op,
490     char                    *Path,
491     UINT8                   Type,
492     UINT32                  Value,
493     UINT16                  Flags)
494 {
495     char                    *ExternalPath;
496     char                    *InternalPath = Path;
497     char                    *Temp;
498     ACPI_STATUS             Status;
499 
500 
501     ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
502 
503 
504     if (!Path)
505     {
506         return_VOID;
507     }
508 
509     /* Remove a root backslash if present */
510 
511     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
512     {
513         Path++;
514     }
515 
516     /* Externalize the pathname */
517 
518     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
519         NULL, &ExternalPath);
520     if (ACPI_FAILURE (Status))
521     {
522         return_VOID;
523     }
524 
525     /*
526      * Get the full pathname from the root if "Path" has one or more
527      * parent prefixes (^). Note: path will not contain a leading '\'.
528      */
529     if (*Path == (UINT8) AML_PARENT_PREFIX)
530     {
531         Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
532 
533         /* Set new external path */
534 
535         ACPI_FREE (ExternalPath);
536         ExternalPath = Temp;
537         if (!Temp)
538         {
539             return_VOID;
540         }
541 
542         /* Create the new internal pathname */
543 
544         Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
545         Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
546         if (ACPI_FAILURE (Status))
547         {
548             ACPI_FREE (ExternalPath);
549             return_VOID;
550         }
551     }
552 
553     /* Create the new External() declaration node */
554 
555     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
556         Type, Value, Flags);
557     if (ACPI_FAILURE (Status))
558     {
559         ACPI_FREE (ExternalPath);
560         if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
561         {
562             ACPI_FREE (InternalPath);
563         }
564     }
565 
566     return_VOID;
567 }
568 
569 
570 /*******************************************************************************
571  *
572  * FUNCTION:    AcpiDmAddNodeToExternalList
573  *
574  * PARAMETERS:  Node                - Namespace node for object to be added
575  *              Type                - ACPI object type to be added
576  *              Value               - Arg count if adding a Method object
577  *              Flags               - To be passed to the external object
578  *
579  * RETURN:      None
580  *
581  * DESCRIPTION: Insert a new name into the global list of Externals which
582  *              will in turn be later emitted as an External() declaration
583  *              in the disassembled output.
584  *
585  *              This function handles the case where the referenced name has
586  *              been found in the namespace, but the name originated in a
587  *              table other than the one that is being disassembled (such
588  *              as a table that is added via the iASL -e option).
589  *
590  ******************************************************************************/
591 
592 void
593 AcpiDmAddNodeToExternalList (
594     ACPI_NAMESPACE_NODE     *Node,
595     UINT8                   Type,
596     UINT32                  Value,
597     UINT16                  Flags)
598 {
599     char                    *ExternalPath;
600     char                    *InternalPath;
601     char                    *Temp;
602     ACPI_STATUS             Status;
603 
604 
605     ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
606 
607 
608     if (!Node)
609     {
610         return_VOID;
611     }
612 
613     /* Get the full external and internal pathnames to the node */
614 
615     ExternalPath = AcpiNsGetExternalPathname (Node);
616     if (!ExternalPath)
617     {
618         return_VOID;
619     }
620 
621     Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
622     if (ACPI_FAILURE (Status))
623     {
624         ACPI_FREE (ExternalPath);
625         return_VOID;
626     }
627 
628     /* Remove the root backslash */
629 
630     if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1]))
631     {
632         Temp = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (ExternalPath) + 1);
633         if (!Temp)
634         {
635             return_VOID;
636         }
637 
638         ACPI_STRCPY (Temp, &ExternalPath[1]);
639         ACPI_FREE (ExternalPath);
640         ExternalPath = Temp;
641     }
642 
643     /* Create the new External() declaration node */
644 
645     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
646         Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
647     if (ACPI_FAILURE (Status))
648     {
649         ACPI_FREE (ExternalPath);
650         ACPI_FREE (InternalPath);
651     }
652 
653     return_VOID;
654 }
655 
656 
657 /*******************************************************************************
658  *
659  * FUNCTION:    AcpiDmAddPathToExternalList
660  *
661  * PARAMETERS:  Path                - External name of the object to be added
662  *              Type                - ACPI object type to be added
663  *              Value               - Arg count if adding a Method object
664  *              Flags               - To be passed to the external object
665  *
666  * RETURN:      None
667  *
668  * DESCRIPTION: Insert a new name into the global list of Externals which
669  *              will in turn be later emitted as an External() declaration
670  *              in the disassembled output.
671  *
672  *              This function currently is used to add externals via a
673  *              reference file (via the -fe iASL option).
674  *
675  ******************************************************************************/
676 
677 static void
678 AcpiDmAddPathToExternalList (
679     char                    *Path,
680     UINT8                   Type,
681     UINT32                  Value,
682     UINT16                  Flags)
683 {
684     char                    *InternalPath;
685     char                    *ExternalPath;
686     ACPI_STATUS             Status;
687 
688 
689     ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
690 
691 
692     if (!Path)
693     {
694         return_VOID;
695     }
696 
697     /* Remove a root backslash if present */
698 
699     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
700     {
701         Path++;
702     }
703 
704     /* Create the internal and external pathnames */
705 
706     Status = AcpiNsInternalizeName (Path, &InternalPath);
707     if (ACPI_FAILURE (Status))
708     {
709         return_VOID;
710     }
711 
712     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
713         NULL, &ExternalPath);
714     if (ACPI_FAILURE (Status))
715     {
716         ACPI_FREE (InternalPath);
717         return_VOID;
718     }
719 
720     /* Create the new External() declaration node */
721 
722     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
723         Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
724     if (ACPI_FAILURE (Status))
725     {
726         ACPI_FREE (ExternalPath);
727         ACPI_FREE (InternalPath);
728     }
729 
730     return_VOID;
731 }
732 
733 
734 /*******************************************************************************
735  *
736  * FUNCTION:    AcpiDmCreateNewExternal
737  *
738  * PARAMETERS:  ExternalPath        - External path to the object
739  *              InternalPath        - Internal (AML) path to the object
740  *              Type                - ACPI object type to be added
741  *              Value               - Arg count if adding a Method object
742  *              Flags               - To be passed to the external object
743  *
744  * RETURN:      Status
745  *
746  * DESCRIPTION: Common low-level function to insert a new name into the global
747  *              list of Externals which will in turn be later emitted as
748  *              External() declarations in the disassembled output.
749  *
750  *              Note: The external name should not include a root prefix
751  *              (backslash). We do not want External() statements to contain
752  *              a leading '\', as this prevents duplicate external statements
753  *              of the form:
754  *
755  *                  External (\ABCD)
756  *                  External (ABCD)
757  *
758  *              This would cause a compile time error when the disassembled
759  *              output file is recompiled.
760  *
761  *              There are two cases that are handled here. For both, we emit
762  *              an External() statement:
763  *              1) The name was simply not found in the namespace.
764  *              2) The name was found, but it originated in a table other than
765  *              the table that is being disassembled.
766  *
767  ******************************************************************************/
768 
769 static ACPI_STATUS
770 AcpiDmCreateNewExternal (
771     char                    *ExternalPath,
772     char                    *InternalPath,
773     UINT8                   Type,
774     UINT32                  Value,
775     UINT16                  Flags)
776 {
777     ACPI_EXTERNAL_LIST      *NewExternal;
778     ACPI_EXTERNAL_LIST      *NextExternal;
779     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
780 
781 
782     ACPI_FUNCTION_TRACE (DmCreateNewExternal);
783 
784 
785     /* Check all existing externals to ensure no duplicates */
786 
787     NextExternal = AcpiGbl_ExternalList;
788     while (NextExternal)
789     {
790         if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
791         {
792             /* Duplicate method, check that the Value (ArgCount) is the same */
793 
794             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
795                 (NextExternal->Value != Value) &&
796                 (Value > 0))
797             {
798                 ACPI_ERROR ((AE_INFO,
799                     "External method arg count mismatch %s: Current %u, attempted %u",
800                     NextExternal->Path, NextExternal->Value, Value));
801             }
802 
803             /* Allow upgrade of type from ANY */
804 
805             else if (NextExternal->Type == ACPI_TYPE_ANY)
806             {
807                 NextExternal->Type = Type;
808                 NextExternal->Value = Value;
809             }
810 
811             return_ACPI_STATUS (AE_ALREADY_EXISTS);
812         }
813 
814         NextExternal = NextExternal->Next;
815     }
816 
817     /* Allocate and init a new External() descriptor */
818 
819     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
820     if (!NewExternal)
821     {
822         return_ACPI_STATUS (AE_NO_MEMORY);
823     }
824 
825     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
826         "Adding external reference node (%s) type [%s]\n",
827         ExternalPath, AcpiUtGetTypeName (Type)));
828 
829     NewExternal->Flags = Flags;
830     NewExternal->Value = Value;
831     NewExternal->Path = ExternalPath;
832     NewExternal->Type = Type;
833     NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
834     NewExternal->InternalPath = InternalPath;
835 
836     /* Link the new descriptor into the global list, alphabetically ordered */
837 
838     NextExternal = AcpiGbl_ExternalList;
839     while (NextExternal)
840     {
841         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
842         {
843             if (PrevExternal)
844             {
845                 PrevExternal->Next = NewExternal;
846             }
847             else
848             {
849                 AcpiGbl_ExternalList = NewExternal;
850             }
851 
852             NewExternal->Next = NextExternal;
853             return_ACPI_STATUS (AE_OK);
854         }
855 
856         PrevExternal = NextExternal;
857         NextExternal = NextExternal->Next;
858     }
859 
860     if (PrevExternal)
861     {
862         PrevExternal->Next = NewExternal;
863     }
864     else
865     {
866         AcpiGbl_ExternalList = NewExternal;
867     }
868 
869     return_ACPI_STATUS (AE_OK);
870 }
871 
872 
873 /*******************************************************************************
874  *
875  * FUNCTION:    AcpiDmAddExternalsToNamespace
876  *
877  * PARAMETERS:  None
878  *
879  * RETURN:      None
880  *
881  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
882  *              "resolved".
883  *
884  ******************************************************************************/
885 
886 void
887 AcpiDmAddExternalsToNamespace (
888     void)
889 {
890     ACPI_STATUS             Status;
891     ACPI_NAMESPACE_NODE     *Node;
892     ACPI_OPERAND_OBJECT     *ObjDesc;
893     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
894 
895 
896     while (External)
897     {
898         /* Add the external name (object) into the namespace */
899 
900         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
901                    ACPI_IMODE_LOAD_PASS1,
902                    ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
903                    NULL, &Node);
904 
905         if (ACPI_FAILURE (Status))
906         {
907             ACPI_EXCEPTION ((AE_INFO, Status,
908                 "while adding external to namespace [%s]",
909                 External->Path));
910         }
911 
912         else switch (External->Type)
913         {
914         case ACPI_TYPE_METHOD:
915 
916             /* For methods, we need to save the argument count */
917 
918             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
919             ObjDesc->Method.ParamCount = (UINT8) External->Value;
920             Node->Object = ObjDesc;
921             break;
922 
923         case ACPI_TYPE_REGION:
924 
925             /* Regions require a region sub-object */
926 
927             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
928             ObjDesc->Region.Node = Node;
929             Node->Object = ObjDesc;
930             break;
931 
932         default:
933 
934             break;
935         }
936 
937         External = External->Next;
938     }
939 }
940 
941 
942 /*******************************************************************************
943  *
944  * FUNCTION:    AcpiDmGetExternalMethodCount
945  *
946  * PARAMETERS:  None
947  *
948  * RETURN:      The number of control method externals in the external list
949  *
950  * DESCRIPTION: Return the number of method externals that have been generated.
951  *              If any control method externals have been found, we must
952  *              re-parse the entire definition block with the new information
953  *              (number of arguments for the methods.) This is limitation of
954  *              AML, we don't know the number of arguments from the control
955  *              method invocation itself.
956  *
957  ******************************************************************************/
958 
959 UINT32
960 AcpiDmGetExternalMethodCount (
961     void)
962 {
963     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
964     UINT32                  Count = 0;
965 
966 
967     while (External)
968     {
969         if (External->Type == ACPI_TYPE_METHOD)
970         {
971             Count++;
972         }
973 
974         External = External->Next;
975     }
976 
977     return (Count);
978 }
979 
980 
981 /*******************************************************************************
982  *
983  * FUNCTION:    AcpiDmClearExternalList
984  *
985  * PARAMETERS:  None
986  *
987  * RETURN:      None
988  *
989  * DESCRIPTION: Free the entire External info list
990  *
991  ******************************************************************************/
992 
993 void
994 AcpiDmClearExternalList (
995     void)
996 {
997     ACPI_EXTERNAL_LIST      *NextExternal;
998 
999 
1000     while (AcpiGbl_ExternalList)
1001     {
1002         NextExternal = AcpiGbl_ExternalList->Next;
1003         ACPI_FREE (AcpiGbl_ExternalList->Path);
1004         ACPI_FREE (AcpiGbl_ExternalList);
1005         AcpiGbl_ExternalList = NextExternal;
1006     }
1007 }
1008 
1009 
1010 /*******************************************************************************
1011  *
1012  * FUNCTION:    AcpiDmEmitExternals
1013  *
1014  * PARAMETERS:  None
1015  *
1016  * RETURN:      None
1017  *
1018  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1019  *              the global external info list.
1020  *
1021  ******************************************************************************/
1022 
1023 void
1024 AcpiDmEmitExternals (
1025     void)
1026 {
1027     ACPI_EXTERNAL_LIST      *NextExternal;
1028 
1029 
1030     if (!AcpiGbl_ExternalList)
1031     {
1032         return;
1033     }
1034 
1035     /*
1036      * Determine the number of control methods in the external list, and
1037      * also how many of those externals were resolved via the namespace.
1038      */
1039     NextExternal = AcpiGbl_ExternalList;
1040     while (NextExternal)
1041     {
1042         if (NextExternal->Type == ACPI_TYPE_METHOD)
1043         {
1044             AcpiGbl_NumExternalMethods++;
1045             if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1046             {
1047                 AcpiGbl_ResolvedExternalMethods++;
1048             }
1049         }
1050 
1051         NextExternal = NextExternal->Next;
1052     }
1053 
1054     /* Check if any control methods were unresolved */
1055 
1056     AcpiDmUnresolvedWarning (1);
1057 
1058     /* Emit any unresolved method externals in a single text block */
1059 
1060     NextExternal = AcpiGbl_ExternalList;
1061     while (NextExternal)
1062     {
1063         if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
1064             (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1065         {
1066             AcpiOsPrintf ("    External (%s%s",
1067                 NextExternal->Path,
1068                 AcpiDmGetObjectTypeName (NextExternal->Type));
1069 
1070             AcpiOsPrintf (")    // Warning: Unresolved method, "
1071                 "guessing %u arguments\n",
1072                 NextExternal->Value);
1073 
1074             NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1075         }
1076 
1077         NextExternal = NextExternal->Next;
1078     }
1079 
1080     AcpiOsPrintf ("\n");
1081 
1082 
1083     /* Emit externals that were imported from a file */
1084 
1085     if (Gbl_ExternalRefFilename)
1086     {
1087         AcpiOsPrintf (
1088             "    /*\n     * External declarations that were imported from\n"
1089             "     * the reference file [%s]\n     */\n",
1090             Gbl_ExternalRefFilename);
1091 
1092         NextExternal = AcpiGbl_ExternalList;
1093         while (NextExternal)
1094         {
1095             if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) &&
1096                 (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE))
1097             {
1098                 AcpiOsPrintf ("    External (%s%s",
1099                     NextExternal->Path,
1100                     AcpiDmGetObjectTypeName (NextExternal->Type));
1101 
1102                 if (NextExternal->Type == ACPI_TYPE_METHOD)
1103                 {
1104                     AcpiOsPrintf (")    // %u Arguments\n",
1105                         NextExternal->Value);
1106                 }
1107                 else
1108                 {
1109                     AcpiOsPrintf (")\n");
1110                 }
1111                 NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1112             }
1113 
1114             NextExternal = NextExternal->Next;
1115         }
1116 
1117         AcpiOsPrintf ("\n");
1118     }
1119 
1120     /*
1121      * Walk the list of externals found during the AML parsing
1122      */
1123     while (AcpiGbl_ExternalList)
1124     {
1125         if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1126         {
1127             AcpiOsPrintf ("    External (%s%s",
1128                 AcpiGbl_ExternalList->Path,
1129                 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1130 
1131             /* For methods, add a comment with the number of arguments */
1132 
1133             if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1134             {
1135                 AcpiOsPrintf (")    // %u Arguments\n",
1136                     AcpiGbl_ExternalList->Value);
1137             }
1138             else
1139             {
1140                 AcpiOsPrintf (")\n");
1141             }
1142         }
1143 
1144         /* Free this external info block and move on to next external */
1145 
1146         NextExternal = AcpiGbl_ExternalList->Next;
1147         if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1148         {
1149             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1150         }
1151 
1152         ACPI_FREE (AcpiGbl_ExternalList->Path);
1153         ACPI_FREE (AcpiGbl_ExternalList);
1154         AcpiGbl_ExternalList = NextExternal;
1155     }
1156 
1157     AcpiOsPrintf ("\n");
1158 }
1159 
1160 
1161 /*******************************************************************************
1162  *
1163  * FUNCTION:    AcpiDmUnresolvedWarning
1164  *
1165  * PARAMETERS:  Type                - Where to output the warning.
1166  *                                    0 means write to stderr
1167  *                                    1 means write to AcpiOsPrintf
1168  *
1169  * RETURN:      None
1170  *
1171  * DESCRIPTION: Issue warning message if there are unresolved external control
1172  *              methods within the disassembly.
1173  *
1174  ******************************************************************************/
1175 
1176 #if 0
1177 Summary of the external control method problem:
1178 
1179 When the -e option is used with disassembly, the various SSDTs are simply
1180 loaded into a global namespace for the disassembler to use in order to
1181 resolve control method references (invocations).
1182 
1183 The disassembler tracks any such references, and will emit an External()
1184 statement for these types of methods, with the proper number of arguments .
1185 
1186 Without the SSDTs, the AML does not contain enough information to properly
1187 disassemble the control method invocation -- because the disassembler does
1188 not know how many arguments to parse.
1189 
1190 An example: Assume we have two control methods. ABCD has one argument, and
1191 EFGH has zero arguments. Further, we have two additional control methods
1192 that invoke ABCD and EFGH, named T1 and T2:
1193 
1194     Method (ABCD, 1)
1195     {
1196     }
1197     Method (EFGH, 0)
1198     {
1199     }
1200     Method (T1)
1201     {
1202         ABCD (Add (2, 7, Local0))
1203     }
1204     Method (T2)
1205     {
1206         EFGH ()
1207         Add (2, 7, Local0)
1208     }
1209 
1210 Here is the AML code that is generated for T1 and T2:
1211 
1212      185:      Method (T1)
1213 
1214 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1215 
1216      186:      {
1217      187:          ABCD (Add (2, 7, Local0))
1218 
1219 00000353:  41 42 43 44 ............    "ABCD"
1220 00000357:  72 0A 02 0A 07 60 ......    "r....`"
1221 
1222      188:      }
1223 
1224      190:      Method (T2)
1225 
1226 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1227 
1228      191:      {
1229      192:          EFGH ()
1230 
1231 00000364:  45 46 47 48 ............    "EFGH"
1232 
1233      193:          Add (2, 7, Local0)
1234 
1235 00000368:  72 0A 02 0A 07 60 ......    "r....`"
1236      194:      }
1237 
1238 Note that the AML code for T1 and T2 is essentially identical. When
1239 disassembling this code, the methods ABCD and EFGH must be known to the
1240 disassembler, otherwise it does not know how to handle the method invocations.
1241 
1242 In other words, if ABCD and EFGH are actually external control methods
1243 appearing in an SSDT, the disassembler does not know what to do unless
1244 the owning SSDT has been loaded via the -e option.
1245 #endif
1246 
1247 void
1248 AcpiDmUnresolvedWarning (
1249     UINT8                   Type)
1250 {
1251 
1252     if (!AcpiGbl_NumExternalMethods)
1253     {
1254         return;
1255     }
1256 
1257     if (Type)
1258     {
1259         if (!AcpiGbl_ExternalFileList)
1260         {
1261             /* The -e option was not specified */
1262 
1263            AcpiOsPrintf ("    /*\n"
1264                 "     * iASL Warning: There were %u external control methods found during\n"
1265                 "     * disassembly, but additional ACPI tables to resolve these externals\n"
1266                 "     * were not specified. This resulting disassembler output file may not\n"
1267                 "     * compile because the disassembler did not know how many arguments\n"
1268                 "     * to assign to these methods. To specify the tables needed to resolve\n"
1269                 "     * external control method references, the -e option can be used to\n"
1270                 "     * specify the filenames. Example iASL invocations:\n"
1271                 "     *     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1272                 "     *     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1273                 "     *     iasl -e ssdt*.aml -d dsdt.aml\n"
1274                 "     *\n"
1275                 "     * In addition, the -fe option can be used to specify a file containing\n"
1276                 "     * control method external declarations with the associated method\n"
1277                 "     * argument counts. Each line of the file must be of the form:\n"
1278                 "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1279                 "     * Invocation:\n"
1280                 "     *     iasl -fe refs.txt -d dsdt.aml\n"
1281                 "     *\n"
1282                 "     * The following methods were unresolved and many not compile properly\n"
1283                 "     * because the disassembler had to guess at the number of arguments\n"
1284                 "     * required for each:\n"
1285                 "     */\n",
1286                AcpiGbl_NumExternalMethods);
1287         }
1288         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1289         {
1290             /* The -e option was specified, but there are still some unresolved externals */
1291 
1292             AcpiOsPrintf ("    /*\n"
1293                 "     * iASL Warning: There were %u external control methods found during\n"
1294                 "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1295                 "     * ACPI tables may be required to properly disassemble the code. This\n"
1296                 "     * resulting disassembler output file may not compile because the\n"
1297                 "     * disassembler did not know how many arguments to assign to the\n"
1298                 "     * unresolved methods.\n"
1299                 "     *\n"
1300                 "     * If necessary, the -fe option can be used to specify a file containing\n"
1301                 "     * control method external declarations with the associated method\n"
1302                 "     * argument counts. Each line of the file must be of the form:\n"
1303                 "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1304                 "     * Invocation:\n"
1305                 "     *     iasl -fe refs.txt -d dsdt.aml\n"
1306                 "     *\n"
1307                 "     * The following methods were unresolved and many not compile properly\n"
1308                 "     * because the disassembler had to guess at the number of arguments\n"
1309                 "     * required for each:\n"
1310                 "     */\n",
1311                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1312                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1313                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1314         }
1315     }
1316     else
1317     {
1318         if (!AcpiGbl_ExternalFileList)
1319         {
1320             /* The -e option was not specified */
1321 
1322             fprintf (stderr, "\n"
1323                 "iASL Warning: There were %u external control methods found during\n"
1324                 "disassembly, but additional ACPI tables to resolve these externals\n"
1325                 "were not specified. The resulting disassembler output file may not\n"
1326                 "compile because the disassembler did not know how many arguments\n"
1327                 "to assign to these methods. To specify the tables needed to resolve\n"
1328                 "external control method references, the -e option can be used to\n"
1329                 "specify the filenames. Example iASL invocations:\n"
1330                 "    iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1331                 "    iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1332                 "    iasl -e ssdt*.aml -d dsdt.aml\n"
1333                 "\n"
1334                 "In addition, the -fe option can be used to specify a file containing\n"
1335                 "control method external declarations with the associated method\n"
1336                 "argument counts. Each line of the file must be of the form:\n"
1337                 "    External (<method pathname>, MethodObj, <argument count>)\n"
1338                 "Invocation:\n"
1339                 "    iasl -fe refs.txt -d dsdt.aml\n",
1340                 AcpiGbl_NumExternalMethods);
1341         }
1342         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1343         {
1344             /* The -e option was specified, but there are still some unresolved externals */
1345 
1346             fprintf (stderr, "\n"
1347                 "iASL Warning: There were %u external control methods found during\n"
1348                 "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1349                 "ACPI tables may be required to properly disassemble the code. The\n"
1350                 "resulting disassembler output file may not compile because the\n"
1351                 "disassembler did not know how many arguments to assign to the\n"
1352                 "unresolved methods.\n"
1353                 "\n"
1354                 "If necessary, the -fe option can be used to specify a file containing\n"
1355                 "control method external declarations with the associated method\n"
1356                 "argument counts. Each line of the file must be of the form:\n"
1357                 "    External (<method pathname>, MethodObj, <argument count>)\n"
1358                 "Invocation:\n"
1359                 "    iasl -fe refs.txt -d dsdt.aml\n",
1360                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1361                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1362                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1363         }
1364     }
1365 }
1366