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