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