xref: /freebsd/sys/contrib/dev/acpica/common/dmextern.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
1 /******************************************************************************
2  *
3  * Module Name: dmextern - Support for External() ASL statements
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/amlcode.h>
47 #include <contrib/dev/acpica/include/acnamesp.h>
48 #include <contrib/dev/acpica/include/acdisasm.h>
49 #include <stdio.h>
50 
51 
52 /*
53  * This module is used for application-level code (iASL disassembler) only.
54  *
55  * It contains the code to create and emit any necessary External() ASL
56  * statements for the module being disassembled.
57  */
58 #define _COMPONENT          ACPI_CA_DISASSEMBLER
59         ACPI_MODULE_NAME    ("dmextern")
60 
61 
62 /*
63  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
64  * ObjectTypeKeyword. Used to generate typed external declarations
65  */
66 static const char           *AcpiGbl_DmTypeNames[] =
67 {
68     /* 00 */ "",                    /* Type ANY */
69     /* 01 */ ", IntObj",
70     /* 02 */ ", StrObj",
71     /* 03 */ ", BuffObj",
72     /* 04 */ ", PkgObj",
73     /* 05 */ ", FieldUnitObj",
74     /* 06 */ ", DeviceObj",
75     /* 07 */ ", EventObj",
76     /* 08 */ ", MethodObj",
77     /* 09 */ ", MutexObj",
78     /* 10 */ ", OpRegionObj",
79     /* 11 */ ", PowerResObj",
80     /* 12 */ ", ProcessorObj",
81     /* 13 */ ", ThermalZoneObj",
82     /* 14 */ ", BuffFieldObj",
83     /* 15 */ ", DDBHandleObj",
84     /* 16 */ "",                    /* Debug object */
85     /* 17 */ ", FieldUnitObj",
86     /* 18 */ ", FieldUnitObj",
87     /* 19 */ ", FieldUnitObj"
88 };
89 
90 
91 /* Local prototypes */
92 
93 static const char *
94 AcpiDmGetObjectTypeName (
95     ACPI_OBJECT_TYPE        Type);
96 
97 static char *
98 AcpiDmNormalizeParentPrefix (
99     ACPI_PARSE_OBJECT       *Op,
100     char                    *Path);
101 
102 
103 /*******************************************************************************
104  *
105  * FUNCTION:    AcpiDmGetObjectTypeName
106  *
107  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
108  *
109  * RETURN:      Pointer to a string
110  *
111  * DESCRIPTION: Map an object type to the ASL object type string.
112  *
113  ******************************************************************************/
114 
115 static const char *
116 AcpiDmGetObjectTypeName (
117     ACPI_OBJECT_TYPE        Type)
118 {
119 
120     if (Type == ACPI_TYPE_LOCAL_SCOPE)
121     {
122         Type = ACPI_TYPE_DEVICE;
123     }
124 
125     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
126     {
127         return ("");
128     }
129 
130     return (AcpiGbl_DmTypeNames[Type]);
131 }
132 
133 
134 /*******************************************************************************
135  *
136  * FUNCTION:    AcpiDmNormalizeParentPrefix
137  *
138  * PARAMETERS:  Op                  - Parse op
139  *              Path                - Path with parent prefix
140  *
141  * RETURN:      The full pathname to the object (from the namespace root)
142  *
143  * DESCRIPTION: Returns the full pathname of a path with parent prefix
144  *              The caller must free the fullpath returned.
145  *
146  ******************************************************************************/
147 
148 static char *
149 AcpiDmNormalizeParentPrefix (
150     ACPI_PARSE_OBJECT       *Op,
151     char                    *Path)
152 {
153     ACPI_NAMESPACE_NODE     *Node;
154     char                    *Fullpath;
155     char                    *ParentPath;
156     ACPI_SIZE               Length;
157     UINT32                  Index = 0;
158 
159 
160     if (!Op)
161     {
162         return (NULL);
163     }
164 
165     /* Search upwards in the parse tree until we reach the next namespace node */
166 
167     Op = Op->Common.Parent;
168     while (Op)
169     {
170         if (Op->Common.Node)
171         {
172             break;
173         }
174 
175         Op = Op->Common.Parent;
176     }
177 
178     if (!Op)
179     {
180         return (NULL);
181     }
182 
183     /*
184      * Find the actual parent node for the reference:
185      * Remove all carat prefixes from the input path.
186      * There may be multiple parent prefixes (For example, ^^^M000)
187      */
188     Node = Op->Common.Node;
189     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
190     {
191         Node = Node->Parent;
192         Path++;
193     }
194 
195     if (!Node)
196     {
197         return (NULL);
198     }
199 
200     /* Get the full pathname for the parent node */
201 
202     ParentPath = AcpiNsGetExternalPathname (Node);
203     if (!ParentPath)
204     {
205         return (NULL);
206     }
207 
208     Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
209     if (ParentPath[1])
210     {
211         /*
212          * If ParentPath is not just a simple '\', increment the length
213          * for the required dot separator (ParentPath.Path)
214          */
215         Length++;
216 
217         /* For External() statements, we do not want a leading '\' */
218 
219         if (*ParentPath == AML_ROOT_PREFIX)
220         {
221             Index = 1;
222         }
223     }
224 
225     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
226     if (!Fullpath)
227     {
228         goto Cleanup;
229     }
230 
231     /*
232      * Concatenate parent fullpath and path. For example,
233      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
234      *
235      * Copy the parent path
236      */
237     ACPI_STRCPY (Fullpath, &ParentPath[Index]);
238 
239     /*
240      * Add dot separator
241      * (don't need dot if parent fullpath is a single backslash)
242      */
243     if (ParentPath[1])
244     {
245         ACPI_STRCAT (Fullpath, ".");
246     }
247 
248     /* Copy child path (carat parent prefix(es) were skipped above) */
249 
250     ACPI_STRCAT (Fullpath, Path);
251 
252 Cleanup:
253     ACPI_FREE (ParentPath);
254     return (Fullpath);
255 }
256 
257 
258 /*******************************************************************************
259  *
260  * FUNCTION:    AcpiDmAddToExternalFileList
261  *
262  * PARAMETERS:  PathList            - Single path or list separated by comma
263  *
264  * RETURN:      None
265  *
266  * DESCRIPTION: Add external files to global list
267  *
268  ******************************************************************************/
269 
270 ACPI_STATUS
271 AcpiDmAddToExternalFileList (
272     char                    *PathList)
273 {
274     ACPI_EXTERNAL_FILE      *ExternalFile;
275     char                    *Path;
276     char                    *TmpPath;
277 
278 
279     if (!PathList)
280     {
281         return (AE_OK);
282     }
283 
284     Path = strtok (PathList, ",");
285 
286     while (Path)
287     {
288         TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
289         if (!TmpPath)
290         {
291             return (AE_NO_MEMORY);
292         }
293 
294         ACPI_STRCPY (TmpPath, Path);
295 
296         ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
297         if (!ExternalFile)
298         {
299             ACPI_FREE (TmpPath);
300             return (AE_NO_MEMORY);
301         }
302 
303         ExternalFile->Path = TmpPath;
304 
305         if (AcpiGbl_ExternalFileList)
306         {
307             ExternalFile->Next = AcpiGbl_ExternalFileList;
308         }
309 
310         AcpiGbl_ExternalFileList = ExternalFile;
311         Path = strtok (NULL, ",");
312     }
313 
314     return (AE_OK);
315 }
316 
317 
318 /*******************************************************************************
319  *
320  * FUNCTION:    AcpiDmClearExternalFileList
321  *
322  * PARAMETERS:  None
323  *
324  * RETURN:      None
325  *
326  * DESCRIPTION: Clear the external file list
327  *
328  ******************************************************************************/
329 
330 void
331 AcpiDmClearExternalFileList (
332     void)
333 {
334     ACPI_EXTERNAL_FILE      *NextExternal;
335 
336 
337     while (AcpiGbl_ExternalFileList)
338     {
339         NextExternal = AcpiGbl_ExternalFileList->Next;
340         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
341         ACPI_FREE (AcpiGbl_ExternalFileList);
342         AcpiGbl_ExternalFileList = NextExternal;
343     }
344 }
345 
346 
347 /*******************************************************************************
348  *
349  * FUNCTION:    AcpiDmAddToExternalList
350  *
351  * PARAMETERS:  Op                  - Current parser Op
352  *              Path                - Internal (AML) path to the object
353  *              Type                - ACPI object type to be added
354  *              Value               - Arg count if adding a Method object
355  *
356  * RETURN:      None
357  *
358  * DESCRIPTION: Insert a new name into the global list of Externals which
359  *              will in turn be later emitted as an External() declaration
360  *              in the disassembled output.
361  *
362  ******************************************************************************/
363 
364 void
365 AcpiDmAddToExternalList (
366     ACPI_PARSE_OBJECT       *Op,
367     char                    *Path,
368     UINT8                   Type,
369     UINT32                  Value)
370 {
371     char                    *ExternalPath;
372     char                    *Fullpath = NULL;
373     ACPI_EXTERNAL_LIST      *NewExternal;
374     ACPI_EXTERNAL_LIST      *NextExternal;
375     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
376     ACPI_STATUS             Status;
377     BOOLEAN                 Resolved = FALSE;
378 
379 
380     if (!Path)
381     {
382         return;
383     }
384 
385     if (Type == ACPI_TYPE_METHOD)
386     {
387         if (Value & 0x80)
388         {
389             Resolved = TRUE;
390         }
391         Value &= 0x07;
392     }
393 
394     /*
395      * We don't want External() statements to contain a leading '\'.
396      * This prevents duplicate external statements of the form:
397      *
398      *    External (\ABCD)
399      *    External (ABCD)
400      *
401      * This would cause a compile time error when the disassembled
402      * output file is recompiled.
403      */
404     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
405     {
406         Path++;
407     }
408 
409     /* Externalize the ACPI pathname */
410 
411     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
412                 NULL, &ExternalPath);
413     if (ACPI_FAILURE (Status))
414     {
415         return;
416     }
417 
418     /*
419      * Get the full pathname from the root if "Path" has one or more
420      * parent prefixes (^). Note: path will not contain a leading '\'.
421      */
422     if (*Path == (UINT8) AML_PARENT_PREFIX)
423     {
424         Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
425         if (Fullpath)
426         {
427             /* Set new external path */
428 
429             ACPI_FREE (ExternalPath);
430             ExternalPath = Fullpath;
431         }
432     }
433 
434     /* Check all existing externals to ensure no duplicates */
435 
436     NextExternal = AcpiGbl_ExternalList;
437     while (NextExternal)
438     {
439         if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
440         {
441             /* Duplicate method, check that the Value (ArgCount) is the same */
442 
443             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
444                 (NextExternal->Value != Value))
445             {
446                 ACPI_ERROR ((AE_INFO,
447                     "Argument count mismatch for method %s %u %u",
448                     NextExternal->Path, NextExternal->Value, Value));
449             }
450 
451             /* Allow upgrade of type from ANY */
452 
453             else if (NextExternal->Type == ACPI_TYPE_ANY)
454             {
455                 NextExternal->Type = Type;
456                 NextExternal->Value = Value;
457             }
458 
459             ACPI_FREE (ExternalPath);
460             return;
461         }
462 
463         NextExternal = NextExternal->Next;
464     }
465 
466     /* Allocate and init a new External() descriptor */
467 
468     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
469     if (!NewExternal)
470     {
471         ACPI_FREE (ExternalPath);
472         return;
473     }
474 
475     NewExternal->Path = ExternalPath;
476     NewExternal->Type = Type;
477     NewExternal->Value = Value;
478     NewExternal->Resolved = Resolved;
479     NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
480 
481     /* Was the external path with parent prefix normalized to a fullpath? */
482 
483     if (Fullpath == ExternalPath)
484     {
485         /* Get new internal path */
486 
487         Status = AcpiNsInternalizeName (ExternalPath, &Path);
488         if (ACPI_FAILURE (Status))
489         {
490             ACPI_FREE (ExternalPath);
491             ACPI_FREE (NewExternal);
492             return;
493         }
494 
495         /* Set flag to indicate External->InternalPath need to be freed */
496 
497         NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
498     }
499 
500     NewExternal->InternalPath = Path;
501 
502     /* Link the new descriptor into the global list, alphabetically ordered */
503 
504     NextExternal = AcpiGbl_ExternalList;
505     while (NextExternal)
506     {
507         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
508         {
509             if (PrevExternal)
510             {
511                 PrevExternal->Next = NewExternal;
512             }
513             else
514             {
515                 AcpiGbl_ExternalList = NewExternal;
516             }
517 
518             NewExternal->Next = NextExternal;
519             return;
520         }
521 
522         PrevExternal = NextExternal;
523         NextExternal = NextExternal->Next;
524     }
525 
526     if (PrevExternal)
527     {
528         PrevExternal->Next = NewExternal;
529     }
530     else
531     {
532         AcpiGbl_ExternalList = NewExternal;
533     }
534 }
535 
536 
537 /*******************************************************************************
538  *
539  * FUNCTION:    AcpiDmAddExternalsToNamespace
540  *
541  * PARAMETERS:  None
542  *
543  * RETURN:      None
544  *
545  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
546  *              "resolved".
547  *
548  ******************************************************************************/
549 
550 void
551 AcpiDmAddExternalsToNamespace (
552     void)
553 {
554     ACPI_STATUS             Status;
555     ACPI_NAMESPACE_NODE     *Node;
556     ACPI_OPERAND_OBJECT     *ObjDesc;
557     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
558 
559 
560     while (External)
561     {
562         /* Add the external name (object) into the namespace */
563 
564         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
565                    ACPI_IMODE_LOAD_PASS1,
566                    ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
567                    NULL, &Node);
568 
569         if (ACPI_FAILURE (Status))
570         {
571             ACPI_EXCEPTION ((AE_INFO, Status,
572                 "while adding external to namespace [%s]",
573                 External->Path));
574         }
575 
576         else switch (External->Type)
577         {
578         case ACPI_TYPE_METHOD:
579 
580             /* For methods, we need to save the argument count */
581 
582             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
583             ObjDesc->Method.ParamCount = (UINT8) External->Value;
584             Node->Object = ObjDesc;
585             break;
586 
587         case ACPI_TYPE_REGION:
588 
589             /* Regions require a region sub-object */
590 
591             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
592             ObjDesc->Region.Node = Node;
593             Node->Object = ObjDesc;
594             break;
595 
596         default:
597             break;
598         }
599 
600         External = External->Next;
601     }
602 }
603 
604 
605 /*******************************************************************************
606  *
607  * FUNCTION:    AcpiDmGetExternalMethodCount
608  *
609  * PARAMETERS:  None
610  *
611  * RETURN:      The number of control method externals in the external list
612  *
613  * DESCRIPTION: Return the number of method externals that have been generated.
614  *              If any control method externals have been found, we must
615  *              re-parse the entire definition block with the new information
616  *              (number of arguments for the methods.) This is limitation of
617  *              AML, we don't know the number of arguments from the control
618  *              method invocation itself.
619  *
620  ******************************************************************************/
621 
622 UINT32
623 AcpiDmGetExternalMethodCount (
624     void)
625 {
626     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
627     UINT32                  Count = 0;
628 
629 
630     while (External)
631     {
632         if (External->Type == ACPI_TYPE_METHOD)
633         {
634             Count++;
635         }
636 
637         External = External->Next;
638     }
639 
640     return (Count);
641 }
642 
643 
644 /*******************************************************************************
645  *
646  * FUNCTION:    AcpiDmClearExternalList
647  *
648  * PARAMETERS:  None
649  *
650  * RETURN:      None
651  *
652  * DESCRIPTION: Free the entire External info list
653  *
654  ******************************************************************************/
655 
656 void
657 AcpiDmClearExternalList (
658     void)
659 {
660     ACPI_EXTERNAL_LIST      *NextExternal;
661 
662 
663     while (AcpiGbl_ExternalList)
664     {
665         NextExternal = AcpiGbl_ExternalList->Next;
666         ACPI_FREE (AcpiGbl_ExternalList->Path);
667         ACPI_FREE (AcpiGbl_ExternalList);
668         AcpiGbl_ExternalList = NextExternal;
669     }
670 }
671 
672 
673 /*******************************************************************************
674  *
675  * FUNCTION:    AcpiDmEmitExternals
676  *
677  * PARAMETERS:  None
678  *
679  * RETURN:      None
680  *
681  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
682  *              the global external info list.
683  *
684  ******************************************************************************/
685 
686 void
687 AcpiDmEmitExternals (
688     void)
689 {
690     ACPI_EXTERNAL_LIST      *NextExternal;
691 
692 
693     if (!AcpiGbl_ExternalList)
694     {
695         return;
696     }
697 
698     /*
699      * Determine the number of control methods in the external list, and
700      * also how many of those externals were resolved via the namespace.
701      */
702     NextExternal = AcpiGbl_ExternalList;
703     while (NextExternal)
704     {
705         if (NextExternal->Type == ACPI_TYPE_METHOD)
706         {
707             AcpiGbl_NumExternalMethods++;
708             if (NextExternal->Resolved)
709             {
710                 AcpiGbl_ResolvedExternalMethods++;
711             }
712         }
713 
714         NextExternal = NextExternal->Next;
715     }
716 
717     /* Check if any control methods were unresolved */
718 
719     AcpiDmUnresolvedWarning (1);
720 
721     /*
722      * Walk the list of externals (unresolved references)
723      * found during the AML parsing
724      */
725     while (AcpiGbl_ExternalList)
726     {
727         AcpiOsPrintf ("    External (%s%s",
728             AcpiGbl_ExternalList->Path,
729             AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
730 
731         if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
732         {
733             if (AcpiGbl_ExternalList->Resolved)
734             {
735                 AcpiOsPrintf (")    // %u Arguments\n",
736                     AcpiGbl_ExternalList->Value);
737             }
738             else
739             {
740                 AcpiOsPrintf (")    // Warning: unresolved Method, "
741                     "assuming %u arguments (may be incorrect, see warning above)\n",
742                     AcpiGbl_ExternalList->Value);
743             }
744         }
745         else
746         {
747             AcpiOsPrintf (")\n");
748         }
749 
750         /* Free this external info block and move on to next external */
751 
752         NextExternal = AcpiGbl_ExternalList->Next;
753         if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
754         {
755             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
756         }
757 
758         ACPI_FREE (AcpiGbl_ExternalList->Path);
759         ACPI_FREE (AcpiGbl_ExternalList);
760         AcpiGbl_ExternalList = NextExternal;
761     }
762 
763     AcpiOsPrintf ("\n");
764 }
765 
766 
767 /*******************************************************************************
768  *
769  * FUNCTION:    AcpiDmUnresolvedWarning
770  *
771  * PARAMETERS:  Type                - Where to output the warning.
772  *                                    0 means write to stderr
773  *                                    1 means write to AcpiOsPrintf
774  *
775  * RETURN:      None
776  *
777  * DESCRIPTION: Issue warning message if there are unresolved external control
778  *              methods within the disassembly.
779  *
780  ******************************************************************************/
781 
782 #if 0
783 Summary of the external control method problem:
784 
785 When the -e option is used with disassembly, the various SSDTs are simply
786 loaded into a global namespace for the disassembler to use in order to
787 resolve control method references (invocations).
788 
789 The disassembler tracks any such references, and will emit an External()
790 statement for these types of methods, with the proper number of arguments .
791 
792 Without the SSDTs, the AML does not contain enough information to properly
793 disassemble the control method invocation -- because the disassembler does
794 not know how many arguments to parse.
795 
796 An example: Assume we have two control methods. ABCD has one argument, and
797 EFGH has zero arguments. Further, we have two additional control methods
798 that invoke ABCD and EFGH, named T1 and T2:
799 
800     Method (ABCD, 1)
801     {
802     }
803     Method (EFGH, 0)
804     {
805     }
806     Method (T1)
807     {
808         ABCD (Add (2, 7, Local0))
809     }
810     Method (T2)
811     {
812         EFGH ()
813         Add (2, 7, Local0)
814     }
815 
816 Here is the AML code that is generated for T1 and T2:
817 
818      185:      Method (T1)
819 
820 0000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
821 
822      186:      {
823      187:          ABCD (Add (2, 7, Local0))
824 
825 00000353:  41 42 43 44 ............    "ABCD"
826 00000357:  72 0A 02 0A 07 60 ......    "r....`"
827 
828      188:      }
829 
830      190:      Method (T2)
831 
832 0000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
833 
834      191:      {
835      192:          EFGH ()
836 
837 00000364:  45 46 47 48 ............    "EFGH"
838 
839      193:          Add (2, 7, Local0)
840 
841 00000368:  72 0A 02 0A 07 60 ......    "r....`"
842      194:      }
843 
844 Note that the AML code for T1 and T2 is essentially identical. When
845 disassembling this code, the methods ABCD and EFGH must be known to the
846 disassembler, otherwise it does not know how to handle the method invocations.
847 
848 In other words, if ABCD and EFGH are actually external control methods
849 appearing in an SSDT, the disassembler does not know what to do unless
850 the owning SSDT has been loaded via the -e option.
851 #endif
852 
853 void
854 AcpiDmUnresolvedWarning (
855     UINT8                   Type)
856 {
857 
858     if (!AcpiGbl_NumExternalMethods)
859     {
860         return;
861     }
862 
863     if (Type)
864     {
865         if (!AcpiGbl_ExternalFileList)
866         {
867             /* The -e option was not specified */
868 
869            AcpiOsPrintf ("    /*\n"
870                 "     * iASL Warning: There were %u external control methods found during\n"
871                 "     * disassembly, but additional ACPI tables to resolve these externals\n"
872                 "     * were not specified. This resulting disassembler output file may not\n"
873                 "     * compile because the disassembler did not know how many arguments\n"
874                 "     * to assign to these methods. To specify the tables needed to resolve\n"
875                 "     * external control method references, use the one of the following\n"
876                 "     * example iASL invocations:\n"
877                 "     *     iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
878                 "     *     iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n"
879                 "     */\n",
880                 AcpiGbl_NumExternalMethods);
881         }
882         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
883         {
884             /* The -e option was specified, but there are still some unresolved externals */
885 
886             AcpiOsPrintf ("    /*\n"
887                 "     * iASL Warning: There were %u external control methods found during\n"
888                 "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
889                 "     * ACPI tables are required to properly disassemble the code. This\n"
890                 "     * resulting disassembler output file may not compile because the\n"
891                 "     * disassembler did not know how many arguments to assign to the\n"
892                 "     * unresolved methods.\n"
893                 "     */\n",
894                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
895                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
896                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
897         }
898     }
899     else
900     {
901         if (!AcpiGbl_ExternalFileList)
902         {
903             /* The -e option was not specified */
904 
905             fprintf (stderr, "\n"
906                 "iASL Warning: There were %u external control methods found during\n"
907                 "disassembly, but additional ACPI tables to resolve these externals\n"
908                 "were not specified. The resulting disassembler output file may not\n"
909                 "compile because the disassembler did not know how many arguments\n"
910                 "to assign to these methods. To specify the tables needed to resolve\n"
911                 "external control method references, use the one of the following\n"
912                 "example iASL invocations:\n"
913                 "    iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
914                 "    iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n",
915                 AcpiGbl_NumExternalMethods);
916         }
917         else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
918         {
919             /* The -e option was specified, but there are still some unresolved externals */
920 
921             fprintf (stderr, "\n"
922                 "iASL Warning: There were %u external control methods found during\n"
923                 "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
924                 "ACPI tables are required to properly disassemble the code. The\n"
925                 "resulting disassembler output file may not compile because the\n"
926                 "disassembler did not know how many arguments to assign to the\n"
927                 "unresolved methods.\n",
928                 AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
929                 (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
930                 (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
931         }
932     }
933 
934 }
935