dmextern.c revision 284460
1/******************************************************************************
2 *
3 * Module Name: dmextern - Support for External() ASL statements
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2015, 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 <contrib/dev/acpica/compiler/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 */
68static 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
97static const char *
98AcpiDmGetObjectTypeName (
99    ACPI_OBJECT_TYPE        Type);
100
101static char *
102AcpiDmNormalizeParentPrefix (
103    ACPI_PARSE_OBJECT       *Op,
104    char                    *Path);
105
106static void
107AcpiDmAddPathToExternalList (
108    char                    *Path,
109    UINT8                   Type,
110    UINT32                  Value,
111    UINT16                  Flags);
112
113static ACPI_STATUS
114AcpiDmCreateNewExternal (
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
134static const char *
135AcpiDmGetObjectTypeName (
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
167static char *
168AcpiDmNormalizeParentPrefix (
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
271Cleanup:
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
289ACPI_STATUS
290AcpiDmAddToExternalFileList (
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
342void
343AcpiDmClearExternalFileList (
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
377void
378AcpiDmGetExternalsFromFile (
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        AslAbort ();
401        return;
402    }
403
404    /* Each line defines a method */
405
406    while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
407    {
408        Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
409        if (!Token)
410        {
411            continue;
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        if (ArgCount > 7)
451        {
452            fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
453            continue;
454        }
455
456        /* Add this external to the global list */
457
458        AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
459            Gbl_ExternalRefFilename, ArgCount, MethodName);
460
461        AcpiDmAddPathToExternalList (MethodName, ACPI_TYPE_METHOD,
462            ArgCount, (ACPI_EXT_RESOLVED_REFERENCE | ACPI_EXT_ORIGIN_FROM_FILE));
463        ImportCount++;
464    }
465
466    if (!ImportCount)
467    {
468        fprintf (stderr, "Did not find any external methods in reference file \"%s\"\n",
469            Gbl_ExternalRefFilename);
470    }
471    else
472    {
473        /* Add the external(s) to the namespace */
474
475        AcpiDmAddExternalsToNamespace ();
476
477        AcpiOsPrintf ("%s: Imported %u external method definitions\n",
478            Gbl_ExternalRefFilename, ImportCount);
479    }
480
481    fclose (ExternalRefFile);
482}
483
484
485/*******************************************************************************
486 *
487 * FUNCTION:    AcpiDmAddOpToExternalList
488 *
489 * PARAMETERS:  Op                  - Current parser Op
490 *              Path                - Internal (AML) path to the object
491 *              Type                - ACPI object type to be added
492 *              Value               - Arg count if adding a Method object
493 *              Flags               - To be passed to the external object
494 *
495 * RETURN:      None
496 *
497 * DESCRIPTION: Insert a new name into the global list of Externals which
498 *              will in turn be later emitted as an External() declaration
499 *              in the disassembled output.
500 *
501 *              This function handles the most common case where the referenced
502 *              name is simply not found in the constructed namespace.
503 *
504 ******************************************************************************/
505
506void
507AcpiDmAddOpToExternalList (
508    ACPI_PARSE_OBJECT       *Op,
509    char                    *Path,
510    UINT8                   Type,
511    UINT32                  Value,
512    UINT16                  Flags)
513{
514    char                    *ExternalPath;
515    char                    *InternalPath = Path;
516    char                    *Temp;
517    ACPI_STATUS             Status;
518
519
520    ACPI_FUNCTION_TRACE (DmAddOpToExternalList);
521
522
523    if (!Path)
524    {
525        return_VOID;
526    }
527
528    /* Remove a root backslash if present */
529
530    if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
531    {
532        Path++;
533    }
534
535    /* Externalize the pathname */
536
537    Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
538        NULL, &ExternalPath);
539    if (ACPI_FAILURE (Status))
540    {
541        return_VOID;
542    }
543
544    /*
545     * Get the full pathname from the root if "Path" has one or more
546     * parent prefixes (^). Note: path will not contain a leading '\'.
547     */
548    if (*Path == (UINT8) AML_PARENT_PREFIX)
549    {
550        Temp = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
551
552        /* Set new external path */
553
554        ACPI_FREE (ExternalPath);
555        ExternalPath = Temp;
556        if (!Temp)
557        {
558            return_VOID;
559        }
560
561        /* Create the new internal pathname */
562
563        Flags |= ACPI_EXT_INTERNAL_PATH_ALLOCATED;
564        Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
565        if (ACPI_FAILURE (Status))
566        {
567            ACPI_FREE (ExternalPath);
568            return_VOID;
569        }
570    }
571
572    /* Create the new External() declaration node */
573
574    Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
575        Type, Value, Flags);
576    if (ACPI_FAILURE (Status))
577    {
578        ACPI_FREE (ExternalPath);
579        if (Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
580        {
581            ACPI_FREE (InternalPath);
582        }
583    }
584
585    return_VOID;
586}
587
588
589/*******************************************************************************
590 *
591 * FUNCTION:    AcpiDmAddNodeToExternalList
592 *
593 * PARAMETERS:  Node                - Namespace node for object to be added
594 *              Type                - ACPI object type to be added
595 *              Value               - Arg count if adding a Method object
596 *              Flags               - To be passed to the external object
597 *
598 * RETURN:      None
599 *
600 * DESCRIPTION: Insert a new name into the global list of Externals which
601 *              will in turn be later emitted as an External() declaration
602 *              in the disassembled output.
603 *
604 *              This function handles the case where the referenced name has
605 *              been found in the namespace, but the name originated in a
606 *              table other than the one that is being disassembled (such
607 *              as a table that is added via the iASL -e option).
608 *
609 ******************************************************************************/
610
611void
612AcpiDmAddNodeToExternalList (
613    ACPI_NAMESPACE_NODE     *Node,
614    UINT8                   Type,
615    UINT32                  Value,
616    UINT16                  Flags)
617{
618    char                    *ExternalPath;
619    char                    *InternalPath;
620    char                    *Temp;
621    ACPI_STATUS             Status;
622
623
624    ACPI_FUNCTION_TRACE (DmAddNodeToExternalList);
625
626
627    if (!Node)
628    {
629        return_VOID;
630    }
631
632    /* Get the full external and internal pathnames to the node */
633
634    ExternalPath = AcpiNsGetExternalPathname (Node);
635    if (!ExternalPath)
636    {
637        return_VOID;
638    }
639
640    Status = AcpiNsInternalizeName (ExternalPath, &InternalPath);
641    if (ACPI_FAILURE (Status))
642    {
643        ACPI_FREE (ExternalPath);
644        return_VOID;
645    }
646
647    /* Remove the root backslash */
648
649    if ((*ExternalPath == AML_ROOT_PREFIX) && (ExternalPath[1]))
650    {
651        Temp = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (ExternalPath) + 1);
652        if (!Temp)
653        {
654            return_VOID;
655        }
656
657        ACPI_STRCPY (Temp, &ExternalPath[1]);
658        ACPI_FREE (ExternalPath);
659        ExternalPath = Temp;
660    }
661
662    /* Create the new External() declaration node */
663
664    Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath, Type,
665        Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
666    if (ACPI_FAILURE (Status))
667    {
668        ACPI_FREE (ExternalPath);
669        ACPI_FREE (InternalPath);
670    }
671
672    return_VOID;
673}
674
675
676/*******************************************************************************
677 *
678 * FUNCTION:    AcpiDmAddPathToExternalList
679 *
680 * PARAMETERS:  Path                - External name of the object to be added
681 *              Type                - ACPI object type to be added
682 *              Value               - Arg count if adding a Method object
683 *              Flags               - To be passed to the external object
684 *
685 * RETURN:      None
686 *
687 * DESCRIPTION: Insert a new name into the global list of Externals which
688 *              will in turn be later emitted as an External() declaration
689 *              in the disassembled output.
690 *
691 *              This function currently is used to add externals via a
692 *              reference file (via the -fe iASL option).
693 *
694 ******************************************************************************/
695
696static void
697AcpiDmAddPathToExternalList (
698    char                    *Path,
699    UINT8                   Type,
700    UINT32                  Value,
701    UINT16                  Flags)
702{
703    char                    *InternalPath;
704    char                    *ExternalPath;
705    ACPI_STATUS             Status;
706
707
708    ACPI_FUNCTION_TRACE (DmAddPathToExternalList);
709
710
711    if (!Path)
712    {
713        return_VOID;
714    }
715
716    /* Remove a root backslash if present */
717
718    if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
719    {
720        Path++;
721    }
722
723    /* Create the internal and external pathnames */
724
725    Status = AcpiNsInternalizeName (Path, &InternalPath);
726    if (ACPI_FAILURE (Status))
727    {
728        return_VOID;
729    }
730
731    Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath,
732        NULL, &ExternalPath);
733    if (ACPI_FAILURE (Status))
734    {
735        ACPI_FREE (InternalPath);
736        return_VOID;
737    }
738
739    /* Create the new External() declaration node */
740
741    Status = AcpiDmCreateNewExternal (ExternalPath, InternalPath,
742        Type, Value, (Flags | ACPI_EXT_INTERNAL_PATH_ALLOCATED));
743    if (ACPI_FAILURE (Status))
744    {
745        ACPI_FREE (ExternalPath);
746        ACPI_FREE (InternalPath);
747    }
748
749    return_VOID;
750}
751
752
753/*******************************************************************************
754 *
755 * FUNCTION:    AcpiDmCreateNewExternal
756 *
757 * PARAMETERS:  ExternalPath        - External path to the object
758 *              InternalPath        - Internal (AML) path to the object
759 *              Type                - ACPI object type to be added
760 *              Value               - Arg count if adding a Method object
761 *              Flags               - To be passed to the external object
762 *
763 * RETURN:      Status
764 *
765 * DESCRIPTION: Common low-level function to insert a new name into the global
766 *              list of Externals which will in turn be later emitted as
767 *              External() declarations in the disassembled output.
768 *
769 *              Note: The external name should not include a root prefix
770 *              (backslash). We do not want External() statements to contain
771 *              a leading '\', as this prevents duplicate external statements
772 *              of the form:
773 *
774 *                  External (\ABCD)
775 *                  External (ABCD)
776 *
777 *              This would cause a compile time error when the disassembled
778 *              output file is recompiled.
779 *
780 *              There are two cases that are handled here. For both, we emit
781 *              an External() statement:
782 *              1) The name was simply not found in the namespace.
783 *              2) The name was found, but it originated in a table other than
784 *              the table that is being disassembled.
785 *
786 ******************************************************************************/
787
788static ACPI_STATUS
789AcpiDmCreateNewExternal (
790    char                    *ExternalPath,
791    char                    *InternalPath,
792    UINT8                   Type,
793    UINT32                  Value,
794    UINT16                  Flags)
795{
796    ACPI_EXTERNAL_LIST      *NewExternal;
797    ACPI_EXTERNAL_LIST      *NextExternal;
798    ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
799
800
801    ACPI_FUNCTION_TRACE (DmCreateNewExternal);
802
803
804    /* Check all existing externals to ensure no duplicates */
805
806    NextExternal = AcpiGbl_ExternalList;
807    while (NextExternal)
808    {
809        if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
810        {
811            /* Duplicate method, check that the Value (ArgCount) is the same */
812
813            if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
814                (NextExternal->Value != Value) &&
815                (Value > 0))
816            {
817                ACPI_ERROR ((AE_INFO,
818                    "External method arg count mismatch %s: Current %u, attempted %u",
819                    NextExternal->Path, NextExternal->Value, Value));
820            }
821
822            /* Allow upgrade of type from ANY */
823
824            else if (NextExternal->Type == ACPI_TYPE_ANY)
825            {
826                NextExternal->Type = Type;
827                NextExternal->Value = Value;
828            }
829
830            return_ACPI_STATUS (AE_ALREADY_EXISTS);
831        }
832
833        NextExternal = NextExternal->Next;
834    }
835
836    /* Allocate and init a new External() descriptor */
837
838    NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
839    if (!NewExternal)
840    {
841        return_ACPI_STATUS (AE_NO_MEMORY);
842    }
843
844    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
845        "Adding external reference node (%s) type [%s]\n",
846        ExternalPath, AcpiUtGetTypeName (Type)));
847
848    NewExternal->Flags = Flags;
849    NewExternal->Value = Value;
850    NewExternal->Path = ExternalPath;
851    NewExternal->Type = Type;
852    NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
853    NewExternal->InternalPath = InternalPath;
854
855    /* Link the new descriptor into the global list, alphabetically ordered */
856
857    NextExternal = AcpiGbl_ExternalList;
858    while (NextExternal)
859    {
860        if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
861        {
862            if (PrevExternal)
863            {
864                PrevExternal->Next = NewExternal;
865            }
866            else
867            {
868                AcpiGbl_ExternalList = NewExternal;
869            }
870
871            NewExternal->Next = NextExternal;
872            return_ACPI_STATUS (AE_OK);
873        }
874
875        PrevExternal = NextExternal;
876        NextExternal = NextExternal->Next;
877    }
878
879    if (PrevExternal)
880    {
881        PrevExternal->Next = NewExternal;
882    }
883    else
884    {
885        AcpiGbl_ExternalList = NewExternal;
886    }
887
888    return_ACPI_STATUS (AE_OK);
889}
890
891
892/*******************************************************************************
893 *
894 * FUNCTION:    AcpiDmAddExternalsToNamespace
895 *
896 * PARAMETERS:  None
897 *
898 * RETURN:      None
899 *
900 * DESCRIPTION: Add all externals to the namespace. Allows externals to be
901 *              "resolved".
902 *
903 ******************************************************************************/
904
905void
906AcpiDmAddExternalsToNamespace (
907    void)
908{
909    ACPI_STATUS             Status;
910    ACPI_NAMESPACE_NODE     *Node;
911    ACPI_OPERAND_OBJECT     *ObjDesc;
912    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
913
914
915    while (External)
916    {
917        /* Add the external name (object) into the namespace */
918
919        Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
920                   ACPI_IMODE_LOAD_PASS1,
921                   ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
922                   NULL, &Node);
923
924        if (ACPI_FAILURE (Status))
925        {
926            ACPI_EXCEPTION ((AE_INFO, Status,
927                "while adding external to namespace [%s]",
928                External->Path));
929        }
930
931        else switch (External->Type)
932        {
933        case ACPI_TYPE_METHOD:
934
935            /* For methods, we need to save the argument count */
936
937            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
938            ObjDesc->Method.ParamCount = (UINT8) External->Value;
939            Node->Object = ObjDesc;
940            break;
941
942        case ACPI_TYPE_REGION:
943
944            /* Regions require a region sub-object */
945
946            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
947            ObjDesc->Region.Node = Node;
948            Node->Object = ObjDesc;
949            break;
950
951        default:
952
953            break;
954        }
955
956        External = External->Next;
957    }
958}
959
960
961/*******************************************************************************
962 *
963 * FUNCTION:    AcpiDmGetExternalMethodCount
964 *
965 * PARAMETERS:  None
966 *
967 * RETURN:      The number of control method externals in the external list
968 *
969 * DESCRIPTION: Return the number of method externals that have been generated.
970 *              If any control method externals have been found, we must
971 *              re-parse the entire definition block with the new information
972 *              (number of arguments for the methods.) This is limitation of
973 *              AML, we don't know the number of arguments from the control
974 *              method invocation itself.
975 *
976 ******************************************************************************/
977
978UINT32
979AcpiDmGetExternalMethodCount (
980    void)
981{
982    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
983    UINT32                  Count = 0;
984
985
986    while (External)
987    {
988        if (External->Type == ACPI_TYPE_METHOD)
989        {
990            Count++;
991        }
992
993        External = External->Next;
994    }
995
996    return (Count);
997}
998
999
1000/*******************************************************************************
1001 *
1002 * FUNCTION:    AcpiDmClearExternalList
1003 *
1004 * PARAMETERS:  None
1005 *
1006 * RETURN:      None
1007 *
1008 * DESCRIPTION: Free the entire External info list
1009 *
1010 ******************************************************************************/
1011
1012void
1013AcpiDmClearExternalList (
1014    void)
1015{
1016    ACPI_EXTERNAL_LIST      *NextExternal;
1017
1018
1019    while (AcpiGbl_ExternalList)
1020    {
1021        NextExternal = AcpiGbl_ExternalList->Next;
1022        ACPI_FREE (AcpiGbl_ExternalList->Path);
1023        ACPI_FREE (AcpiGbl_ExternalList);
1024        AcpiGbl_ExternalList = NextExternal;
1025    }
1026}
1027
1028
1029/*******************************************************************************
1030 *
1031 * FUNCTION:    AcpiDmEmitExternals
1032 *
1033 * PARAMETERS:  None
1034 *
1035 * RETURN:      None
1036 *
1037 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1038 *              the global external info list.
1039 *
1040 ******************************************************************************/
1041
1042void
1043AcpiDmEmitExternals (
1044    void)
1045{
1046    ACPI_EXTERNAL_LIST      *NextExternal;
1047
1048
1049    if (!AcpiGbl_ExternalList)
1050    {
1051        return;
1052    }
1053
1054    /*
1055     * Determine the number of control methods in the external list, and
1056     * also how many of those externals were resolved via the namespace.
1057     */
1058    NextExternal = AcpiGbl_ExternalList;
1059    while (NextExternal)
1060    {
1061        if (NextExternal->Type == ACPI_TYPE_METHOD)
1062        {
1063            AcpiGbl_NumExternalMethods++;
1064            if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1065            {
1066                AcpiGbl_ResolvedExternalMethods++;
1067            }
1068        }
1069
1070        NextExternal = NextExternal->Next;
1071    }
1072
1073    /* Check if any control methods were unresolved */
1074
1075    AcpiDmUnresolvedWarning (1);
1076
1077    /* Emit any unresolved method externals in a single text block */
1078
1079    NextExternal = AcpiGbl_ExternalList;
1080    while (NextExternal)
1081    {
1082        if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
1083            (!(NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1084        {
1085            AcpiOsPrintf ("    External (%s%s",
1086                NextExternal->Path,
1087                AcpiDmGetObjectTypeName (NextExternal->Type));
1088
1089            AcpiOsPrintf (")    // Warning: Unresolved method, "
1090                "guessing %u arguments\n",
1091                NextExternal->Value);
1092
1093            NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1094        }
1095
1096        NextExternal = NextExternal->Next;
1097    }
1098
1099    AcpiOsPrintf ("\n");
1100
1101
1102    /* Emit externals that were imported from a file */
1103
1104    if (Gbl_ExternalRefFilename)
1105    {
1106        AcpiOsPrintf (
1107            "    /*\n     * External declarations that were imported from\n"
1108            "     * the reference file [%s]\n     */\n",
1109            Gbl_ExternalRefFilename);
1110
1111        NextExternal = AcpiGbl_ExternalList;
1112        while (NextExternal)
1113        {
1114            if (!(NextExternal->Flags & ACPI_EXT_EXTERNAL_EMITTED) &&
1115                (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_FILE))
1116            {
1117                AcpiOsPrintf ("    External (%s%s",
1118                    NextExternal->Path,
1119                    AcpiDmGetObjectTypeName (NextExternal->Type));
1120
1121                if (NextExternal->Type == ACPI_TYPE_METHOD)
1122                {
1123                    AcpiOsPrintf (")    // %u Arguments\n",
1124                        NextExternal->Value);
1125                }
1126                else
1127                {
1128                    AcpiOsPrintf (")\n");
1129                }
1130                NextExternal->Flags |= ACPI_EXT_EXTERNAL_EMITTED;
1131            }
1132
1133            NextExternal = NextExternal->Next;
1134        }
1135
1136        AcpiOsPrintf ("\n");
1137    }
1138
1139    /*
1140     * Walk the list of externals found during the AML parsing
1141     */
1142    while (AcpiGbl_ExternalList)
1143    {
1144        if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1145        {
1146            AcpiOsPrintf ("    External (%s%s",
1147                AcpiGbl_ExternalList->Path,
1148                AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1149
1150            /* For methods, add a comment with the number of arguments */
1151
1152            if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1153            {
1154                AcpiOsPrintf (")    // %u Arguments\n",
1155                    AcpiGbl_ExternalList->Value);
1156            }
1157            else
1158            {
1159                AcpiOsPrintf (")\n");
1160            }
1161        }
1162
1163        /* Free this external info block and move on to next external */
1164
1165        NextExternal = AcpiGbl_ExternalList->Next;
1166        if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1167        {
1168            ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1169        }
1170
1171        ACPI_FREE (AcpiGbl_ExternalList->Path);
1172        ACPI_FREE (AcpiGbl_ExternalList);
1173        AcpiGbl_ExternalList = NextExternal;
1174    }
1175
1176    AcpiOsPrintf ("\n");
1177}
1178
1179
1180/*******************************************************************************
1181 *
1182 * FUNCTION:    AcpiDmUnresolvedWarning
1183 *
1184 * PARAMETERS:  Type                - Where to output the warning.
1185 *                                    0 means write to stderr
1186 *                                    1 means write to AcpiOsPrintf
1187 *
1188 * RETURN:      None
1189 *
1190 * DESCRIPTION: Issue warning message if there are unresolved external control
1191 *              methods within the disassembly.
1192 *
1193 ******************************************************************************/
1194
1195#if 0
1196Summary of the external control method problem:
1197
1198When the -e option is used with disassembly, the various SSDTs are simply
1199loaded into a global namespace for the disassembler to use in order to
1200resolve control method references (invocations).
1201
1202The disassembler tracks any such references, and will emit an External()
1203statement for these types of methods, with the proper number of arguments .
1204
1205Without the SSDTs, the AML does not contain enough information to properly
1206disassemble the control method invocation -- because the disassembler does
1207not know how many arguments to parse.
1208
1209An example: Assume we have two control methods. ABCD has one argument, and
1210EFGH has zero arguments. Further, we have two additional control methods
1211that invoke ABCD and EFGH, named T1 and T2:
1212
1213    Method (ABCD, 1)
1214    {
1215    }
1216    Method (EFGH, 0)
1217    {
1218    }
1219    Method (T1)
1220    {
1221        ABCD (Add (2, 7, Local0))
1222    }
1223    Method (T2)
1224    {
1225        EFGH ()
1226        Add (2, 7, Local0)
1227    }
1228
1229Here is the AML code that is generated for T1 and T2:
1230
1231     185:      Method (T1)
1232
12330000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1234
1235     186:      {
1236     187:          ABCD (Add (2, 7, Local0))
1237
123800000353:  41 42 43 44 ............    "ABCD"
123900000357:  72 0A 02 0A 07 60 ......    "r....`"
1240
1241     188:      }
1242
1243     190:      Method (T2)
1244
12450000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1246
1247     191:      {
1248     192:          EFGH ()
1249
125000000364:  45 46 47 48 ............    "EFGH"
1251
1252     193:          Add (2, 7, Local0)
1253
125400000368:  72 0A 02 0A 07 60 ......    "r....`"
1255     194:      }
1256
1257Note that the AML code for T1 and T2 is essentially identical. When
1258disassembling this code, the methods ABCD and EFGH must be known to the
1259disassembler, otherwise it does not know how to handle the method invocations.
1260
1261In other words, if ABCD and EFGH are actually external control methods
1262appearing in an SSDT, the disassembler does not know what to do unless
1263the owning SSDT has been loaded via the -e option.
1264#endif
1265
1266void
1267AcpiDmUnresolvedWarning (
1268    UINT8                   Type)
1269{
1270
1271    if (!AcpiGbl_NumExternalMethods)
1272    {
1273        return;
1274    }
1275
1276    if (Type)
1277    {
1278        if (!AcpiGbl_ExternalFileList)
1279        {
1280            /* The -e option was not specified */
1281
1282           AcpiOsPrintf ("    /*\n"
1283                "     * iASL Warning: There were %u external control methods found during\n"
1284                "     * disassembly, but additional ACPI tables to resolve these externals\n"
1285                "     * were not specified. This resulting disassembler output file may not\n"
1286                "     * compile because the disassembler did not know how many arguments\n"
1287                "     * to assign to these methods. To specify the tables needed to resolve\n"
1288                "     * external control method references, the -e option can be used to\n"
1289                "     * specify the filenames. Note: SSDTs can be dynamically loaded at\n"
1290                "     * runtime and may or may not be available via the host OS.\n"
1291                "     * Example iASL invocations:\n"
1292                "     *     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1293                "     *     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1294                "     *     iasl -e ssdt*.aml -d dsdt.aml\n"
1295                "     *\n"
1296                "     * In addition, the -fe option can be used to specify a file containing\n"
1297                "     * control method external declarations with the associated method\n"
1298                "     * argument counts. Each line of the file must be of the form:\n"
1299                "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1300                "     * Invocation:\n"
1301                "     *     iasl -fe refs.txt -d dsdt.aml\n"
1302                "     *\n"
1303                "     * The following methods were unresolved and many not compile properly\n"
1304                "     * because the disassembler had to guess at the number of arguments\n"
1305                "     * required for each:\n"
1306                "     */\n",
1307               AcpiGbl_NumExternalMethods);
1308        }
1309        else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1310        {
1311            /* The -e option was specified, but there are still some unresolved externals */
1312
1313            AcpiOsPrintf ("    /*\n"
1314                "     * iASL Warning: There were %u external control methods found during\n"
1315                "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1316                "     * ACPI tables may be required to properly disassemble the code. This\n"
1317                "     * resulting disassembler output file may not compile because the\n"
1318                "     * disassembler did not know how many arguments to assign to the\n"
1319                "     * unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1320                "     * runtime and may or may not be available via the host OS.\n"
1321                "     *\n"
1322                "     * If necessary, the -fe option can be used to specify a file containing\n"
1323                "     * control method external declarations with the associated method\n"
1324                "     * argument counts. Each line of the file must be of the form:\n"
1325                "     *     External (<method pathname>, MethodObj, <argument count>)\n"
1326                "     * Invocation:\n"
1327                "     *     iasl -fe refs.txt -d dsdt.aml\n"
1328                "     *\n"
1329                "     * The following methods were unresolved and many not compile properly\n"
1330                "     * because the disassembler had to guess at the number of arguments\n"
1331                "     * required for each:\n"
1332                "     */\n",
1333                AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1334                (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1335                (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1336        }
1337    }
1338    else
1339    {
1340        if (!AcpiGbl_ExternalFileList)
1341        {
1342            /* The -e option was not specified */
1343
1344            fprintf (stderr, "\n"
1345                "iASL Warning: There were %u external control methods found during\n"
1346                "disassembly, but additional ACPI tables to resolve these externals\n"
1347                "were not specified. The resulting disassembler output file may not\n"
1348                "compile because the disassembler did not know how many arguments\n"
1349                "to assign to these methods. To specify the tables needed to resolve\n"
1350                "external control method references, the -e option can be used to\n"
1351                "specify the filenames. Note: SSDTs can be dynamically loaded at\n"
1352                "runtime and may or may not be available via the host OS.\n"
1353                "Example iASL invocations:\n"
1354                "    iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1355                "    iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1356                "    iasl -e ssdt*.aml -d dsdt.aml\n"
1357                "\n"
1358                "In addition, the -fe option can be used to specify a file containing\n"
1359                "control method external declarations with the associated method\n"
1360                "argument counts. Each line of the file must be of the form:\n"
1361                "    External (<method pathname>, MethodObj, <argument count>)\n"
1362                "Invocation:\n"
1363                "    iasl -fe refs.txt -d dsdt.aml\n",
1364                AcpiGbl_NumExternalMethods);
1365        }
1366        else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1367        {
1368            /* The -e option was specified, but there are still some unresolved externals */
1369
1370            fprintf (stderr, "\n"
1371                "iASL Warning: There were %u external control methods found during\n"
1372                "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1373                "ACPI tables may be required to properly disassemble the code. The\n"
1374                "resulting disassembler output file may not compile because the\n"
1375                "disassembler did not know how many arguments to assign to the\n"
1376                "unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1377                "runtime and may or may not be available via the host OS.\n"
1378                "\n"
1379                "If necessary, the -fe option can be used to specify a file containing\n"
1380                "control method external declarations with the associated method\n"
1381                "argument counts. Each line of the file must be of the form:\n"
1382                "    External (<method pathname>, MethodObj, <argument count>)\n"
1383                "Invocation:\n"
1384                "    iasl -fe refs.txt -d dsdt.aml\n",
1385                AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1386                (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1387                (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1388        }
1389    }
1390}
1391