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