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