1 /******************************************************************************
2  *
3  * Module Name: dmextern - Support for External() ASL statements
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 #include "acdisasm.h"
49 #include "aslcompiler.h"
50 #include <stdio.h>
51 #include <errno.h>
52 
53 
54 /*
55  * This module is used for application-level code (iASL disassembler) only.
56  *
57  * It contains the code to create and emit any necessary External() ASL
58  * statements for the module being disassembled.
59  */
60 #define _COMPONENT          ACPI_CA_DISASSEMBLER
61         ACPI_MODULE_NAME    ("dmextern")
62 
63 
64 /*
65  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
66  * ObjectTypeKeyword. Used to generate typed external declarations
67  */
68 static const char           *AcpiGbl_DmTypeNames[] =
69 {
70     /* 00 */ ", UnknownObj",        /* Type ANY */
71     /* 01 */ ", IntObj",
72     /* 02 */ ", StrObj",
73     /* 03 */ ", BuffObj",
74     /* 04 */ ", PkgObj",
75     /* 05 */ ", FieldUnitObj",
76     /* 06 */ ", DeviceObj",
77     /* 07 */ ", EventObj",
78     /* 08 */ ", MethodObj",
79     /* 09 */ ", MutexObj",
80     /* 10 */ ", OpRegionObj",
81     /* 11 */ ", PowerResObj",
82     /* 12 */ ", ProcessorObj",
83     /* 13 */ ", ThermalZoneObj",
84     /* 14 */ ", BuffFieldObj",
85     /* 15 */ ", DDBHandleObj",
86     /* 16 */ "",                    /* Debug object */
87     /* 17 */ ", FieldUnitObj",
88     /* 18 */ ", FieldUnitObj",
89     /* 19 */ ", FieldUnitObj"
90 };
91 
92 #define METHOD_SEPARATORS           " \t,()\n"
93 
94 static const char          *ExternalConflictMessage =
95     "    // Conflicts with a later declaration";
96 
97 
98 /* Local prototypes */
99 
100 static const char *
101 AcpiDmGetObjectTypeName (
102     ACPI_OBJECT_TYPE        Type);
103 
104 static char *
105 AcpiDmNormalizeParentPrefix (
106     ACPI_PARSE_OBJECT       *Op,
107     char                    *Path);
108 
109 static ACPI_STATUS
110 AcpiDmGetExternalAndInternalPath (
111     ACPI_NAMESPACE_NODE     *Node,
112     char                    **ExternalPath,
113     char                    **InternalPath);
114 
115 static ACPI_STATUS
116 AcpiDmRemoveRootPrefix (
117     char                    **Path);
118 
119 static void
120 AcpiDmAddPathToExternalList (
121     char                    *Path,
122     UINT8                   Type,
123     UINT32                  Value,
124     UINT16                  Flags);
125 
126 static ACPI_STATUS
127 AcpiDmCreateNewExternal (
128     char                    *ExternalPath,
129     char                    *InternalPath,
130     UINT8                   Type,
131     UINT32                  Value,
132     UINT16                  Flags);
133 
134 static void
135 AcpiDmCheckForExternalConflict (
136     char                    *Path);
137 
138 static ACPI_STATUS
139 AcpiDmResolveExternal (
140     char                    *Path,
141     UINT8                   Type,
142     ACPI_NAMESPACE_NODE     **Node);
143 
144 
145 static void
146 AcpiDmConflictingDeclaration (
147     char                    *Path);
148 
149 
150 /*******************************************************************************
151  *
152  * FUNCTION:    AcpiDmGetObjectTypeName
153  *
154  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
155  *
156  * RETURN:      Pointer to a string
157  *
158  * DESCRIPTION: Map an object type to the ASL object type string.
159  *
160  ******************************************************************************/
161 
162 static const char *
AcpiDmGetObjectTypeName(ACPI_OBJECT_TYPE Type)163 AcpiDmGetObjectTypeName (
164     ACPI_OBJECT_TYPE        Type)
165 {
166 
167     if (Type == ACPI_TYPE_LOCAL_SCOPE)
168     {
169         Type = ACPI_TYPE_DEVICE;
170     }
171     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
172     {
173         return ("");
174     }
175 
176     return (AcpiGbl_DmTypeNames[Type]);
177 }
178 
179 
180 /*******************************************************************************
181  *
182  * FUNCTION:    AcpiDmNormalizeParentPrefix
183  *
184  * PARAMETERS:  Op                  - Parse op
185  *              Path                - Path with parent prefix
186  *
187  * RETURN:      The full pathname to the object (from the namespace root)
188  *
189  * DESCRIPTION: Returns the full pathname of a path with parent prefix
190  *              The caller must free the fullpath returned.
191  *
192  ******************************************************************************/
193 
194 static char *
AcpiDmNormalizeParentPrefix(ACPI_PARSE_OBJECT * Op,char * Path)195 AcpiDmNormalizeParentPrefix (
196     ACPI_PARSE_OBJECT       *Op,
197     char                    *Path)
198 {
199     ACPI_NAMESPACE_NODE     *Node;
200     char                    *Fullpath;
201     char                    *ParentPath;
202     ACPI_SIZE               Length;
203     UINT32                  Index = 0;
204 
205 
206     if (!Op)
207     {
208         return (NULL);
209     }
210 
211     /* Search upwards in the parse tree until we reach the next namespace node */
212 
213     Op = Op->Common.Parent;
214     while (Op)
215     {
216         if (Op->Common.Node)
217         {
218             break;
219         }
220 
221         Op = Op->Common.Parent;
222     }
223 
224     if (!Op)
225     {
226         return (NULL);
227     }
228 
229     /*
230      * Find the actual parent node for the reference:
231      * Remove all carat prefixes from the input path.
232      * There may be multiple parent prefixes (For example, ^^^M000)
233      */
234     Node = Op->Common.Node;
235     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
236     {
237         Node = Node->Parent;
238         Path++;
239     }
240 
241     if (!Node)
242     {
243         return (NULL);
244     }
245 
246     /* Get the full pathname for the parent node */
247 
248     ParentPath = AcpiNsGetExternalPathname (Node);
249     if (!ParentPath)
250     {
251         return (NULL);
252     }
253 
254     Length = (strlen (ParentPath) + strlen (Path) + 1);
255     if (ParentPath[1])
256     {
257         /*
258          * If ParentPath is not just a simple '\', increment the length
259          * for the required dot separator (ParentPath.Path)
260          */
261         Length++;
262 
263         /* For External() statements, we do not want a leading '\' */
264 
265         if (*ParentPath == AML_ROOT_PREFIX)
266         {
267             Index = 1;
268         }
269     }
270 
271     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
272     if (!Fullpath)
273     {
274         goto Cleanup;
275     }
276 
277     /*
278      * Concatenate parent fullpath and path. For example,
279      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
280      *
281      * Copy the parent path
282      */
283     strcpy (Fullpath, &ParentPath[Index]);
284 
285     /*
286      * Add dot separator
287      * (don't need dot if parent fullpath is a single backslash)
288      */
289     if (ParentPath[1])
290     {
291         strcat (Fullpath, ".");
292     }
293 
294     /* Copy child path (carat parent prefix(es) were skipped above) */
295 
296     strcat (Fullpath, Path);
297 
298 Cleanup:
299     ACPI_FREE (ParentPath);
300     return (Fullpath);
301 }
302 
303 
304 /*******************************************************************************
305  *
306  * FUNCTION:    AcpiDmAddToExternalFileList
307  *
308  * PARAMETERS:  PathList            - Single path or list separated by comma
309  *
310  * RETURN:      None
311  *
312  * DESCRIPTION: Add external files to global list
313  *
314  ******************************************************************************/
315 
316 ACPI_STATUS
AcpiDmAddToExternalFileList(char * Pathname)317 AcpiDmAddToExternalFileList (
318     char                    *Pathname)
319 {
320     ACPI_EXTERNAL_FILE      *ExternalFile;
321     char                    *LocalPathname;
322 
323 
324     if (!Pathname)
325     {
326         return (AE_OK);
327     }
328 
329     LocalPathname = ACPI_ALLOCATE (strlen (Pathname) + 1);
330     if (!LocalPathname)
331     {
332         return (AE_NO_MEMORY);
333     }
334 
335     ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
336     if (!ExternalFile)
337     {
338         ACPI_FREE (LocalPathname);
339         return (AE_NO_MEMORY);
340     }
341 
342     /* Take a copy of the file pathname */
343 
344     strcpy (LocalPathname, Pathname);
345     ExternalFile->Path = LocalPathname;
346 
347     if (AcpiGbl_ExternalFileList)
348     {
349         ExternalFile->Next = AcpiGbl_ExternalFileList;
350     }
351 
352     AcpiGbl_ExternalFileList = ExternalFile;
353     return (AE_OK);
354 }
355 
356 
357 /*******************************************************************************
358  *
359  * FUNCTION:    AcpiDmClearExternalFileList
360  *
361  * PARAMETERS:  None
362  *
363  * RETURN:      None
364  *
365  * DESCRIPTION: Clear the external file list
366  *
367  ******************************************************************************/
368 
369 void
AcpiDmClearExternalFileList(void)370 AcpiDmClearExternalFileList (
371     void)
372 {
373     ACPI_EXTERNAL_FILE      *NextExternal;
374 
375 
376     while (AcpiGbl_ExternalFileList)
377     {
378         NextExternal = AcpiGbl_ExternalFileList->Next;
379         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
380         ACPI_FREE (AcpiGbl_ExternalFileList);
381         AcpiGbl_ExternalFileList = NextExternal;
382     }
383 }
384 
385 
386 /*******************************************************************************
387  *
388  * FUNCTION:    AcpiDmGetExternalsFromFile
389  *
390  * PARAMETERS:  None
391  *
392  * RETURN:      None
393  *
394  * DESCRIPTION: Process the optional external reference file.
395  *
396  * Each line in the file should be of the form:
397  *      External (<Method namepath>, MethodObj, <ArgCount>)
398  *
399  * Example:
400  *      External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
401  *
402  ******************************************************************************/
403 
404 void
AcpiDmGetExternalsFromFile(void)405 AcpiDmGetExternalsFromFile (
406     void)
407 {
408     FILE                    *ExternalRefFile;
409     char                    *Token;
410     char                    *MethodName;
411     UINT32                  ArgCount;
412     UINT32                  ImportCount = 0;
413 
414 
415     if (!AslGbl_ExternalRefFilename)
416     {
417         return;
418     }
419 
420     /* Open the file */
421 
422     ExternalRefFile = fopen (AslGbl_ExternalRefFilename, "r");
423     if (!ExternalRefFile)
424     {
425         fprintf (stderr, "Could not open external reference file \"%s\"\n",
426             AslGbl_ExternalRefFilename);
427         AslAbort ();
428         return;
429     }
430 
431     /* Each line defines a method */
432 
433     while (fgets (AslGbl_StringBuffer, ASL_STRING_BUFFER_SIZE, ExternalRefFile))
434     {
435         Token = strtok (AslGbl_StringBuffer, METHOD_SEPARATORS);   /* "External" */
436         if (!Token)
437         {
438             continue;
439         }
440 
441         if (strcmp (Token, "External"))
442         {
443             continue;
444         }
445 
446         MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
447         if (!MethodName)
448         {
449             continue;
450         }
451 
452         Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
453         if (!Token)
454         {
455             continue;
456         }
457 
458         if (strcmp (Token, "MethodObj"))
459         {
460             continue;
461         }
462 
463         Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
464         if (!Token)
465         {
466             continue;
467         }
468 
469         /* Convert arg count string to an integer */
470 
471         errno = 0;
472         ArgCount = strtoul (Token, NULL, 0);
473         if (errno)
474         {
475             fprintf (stderr, "Invalid argument count (%s)\n", Token);
476             continue;
477         }
478 
479         if (ArgCount > 7)
480         {
481             fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
482             continue;
483         }
484 
485         /* Add this external to the global list */
486 
487         AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
488             AslGbl_ExternalRefFilename, ArgCount, MethodName);
489 
490         AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
491             ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
492         ImportCount++;
493     }
494 
495     if (!ImportCount)
496     {
497         fprintf (stderr,
498             "Did not find any external methods in reference file \"%s\"\n",
499             AslGbl_ExternalRefFilename);
500     }
501     else
502     {
503         /* Add the external(s) to the namespace */
504 
505         AcpiDmAddExternalListToNamespace ();
506 
507         AcpiOsPrintf ("%s: Imported %u external method definitions\n",
508             AslGbl_ExternalRefFilename, ImportCount);
509     }
510 
511     fclose (ExternalRefFile);
512 }
513 
514 
515 /*******************************************************************************
516  *
517  * FUNCTION:    AcpiDmAddOpToExternalList
518  *
519  * PARAMETERS:  Op                  - Current parser Op
520  *              Path                - Internal (AML) path to the object
521  *              Type                - ACPI object type to be added
522  *              Value               - Arg count if adding a Method object
523  *              Flags               - To be passed to the external object
524  *
525  * RETURN:      None
526  *
527  * DESCRIPTION: Insert a new name into the global list of Externals which
528  *              will in turn be later emitted as an External() declaration
529  *              in the disassembled output.
530  *
531  *              This function handles the most common case where the referenced
532  *              name is simply not found in the constructed namespace.
533  *
534  ******************************************************************************/
535 
536 void
AcpiDmAddOpToExternalList(ACPI_PARSE_OBJECT * Op,char * Path,UINT8 Type,UINT32 Value,UINT16 Flags)537 AcpiDmAddOpToExternalList (
538     ACPI_PARSE_OBJECT       *Op,
539     char                    *Path,
540     UINT8                   Type,
541     UINT32                  Value,
542     UINT16                  Flags)
543 {
544     char                    *ExternalPath;
545     char                    *InternalPath = Path;
546     char                    *Temp;
547     ACPI_STATUS             Status;
548 
549 
550     ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
551 
552 
553     if (!Path)
554     {
555         return_VOID;
556     }
557 
558     /* Remove a root backslash if present */
559 
560     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
561     {
562         Path++;
563     }
564 
565     /* Externalize the pathname */
566 
567     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
568         NULL, &ExternalPath);
569     if (ACPI_FAILURE (Status))
570     {
571         return_VOID;
572     }
573 
574     /*
575      * Get the full pathname from the root if "Path" has one or more
576      * parent prefixes (^). Note: path will not contain a leading '\'.
577      */
578     if (*Path == (UINT8) AML_PARENT_PREFIX)
579     {
580         Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
581 
582         /* Set new external path */
583 
584         ACPI_FREE (ExternalPath);
585         ExternalPath = Temp;
586         if (!Temp)
587         {
588             return_VOID;
589         }
590 
591         /* Create the new internal pathname */
592 
593         Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
594         Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
595         if (ACPI_FAILURE (Status))
596         {
597             ACPI_FREE (ExternalPath);
598             return_VOID;
599         }
600     }
601 
602     /* Create the new External() declaration node */
603 
604     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
605         Type, Value, Flags);
606     if (ACPI_FAILURE (Status))
607     {
608         ACPI_FREE (ExternalPath);
609         if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
610         {
611             ACPI_FREE (InternalPath);
612         }
613     }
614 
615     return_VOID;
616 }
617 
618 
619 /*******************************************************************************
620  *
621  * FUNCTION:    AcpiDmGetExternalAndInternalPath
622  *
623  * PARAMETERS:  Node                - Namespace node for object to be added
624  *              ExternalPath        - Will contain the external path of the node
625  *              InternalPath        - Will contain the internal path of the node
626  *
627  * RETURN:      None
628  *
629  * DESCRIPTION: Get the External and Internal path from the given node.
630  *
631  ******************************************************************************/
632 
633 static ACPI_STATUS
AcpiDmGetExternalAndInternalPath(ACPI_NAMESPACE_NODE * Node,char ** ExternalPath,char ** InternalPath)634 AcpiDmGetExternalAndInternalPath (
635     ACPI_NAMESPACE_NODE     *Node,
636     char                    **ExternalPath,
637     char                    **InternalPath)
638 {
639     ACPI_STATUS             Status;
640 
641 
642     if (!Node)
643     {
644         return (AE_BAD_PARAMETER);
645     }
646 
647     /* Get the full external and internal pathnames to the node */
648 
649     *ExternalPath = AcpiNsGetExternalPathname (Node);
650     if (!*ExternalPath)
651     {
652         return (AE_BAD_PATHNAME);
653     }
654 
655     Status = AcpiNsInternalizeName (*ExternalPath, InternalPath);
656     if (ACPI_FAILURE (Status))
657     {
658         ACPI_FREE (*ExternalPath);
659         return (Status);
660     }
661 
662     return (AE_OK);
663 }
664 
665 
666 /*******************************************************************************
667  *
668  * FUNCTION:    AcpiDmRemoveRootPrefix
669  *
670  * PARAMETERS:  Path                - Remove Root prefix from this Path
671  *
672  * RETURN:      None
673  *
674  * DESCRIPTION: Remove the root prefix character '\' from Path.
675  *
676  ******************************************************************************/
677 
678 static ACPI_STATUS
AcpiDmRemoveRootPrefix(char ** Path)679 AcpiDmRemoveRootPrefix (
680     char                    **Path)
681 {
682     char                    *InputPath = *Path;
683 
684 
685     if ((*InputPath == AML_ROOT_PREFIX) && (InputPath[1]))
686     {
687         if (!memmove(InputPath, InputPath+1, strlen(InputPath)))
688         {
689             return (AE_ERROR);
690         }
691 
692         *Path = InputPath;
693     }
694 
695     return (AE_OK);
696 }
697 
698 
699 /*******************************************************************************
700  *
701  * FUNCTION:    AcpiDmAddNodeToExternalList
702  *
703  * PARAMETERS:  Node                - Namespace node for object to be added
704  *              Type                - ACPI object type to be added
705  *              Value               - Arg count if adding a Method object
706  *              Flags               - To be passed to the external object
707  *
708  * RETURN:      None
709  *
710  * DESCRIPTION: Insert a new name into the global list of Externals which
711  *              will in turn be later emitted as an External() declaration
712  *              in the disassembled output.
713  *
714  *              This function handles the case where the referenced name has
715  *              been found in the namespace, but the name originated in a
716  *              table other than the one that is being disassembled (such
717  *              as a table that is added via the iASL -e option).
718  *
719  ******************************************************************************/
720 
721 void
AcpiDmAddNodeToExternalList(ACPI_NAMESPACE_NODE * Node,UINT8 Type,UINT32 Value,UINT16 Flags)722 AcpiDmAddNodeToExternalList (
723     ACPI_NAMESPACE_NODE     *Node,
724     UINT8                   Type,
725     UINT32                  Value,
726     UINT16                  Flags)
727 {
728     char                    *ExternalPath;
729     char                    *InternalPath;
730     ACPI_STATUS             Status;
731 
732 
733     ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
734 
735     /* Get the full external and internal pathnames to the node */
736 
737     Status = AcpiDmGetExternalAndInternalPath (Node, &ExternalPath, &InternalPath);
738     if (ACPI_FAILURE (Status))
739     {
740         return_VOID;
741     }
742 
743     /* Remove the root backslash */
744 
745     Status = AcpiDmRemoveRootPrefix (&ExternalPath);
746     if (ACPI_FAILURE (Status))
747     {
748         ACPI_FREE (ExternalPath);
749         ACPI_FREE (InternalPath);
750         return_VOID;
751     }
752 
753     /* Create the new External() declaration node */
754 
755     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
756         Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
757     if (ACPI_FAILURE (Status))
758     {
759         ACPI_FREE (ExternalPath);
760         ACPI_FREE (InternalPath);
761     }
762 
763     return_VOID;
764 }
765 
766 
767 /*******************************************************************************
768  *
769  * FUNCTION:    AcpiDmAddPathToExternalList
770  *
771  * PARAMETERS:  Path                - External name of the object to be added
772  *              Type                - ACPI object type to be added
773  *              Value               - Arg count if adding a Method object
774  *              Flags               - To be passed to the external object
775  *
776  * RETURN:      None
777  *
778  * DESCRIPTION: Insert a new name into the global list of Externals which
779  *              will in turn be later emitted as an External() declaration
780  *              in the disassembled output.
781  *
782  *              This function currently is used to add externals via a
783  *              reference file (via the -fe iASL option).
784  *
785  ******************************************************************************/
786 
787 static void
AcpiDmAddPathToExternalList(char * Path,UINT8 Type,UINT32 Value,UINT16 Flags)788 AcpiDmAddPathToExternalList (
789     char                    *Path,
790     UINT8                   Type,
791     UINT32                  Value,
792     UINT16                  Flags)
793 {
794     char                    *InternalPath;
795     char                    *ExternalPath;
796     ACPI_STATUS             Status;
797 
798 
799     ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
800 
801 
802     if (!Path)
803     {
804         return_VOID;
805     }
806 
807     /* Remove a root backslash if present */
808 
809     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
810     {
811         Path++;
812     }
813 
814     /* Create the internal and external pathnames */
815 
816     Status = AcpiNsInternalizeName (Path, &InternalPath);
817     if (ACPI_FAILURE (Status))
818     {
819         return_VOID;
820     }
821 
822     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
823         NULL, &ExternalPath);
824     if (ACPI_FAILURE (Status))
825     {
826         ACPI_FREE (InternalPath);
827         return_VOID;
828     }
829 
830     /* Create the new External() declaration node */
831 
832     Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
833         Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
834     if (ACPI_FAILURE (Status))
835     {
836         ACPI_FREE (ExternalPath);
837         ACPI_FREE (InternalPath);
838     }
839 
840     return_VOID;
841 }
842 
843 
844 /*******************************************************************************
845  *
846  * FUNCTION:    AcpiDmCreateNewExternal
847  *
848  * PARAMETERS:  ExternalPath        - External path to the object
849  *              InternalPath        - Internal (AML) path to the object
850  *              Type                - ACPI object type to be added
851  *              Value               - Arg count if adding a Method object
852  *              Flags               - To be passed to the external object
853  *
854  * RETURN:      Status
855  *
856  * DESCRIPTION: Common low-level function to insert a new name into the global
857  *              list of Externals which will in turn be later emitted as
858  *              External() declarations in the disassembled output.
859  *
860  *              Note: The external name should not include a root prefix
861  *              (backslash). We do not want External() statements to contain
862  *              a leading '\', as this prevents duplicate external statements
863  *              of the form:
864  *
865  *                  External (\ABCD)
866  *                  External (ABCD)
867  *
868  *              This would cause a compile time error when the disassembled
869  *              output file is recompiled.
870  *
871  *              There are two cases that are handled here. For both, we emit
872  *              an External() statement:
873  *              1) The name was simply not found in the namespace.
874  *              2) The name was found, but it originated in a table other than
875  *              the table that is being disassembled.
876  *
877  ******************************************************************************/
878 
879 static ACPI_STATUS
AcpiDmCreateNewExternal(char * ExternalPath,char * InternalPath,UINT8 Type,UINT32 Value,UINT16 Flags)880 AcpiDmCreateNewExternal (
881     char                    *ExternalPath,
882     char                    *InternalPath,
883     UINT8                   Type,
884     UINT32                  Value,
885     UINT16                  Flags)
886 {
887     ACPI_EXTERNAL_LIST      *NewExternal;
888     ACPI_EXTERNAL_LIST      *NextExternal;
889     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
890 
891 
892     ACPI_FUNCTION_TRACE (DmCreateNewExternal);
893 
894 
895     /* Check all existing externals to ensure no duplicates */
896 
897     NextExternal = AcpiGbl_ExternalList;
898     while (NextExternal)
899     {
900         /* Check for duplicates */
901 
902         if (!strcmp (ExternalPath, NextExternal->Path))
903         {
904             /*
905              * If this external came from an External() opcode, we are
906              * finished with this one. (No need to check any further).
907              */
908             if (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE)
909             {
910                 return_ACPI_STATUS (AE_ALREADY_EXISTS);
911             }
912 
913             /* Allow upgrade of type from ANY */
914 
915             else if ((NextExternal->Type == ACPI_TYPE_ANY) &&
916                 (Type != ACPI_TYPE_ANY))
917             {
918                 NextExternal->Type = Type;
919             }
920 
921             /* Update the argument count as necessary */
922 
923             if (Value < NextExternal->Value)
924             {
925                 NextExternal->Value = Value;
926             }
927 
928             /* Update flags. */
929 
930             NextExternal->Flags |= Flags;
931             NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED;
932 
933             return_ACPI_STATUS (AE_ALREADY_EXISTS);
934         }
935 
936         NextExternal = NextExternal->Next;
937     }
938 
939     /* Allocate and init a new External() descriptor */
940 
941     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
942     if (!NewExternal)
943     {
944         return_ACPI_STATUS (AE_NO_MEMORY);
945     }
946 
947     ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
948         "Adding external reference node (%s) type [%s]\n",
949         ExternalPath, AcpiUtGetTypeName (Type)));
950 
951     NewExternal->Flags = Flags;
952     NewExternal->Value = Value;
953     NewExternal->Path = ExternalPath;
954     NewExternal->Type = Type;
955     NewExternal->Length = (UINT16) strlen (ExternalPath);
956     NewExternal->InternalPath = InternalPath;
957 
958     /* Link the new descriptor into the global list, alphabetically ordered */
959 
960     NextExternal = AcpiGbl_ExternalList;
961     while (NextExternal)
962     {
963         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
964         {
965             if (PrevExternal)
966             {
967                 PrevExternal->Next = NewExternal;
968             }
969             else
970             {
971                 AcpiGbl_ExternalList = NewExternal;
972             }
973 
974             NewExternal->Next = NextExternal;
975             return_ACPI_STATUS (AE_OK);
976         }
977 
978         PrevExternal = NextExternal;
979         NextExternal = NextExternal->Next;
980     }
981 
982     if (PrevExternal)
983     {
984         PrevExternal->Next = NewExternal;
985     }
986     else
987     {
988         AcpiGbl_ExternalList = NewExternal;
989     }
990 
991     return_ACPI_STATUS (AE_OK);
992 }
993 
994 
995 /*******************************************************************************
996  *
997  * FUNCTION:    AcpiDmResolveExternal
998  *
999  * PARAMETERS:  Path               - Path of the external
1000  *              Type               - Type of the external
1001  *              Node               - Input node for AcpiNsLookup
1002  *
1003  * RETURN:      Status
1004  *
1005  * DESCRIPTION: Resolve the external within the namespace by AcpiNsLookup.
1006  *              If the returned node is an external and has the same type
1007  *              we assume that it was either an existing external or a
1008  *
1009  ******************************************************************************/
1010 
1011 static ACPI_STATUS
AcpiDmResolveExternal(char * Path,UINT8 Type,ACPI_NAMESPACE_NODE ** Node)1012 AcpiDmResolveExternal (
1013     char                    *Path,
1014     UINT8                   Type,
1015     ACPI_NAMESPACE_NODE     **Node)
1016 {
1017     ACPI_STATUS             Status;
1018 
1019 
1020     Status = AcpiNsLookup (NULL, Path, Type,
1021         ACPI_IMODE_LOAD_PASS1,
1022         ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
1023         NULL, Node);
1024 
1025     if (!Node)
1026     {
1027         ACPI_EXCEPTION ((AE_INFO, Status,
1028             "while adding external to namespace [%s]", Path));
1029     }
1030 
1031     /* Note the asl code "external(a) external(a)" is acceptable ASL */
1032 
1033     else if ((*Node)->Type == Type &&
1034         (*Node)->Flags & ANOBJ_IS_EXTERNAL)
1035     {
1036         return (AE_OK);
1037     }
1038     else
1039     {
1040         ACPI_EXCEPTION ((AE_INFO, AE_ERROR,
1041             "[%s] has conflicting declarations", Path));
1042     }
1043 
1044     return (AE_ERROR);
1045 }
1046 
1047 
1048 /*******************************************************************************
1049  *
1050  * FUNCTION:    AcpiDmCreateSubobjectForExternal
1051  *
1052  * PARAMETERS:  Type                  - Type of the external
1053  *              Node                  - Namespace node from AcpiNsLookup
1054  *              ParamCount            - Value to be used for Method
1055  *
1056  * RETURN:      None
1057  *
1058  * DESCRIPTION: Add one external to the namespace. Allows external to be
1059  *              "resolved".
1060  *
1061  ******************************************************************************/
1062 
1063 void
AcpiDmCreateSubobjectForExternal(UINT8 Type,ACPI_NAMESPACE_NODE ** Node,UINT32 ParamCount)1064 AcpiDmCreateSubobjectForExternal (
1065     UINT8                   Type,
1066     ACPI_NAMESPACE_NODE     **Node,
1067     UINT32                  ParamCount)
1068 {
1069     ACPI_OPERAND_OBJECT     *ObjDesc;
1070 
1071 
1072     switch (Type)
1073     {
1074     case ACPI_TYPE_METHOD:
1075 
1076         /* For methods, we need to save the argument count */
1077 
1078         ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
1079         ObjDesc->Method.ParamCount = (UINT8) ParamCount;
1080         (*Node)->Object = ObjDesc;
1081         break;
1082 
1083     case ACPI_TYPE_REGION:
1084 
1085         /* Regions require a region sub-object */
1086 
1087         ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
1088         ObjDesc->Region.Node = *Node;
1089         (*Node)->Object = ObjDesc;
1090         break;
1091 
1092     default:
1093 
1094         break;
1095     }
1096 }
1097 
1098 
1099 /*******************************************************************************
1100  *
1101  * FUNCTION:    AcpiDmAddOneExternalToNamespace
1102  *
1103  * PARAMETERS:  Path                   - External parse object
1104  *              Type                   - Type of parse object
1105  *              ParamCount             - External method parameter count
1106  *
1107  * RETURN:      None
1108  *
1109  * DESCRIPTION: Add one external to the namespace by resolvign the external
1110  *              (by performing a namespace lookup) and annotating the resulting
1111  *              namespace node with the appropriate information if the type
1112  *              is ACPI_TYPE_REGION or ACPI_TYPE_METHOD.
1113  *
1114  ******************************************************************************/
1115 
1116 void
AcpiDmAddOneExternalToNamespace(char * Path,UINT8 Type,UINT32 ParamCount)1117 AcpiDmAddOneExternalToNamespace (
1118     char                    *Path,
1119     UINT8                   Type,
1120     UINT32                  ParamCount)
1121 {
1122     ACPI_STATUS             Status;
1123     ACPI_NAMESPACE_NODE     *Node;
1124 
1125 
1126     Status = AcpiDmResolveExternal (Path, Type, &Node);
1127 
1128     if (ACPI_FAILURE (Status))
1129     {
1130         return;
1131     }
1132 
1133     AcpiDmCreateSubobjectForExternal (Type, &Node, ParamCount);
1134 
1135 }
1136 
1137 
1138 /*******************************************************************************
1139  *
1140  * FUNCTION:    AcpiDmAddExternalListToNamespace
1141  *
1142  * PARAMETERS:  None
1143  *
1144  * RETURN:      None
1145  *
1146  * DESCRIPTION: Add all externals within AcpiGbl_ExternalList to the namespace.
1147  *              Allows externals to be "resolved".
1148  *
1149  ******************************************************************************/
1150 
1151 void
AcpiDmAddExternalListToNamespace(void)1152 AcpiDmAddExternalListToNamespace (
1153     void)
1154 {
1155     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
1156 
1157 
1158     while (External)
1159     {
1160         AcpiDmAddOneExternalToNamespace (External->InternalPath,
1161             External->Type, External->Value);
1162         External = External->Next;
1163     }
1164 }
1165 
1166 
1167 /*******************************************************************************
1168  *
1169  * FUNCTION:    AcpiDmGetUnresolvedExternalMethodCount
1170  *
1171  * PARAMETERS:  None
1172  *
1173  * RETURN:      The number of unresolved control method externals in the
1174  *              external list
1175  *
1176  * DESCRIPTION: Return the number of unresolved external methods that have been
1177  *              generated. If any unresolved control method externals have been
1178  *              found, we must re-parse the entire definition block with the new
1179  *              information (number of arguments for the methods.)
1180  *              This is limitation of AML, we don't know the number of arguments
1181  *              from the control method invocation itself.
1182  *
1183  *              Note: resolved external control methods are external control
1184  *              methods encoded with the AML_EXTERNAL_OP bytecode within the
1185  *              AML being disassembled.
1186  *
1187  ******************************************************************************/
1188 
1189 UINT32
AcpiDmGetUnresolvedExternalMethodCount(void)1190 AcpiDmGetUnresolvedExternalMethodCount (
1191     void)
1192 {
1193     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
1194     UINT32                  Count = 0;
1195 
1196 
1197     while (External)
1198     {
1199         if (External->Type == ACPI_TYPE_METHOD &&
1200             !(External->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE))
1201         {
1202             Count++;
1203         }
1204 
1205         External = External->Next;
1206     }
1207 
1208     return (Count);
1209 }
1210 
1211 
1212 /*******************************************************************************
1213  *
1214  * FUNCTION:    AcpiDmClearExternalList
1215  *
1216  * PARAMETERS:  None
1217  *
1218  * RETURN:      None
1219  *
1220  * DESCRIPTION: Free the entire External info list
1221  *
1222  ******************************************************************************/
1223 
1224 void
AcpiDmClearExternalList(void)1225 AcpiDmClearExternalList (
1226     void)
1227 {
1228     ACPI_EXTERNAL_LIST      *NextExternal;
1229 
1230 
1231     while (AcpiGbl_ExternalList)
1232     {
1233         NextExternal = AcpiGbl_ExternalList->Next;
1234         ACPI_FREE (AcpiGbl_ExternalList->Path);
1235         ACPI_FREE (AcpiGbl_ExternalList);
1236         AcpiGbl_ExternalList = NextExternal;
1237     }
1238 }
1239 
1240 
1241 /*******************************************************************************
1242  *
1243  * FUNCTION:    AcpiDmEmitExternals
1244  *
1245  * PARAMETERS:  None
1246  *
1247  * RETURN:      None
1248  *
1249  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1250  *              the global external info list.
1251  *
1252  ******************************************************************************/
1253 
1254 void
AcpiDmEmitExternals(void)1255 AcpiDmEmitExternals (
1256     void)
1257 {
1258     ACPI_EXTERNAL_LIST      *NextExternal;
1259 
1260 
1261     if (!AcpiGbl_ExternalList)
1262     {
1263         return;
1264     }
1265 
1266     /*
1267      * Determine the number of control methods in the external list, and
1268      * also how many of those externals were resolved via the namespace.
1269      */
1270     NextExternal = AcpiGbl_ExternalList;
1271     while (NextExternal)
1272     {
1273         if (NextExternal->Type == ACPI_TYPE_METHOD)
1274         {
1275             AcpiGbl_NumExternalMethods++;
1276             if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1277             {
1278                 AcpiGbl_ResolvedExternalMethods++;
1279             }
1280         }
1281 
1282         NextExternal = NextExternal->Next;
1283     }
1284 
1285     /* Check if any control methods were unresolved */
1286 
1287     AcpiDmUnresolvedWarning (1);
1288 
1289     if (AslGbl_ExternalRefFilename)
1290     {
1291         AcpiOsPrintf (
1292             "    /*\n     * External declarations were imported from\n"
1293             "     * a reference file -- %s\n     */\n\n",
1294             AslGbl_ExternalRefFilename);
1295     }
1296 
1297     /*
1298      * Walk and emit the list of externals found during the AML parsing
1299      */
1300     while (AcpiGbl_ExternalList)
1301     {
1302         if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1303         {
1304             AcpiOsPrintf ("    External (%s%s)",
1305                 AcpiGbl_ExternalList->Path,
1306                 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1307 
1308             /* Check for "unresolved" method reference */
1309 
1310             if ((AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) &&
1311                 (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1312             {
1313                 AcpiOsPrintf ("    // Warning: Unknown method, "
1314                     "guessing %u arguments",
1315                     AcpiGbl_ExternalList->Value);
1316             }
1317 
1318             /* Check for external from a external references file */
1319 
1320             else if (AcpiGbl_ExternalList->Flags & ACPI_EXT_ORIGIN_FROM_FILE)
1321             {
1322                 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1323                 {
1324                     AcpiOsPrintf ("    // %u Arguments",
1325                         AcpiGbl_ExternalList->Value);
1326                 }
1327 
1328                 AcpiOsPrintf ("    // From external reference file");
1329             }
1330 
1331             /* This is the normal external case */
1332 
1333             else
1334             {
1335                 /* For methods, add a comment with the number of arguments */
1336 
1337                 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1338                 {
1339                     AcpiOsPrintf ("    // %u Arguments",
1340                         AcpiGbl_ExternalList->Value);
1341                 }
1342             }
1343 
1344             if (AcpiGbl_ExternalList->Flags &= ACPI_EXT_CONFLICTING_DECLARATION)
1345             {
1346                 AcpiOsPrintf ("%s", ExternalConflictMessage);
1347                 AcpiDmConflictingDeclaration (AcpiGbl_ExternalList->Path);
1348             }
1349             AcpiOsPrintf ("\n");
1350         }
1351 
1352         /* Free this external info block and move on to next external */
1353 
1354         NextExternal = AcpiGbl_ExternalList->Next;
1355         if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1356         {
1357             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1358         }
1359 
1360         ACPI_FREE (AcpiGbl_ExternalList->Path);
1361         ACPI_FREE (AcpiGbl_ExternalList);
1362         AcpiGbl_ExternalList = NextExternal;
1363     }
1364 
1365     AcpiOsPrintf ("\n");
1366 }
1367 
1368 
1369 /*******************************************************************************
1370  *
1371  * FUNCTION:    AcpiDmMarkExternalConflict
1372  *
1373  * PARAMETERS:  Path          - Namepath to search
1374  *
1375  * RETURN:      ExternalList
1376  *
1377  * DESCRIPTION: Search the AcpiGbl_ExternalList for a matching path
1378  *
1379  ******************************************************************************/
1380 
1381 void
AcpiDmMarkExternalConflict(ACPI_NAMESPACE_NODE * Node)1382 AcpiDmMarkExternalConflict (
1383     ACPI_NAMESPACE_NODE     *Node)
1384 {
1385     ACPI_EXTERNAL_LIST      *ExternalList = AcpiGbl_ExternalList;
1386     char                    *ExternalPath;
1387     char                    *InternalPath;
1388     char                    *Temp;
1389     ACPI_STATUS             Status;
1390 
1391 
1392     ACPI_FUNCTION_TRACE (DmMarkExternalConflict);
1393 
1394 
1395     if (Node->Flags & ANOBJ_IS_EXTERNAL)
1396     {
1397         return_VOID;
1398     }
1399 
1400     /* Get the full external and internal pathnames to the node */
1401 
1402     Status = AcpiDmGetExternalAndInternalPath (Node,
1403         &ExternalPath, &InternalPath);
1404     if (ACPI_FAILURE (Status))
1405     {
1406         return_VOID;
1407     }
1408 
1409     /* Remove the root backslash */
1410 
1411     Status = AcpiDmRemoveRootPrefix (&InternalPath);
1412     if (ACPI_FAILURE (Status))
1413     {
1414         ACPI_FREE (InternalPath);
1415         ACPI_FREE (ExternalPath);
1416         return_VOID;
1417     }
1418 
1419     while (ExternalList)
1420     {
1421         Temp = ExternalList->InternalPath;
1422         if ((*ExternalList->InternalPath == AML_ROOT_PREFIX) &&
1423             (ExternalList->InternalPath[1]))
1424         {
1425             Temp++;
1426         }
1427 
1428         if (!strcmp (ExternalList->InternalPath, InternalPath))
1429         {
1430             ExternalList->Flags |= ACPI_EXT_CONFLICTING_DECLARATION;
1431         }
1432         ExternalList = ExternalList->Next;
1433     }
1434 
1435     ACPI_FREE (InternalPath);
1436     ACPI_FREE (ExternalPath);
1437 
1438     return_VOID;
1439 }
1440 
1441 
1442 /*******************************************************************************
1443  *
1444  * FUNCTION:    AcpiDmConflictingDeclaration
1445  *
1446  * PARAMETERS:  Path                - Path with conflicting declaration
1447  *
1448  * RETURN:      None
1449  *
1450  * DESCRIPTION: Emit a warning when printing conflicting ASL external
1451  *              declarations.
1452  *
1453  ******************************************************************************/
1454 
1455 static void
AcpiDmConflictingDeclaration(char * Path)1456 AcpiDmConflictingDeclaration (
1457     char                    *Path)
1458 {
1459     fprintf (stderr,
1460         " Warning - Emitting ASL code \"External (%s)\"\n"
1461         "           This is a conflicting declaration with some "
1462         "other declaration within the ASL code.\n"
1463         "           This external declaration may need to be "
1464         "deleted in order to recompile the dsl file.\n\n",
1465         Path);
1466 }
1467 
1468 
1469 /*******************************************************************************
1470  *
1471  * FUNCTION:    AcpiDmEmitExternal
1472  *
1473  * PARAMETERS:  Op                  External Parse Object
1474  *
1475  * RETURN:      None
1476  *
1477  * DESCRIPTION: Emit an External() ASL statement for the current External
1478  *              parse object. Note: External Ops are named types so the
1479  *              namepath is contained within NameOp->Name.Path.
1480  *
1481  ******************************************************************************/
1482 
1483 void
AcpiDmEmitExternal(ACPI_PARSE_OBJECT * NameOp,ACPI_PARSE_OBJECT * TypeOp)1484 AcpiDmEmitExternal (
1485     ACPI_PARSE_OBJECT       *NameOp,
1486     ACPI_PARSE_OBJECT       *TypeOp)
1487 {
1488     AcpiOsPrintf ("External (");
1489     AcpiDmNamestring (NameOp->Named.Path);
1490     AcpiOsPrintf ("%s)",
1491         AcpiDmGetObjectTypeName ((ACPI_OBJECT_TYPE) TypeOp->Common.Value.Integer));
1492     AcpiDmCheckForExternalConflict (NameOp->Named.Path);
1493     AcpiOsPrintf ("\n");
1494 }
1495 
1496 
1497 /*******************************************************************************
1498  *
1499  * FUNCTION:    AcpiDmCheckForExternalConflict
1500  *
1501  * PARAMETERS:  Path                - Path to check
1502  *
1503  * RETURN:      None
1504  *
1505  * DESCRIPTION: Search the External List to see if the input Path has a
1506  *              conflicting declaration.
1507  *
1508  ******************************************************************************/
1509 
1510 static void
AcpiDmCheckForExternalConflict(char * Path)1511 AcpiDmCheckForExternalConflict (
1512     char                    *Path)
1513 {
1514     ACPI_EXTERNAL_LIST      *ExternalList = AcpiGbl_ExternalList;
1515     char                    *ListItemPath;
1516     char                    *InputPath;
1517 
1518 
1519     if (!Path)
1520     {
1521         return;
1522     }
1523 
1524     /* Move past the root prefix '\' */
1525 
1526     InputPath = Path;
1527     if ((*InputPath == AML_ROOT_PREFIX) && InputPath[1])
1528     {
1529         InputPath++;
1530     }
1531 
1532     while (ExternalList)
1533     {
1534         ListItemPath = ExternalList->Path;
1535         if (ListItemPath)
1536         {
1537             /* Move past the root prefix '\' */
1538 
1539             if ((*ListItemPath == AML_ROOT_PREFIX) &&
1540                 ListItemPath[1])
1541             {
1542                 ListItemPath++;
1543             }
1544 
1545             if (!strcmp (ListItemPath, InputPath) &&
1546                 (ExternalList->Flags & ACPI_EXT_CONFLICTING_DECLARATION))
1547             {
1548                 AcpiOsPrintf ("%s", ExternalConflictMessage);
1549                 AcpiDmConflictingDeclaration (Path);
1550 
1551                 return;
1552             }
1553         }
1554         ExternalList = ExternalList->Next;
1555     }
1556 }
1557 /*******************************************************************************
1558  *
1559  * FUNCTION:    AcpiDmUnresolvedWarning
1560  *
1561  * PARAMETERS:  Type                - Where to output the warning.
1562  *                                    0 means write to stderr
1563  *                                    1 means write to AcpiOsPrintf
1564  *
1565  * RETURN:      None
1566  *
1567  * DESCRIPTION: Issue warning message if there are unresolved external control
1568  *              methods within the disassembly.
1569  *
1570  ******************************************************************************/
1571 
1572 /*
1573 Summary of the external control method problem:
1574 
1575 When the -e option is used with disassembly, the various SSDTs are simply
1576 loaded into a global namespace for the disassembler to use in order to
1577 resolve control method references (invocations).
1578 
1579 The disassembler tracks any such references, and will emit an External()
1580 statement for these types of methods, with the proper number of arguments .
1581 
1582 Without the SSDTs, the AML does not contain enough information to properly
1583 disassemble the control method invocation -- because the disassembler does
1584 not know how many arguments to parse.
1585 
1586 An example: Assume we have two control methods. ABCD has one argument, and
1587 EFGH has zero arguments. Further, we have two additional control methods
1588 that invoke ABCD and EFGH, named T1 and T2:
1589 
1590     Method (ABCD, 1)
1591     {
1592     }
1593     Method (EFGH, 0)
1594     {
1595     }
1596     Method (T1)
1597     {
1598         ABCD (Add (2, 7, Local0))
1599     }
1600     Method (T2)
1601     {
1602         EFGH ()
1603         Add (2, 7, Local0)
1604     }
1605 
1606 Here is the AML code that is generated for T1 and T2:
1607 
1608      185:      Method (T1)
1609 
1610 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1611 
1612      186:      {
1613      187:          ABCD (Add (2, 7, Local0))
1614 
1615 00000353:  41 42 43 44 ............    "ABCD"
1616 00000357:  72 0A 02 0A 07 60 ......    "r....`"
1617 
1618      188:      }
1619 
1620      190:      Method (T2)
1621 
1622 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1623 
1624      191:      {
1625      192:          EFGH ()
1626 
1627 00000364:  45 46 47 48 ............    "EFGH"
1628 
1629      193:          Add (2, 7, Local0)
1630 
1631 00000368:  72 0A 02 0A 07 60 ......    "r....`"
1632      194:      }
1633 
1634 Note that the AML code for T1 and T2 is essentially identical. When
1635 disassembling this code, the methods ABCD and EFGH must be known to the
1636 disassembler, otherwise it does not know how to handle the method invocations.
1637 
1638 In other words, if ABCD and EFGH are actually external control methods
1639 appearing in an SSDT, the disassembler does not know what to do unless
1640 the owning SSDT has been loaded via the -e option.
1641 */
1642 
1643 static char             ExternalWarningPart1[600];
1644 static char             ExternalWarningPart2[400];
1645 static char             ExternalWarningPart3[400];
1646 static char             ExternalWarningPart4[200];
1647 
1648 void
AcpiDmUnresolvedWarning(UINT8 Type)1649 AcpiDmUnresolvedWarning (
1650     UINT8                   Type)
1651 {
1652     char                    *Format;
1653     char                    Pad[] = "     *";
1654     char                    NoPad[] = "";
1655 
1656 
1657     if (!AcpiGbl_NumExternalMethods)
1658     {
1659         return;
1660     }
1661 
1662     if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
1663     {
1664         return;
1665     }
1666 
1667     Format = Type ? Pad : NoPad;
1668 
1669     sprintf (ExternalWarningPart1,
1670         "%s iASL Warning: There %s %u external control method%s found during\n"
1671         "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1672         "%s ACPI tables may be required to properly disassemble the code. This\n"
1673         "%s resulting disassembler output file may not compile because the\n"
1674         "%s disassembler did not know how many arguments to assign to the\n"
1675         "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1676         "%s runtime and may or may not be available via the host OS.\n",
1677         Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
1678         AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
1679         Format, AcpiGbl_ResolvedExternalMethods,
1680         (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
1681         (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
1682         Format, Format, Format, Format, Format);
1683 
1684     sprintf (ExternalWarningPart2,
1685         "%s To specify the tables needed to resolve external control method\n"
1686         "%s references, the -e option can be used to specify the filenames.\n"
1687         "%s Example iASL invocations:\n"
1688         "%s     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1689         "%s     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1690         "%s     iasl -e ssdt*.aml -d dsdt.aml\n",
1691         Format, Format, Format, Format, Format, Format);
1692 
1693     sprintf (ExternalWarningPart3,
1694         "%s In addition, the -fe option can be used to specify a file containing\n"
1695         "%s control method external declarations with the associated method\n"
1696         "%s argument counts. Each line of the file must be of the form:\n"
1697         "%s     External (<method pathname>, MethodObj, <argument count>)\n"
1698         "%s Invocation:\n"
1699         "%s     iasl -fe refs.txt -d dsdt.aml\n",
1700         Format, Format, Format, Format, Format, Format);
1701 
1702     sprintf (ExternalWarningPart4,
1703         "%s The following methods were unresolved and many not compile properly\n"
1704         "%s because the disassembler had to guess at the number of arguments\n"
1705         "%s required for each:\n",
1706         Format, Format, Format);
1707 
1708     if (Type)
1709     {
1710         if (!AcpiGbl_ExternalFileList)
1711         {
1712             /* The -e option was not specified */
1713 
1714            AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     *\n%s     */\n",
1715                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
1716                ExternalWarningPart4);
1717         }
1718         else
1719         {
1720             /* The -e option was specified, but there are still some unresolved externals */
1721 
1722             AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     */\n",
1723                ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
1724         }
1725     }
1726     else
1727     {
1728         if (!AcpiGbl_ExternalFileList)
1729         {
1730             /* The -e option was not specified */
1731 
1732             fprintf (stderr, "\n%s\n%s\n%s\n",
1733                ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
1734         }
1735         else
1736         {
1737             /* The -e option was specified, but there are still some unresolved externals */
1738 
1739             fprintf (stderr, "\n%s\n%s\n",
1740                ExternalWarningPart1, ExternalWarningPart3);
1741         }
1742     }
1743 }
1744