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