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