dmextern.c revision 306536
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 <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    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
166static char *
167AcpiDmNormalizeParentPrefix (
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
270Cleanup:
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
288ACPI_STATUS
289AcpiDmAddToExternalFileList (
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
341void
342AcpiDmClearExternalFileList (
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
376void
377AcpiDmGetExternalsFromFile (
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
508void
509AcpiDmAddOpToExternalList (
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
613void
614AcpiDmAddNodeToExternalList (
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
698static void
699AcpiDmAddPathToExternalList (
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:    AcpiDmCreateNewExternal
758 *
759 * PARAMETERS:  ExternalPath        - External path to the object
760 *              InternalPath        - Internal (AML) path to the object
761 *              Type                - ACPI object type to be added
762 *              Value               - Arg count if adding a Method object
763 *              Flags               - To be passed to the external object
764 *
765 * RETURN:      Status
766 *
767 * DESCRIPTION: Common low-level function to insert a new name into the global
768 *              list of Externals which will in turn be later emitted as
769 *              External() declarations in the disassembled output.
770 *
771 *              Note: The external name should not include a root prefix
772 *              (backslash). We do not want External() statements to contain
773 *              a leading '\', as this prevents duplicate external statements
774 *              of the form:
775 *
776 *                  External (\ABCD)
777 *                  External (ABCD)
778 *
779 *              This would cause a compile time error when the disassembled
780 *              output file is recompiled.
781 *
782 *              There are two cases that are handled here. For both, we emit
783 *              an External() statement:
784 *              1) The name was simply not found in the namespace.
785 *              2) The name was found, but it originated in a table other than
786 *              the table that is being disassembled.
787 *
788 ******************************************************************************/
789
790static ACPI_STATUS
791AcpiDmCreateNewExternal (
792    char                    *ExternalPath,
793    char                    *InternalPath,
794    UINT8                   Type,
795    UINT32                  Value,
796    UINT16                  Flags)
797{
798    ACPI_EXTERNAL_LIST      *NewExternal;
799    ACPI_EXTERNAL_LIST      *NextExternal;
800    ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
801
802
803    ACPI_FUNCTION_TRACE (DmCreateNewExternal);
804
805
806    /* Check all existing externals to ensure no duplicates */
807
808    NextExternal = AcpiGbl_ExternalList;
809    while (NextExternal)
810    {
811        /* Check for duplicates */
812
813        if (!strcmp (ExternalPath, NextExternal->Path))
814        {
815            /*
816             * If this external came from an External() opcode, we are
817             * finished with this one. (No need to check any further).
818             */
819            if (NextExternal->Flags & ACPI_EXT_ORIGIN_FROM_OPCODE)
820            {
821                return_ACPI_STATUS (AE_ALREADY_EXISTS);
822            }
823
824            /* Allow upgrade of type from ANY */
825
826            else if ((NextExternal->Type == ACPI_TYPE_ANY) &&
827                (Type != ACPI_TYPE_ANY))
828            {
829                NextExternal->Type = Type;
830            }
831
832            /* Update the argument count as necessary */
833
834            if (Value < NextExternal->Value)
835            {
836                NextExternal->Value = Value;
837            }
838
839            /* Update flags. */
840
841            NextExternal->Flags |= Flags;
842            NextExternal->Flags &= ~ACPI_EXT_INTERNAL_PATH_ALLOCATED;
843
844            return_ACPI_STATUS (AE_ALREADY_EXISTS);
845        }
846
847        NextExternal = NextExternal->Next;
848    }
849
850    /* Allocate and init a new External() descriptor */
851
852    NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
853    if (!NewExternal)
854    {
855        return_ACPI_STATUS (AE_NO_MEMORY);
856    }
857
858    ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
859        "Adding external reference node (%s) type [%s]\n",
860        ExternalPath, AcpiUtGetTypeName (Type)));
861
862    NewExternal->Flags = Flags;
863    NewExternal->Value = Value;
864    NewExternal->Path = ExternalPath;
865    NewExternal->Type = Type;
866    NewExternal->Length = (UINT16) strlen (ExternalPath);
867    NewExternal->InternalPath = InternalPath;
868
869    /* Link the new descriptor into the global list, alphabetically ordered */
870
871    NextExternal = AcpiGbl_ExternalList;
872    while (NextExternal)
873    {
874        if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
875        {
876            if (PrevExternal)
877            {
878                PrevExternal->Next = NewExternal;
879            }
880            else
881            {
882                AcpiGbl_ExternalList = NewExternal;
883            }
884
885            NewExternal->Next = NextExternal;
886            return_ACPI_STATUS (AE_OK);
887        }
888
889        PrevExternal = NextExternal;
890        NextExternal = NextExternal->Next;
891    }
892
893    if (PrevExternal)
894    {
895        PrevExternal->Next = NewExternal;
896    }
897    else
898    {
899        AcpiGbl_ExternalList = NewExternal;
900    }
901
902    return_ACPI_STATUS (AE_OK);
903}
904
905
906/*******************************************************************************
907 *
908 * FUNCTION:    AcpiDmAddExternalsToNamespace
909 *
910 * PARAMETERS:  None
911 *
912 * RETURN:      None
913 *
914 * DESCRIPTION: Add all externals to the namespace. Allows externals to be
915 *              "resolved".
916 *
917 ******************************************************************************/
918
919void
920AcpiDmAddExternalsToNamespace (
921    void)
922{
923    ACPI_STATUS             Status;
924    ACPI_NAMESPACE_NODE     *Node;
925    ACPI_OPERAND_OBJECT     *ObjDesc;
926    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
927
928
929    while (External)
930    {
931        /* Add the external name (object) into the namespace */
932
933        Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
934            ACPI_IMODE_LOAD_PASS1,
935            ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
936            NULL, &Node);
937
938        if (ACPI_FAILURE (Status))
939        {
940            ACPI_EXCEPTION ((AE_INFO, Status,
941                "while adding external to namespace [%s]",
942                External->Path));
943        }
944
945        else switch (External->Type)
946        {
947        case ACPI_TYPE_METHOD:
948
949            /* For methods, we need to save the argument count */
950
951            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
952            ObjDesc->Method.ParamCount = (UINT8) External->Value;
953            Node->Object = ObjDesc;
954            break;
955
956        case ACPI_TYPE_REGION:
957
958            /* Regions require a region sub-object */
959
960            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
961            ObjDesc->Region.Node = Node;
962            Node->Object = ObjDesc;
963            break;
964
965        default:
966
967            break;
968        }
969
970        External = External->Next;
971    }
972}
973
974
975/*******************************************************************************
976 *
977 * FUNCTION:    AcpiDmGetExternalMethodCount
978 *
979 * PARAMETERS:  None
980 *
981 * RETURN:      The number of control method externals in the external list
982 *
983 * DESCRIPTION: Return the number of method externals that have been generated.
984 *              If any control method externals have been found, we must
985 *              re-parse the entire definition block with the new information
986 *              (number of arguments for the methods.) This is limitation of
987 *              AML, we don't know the number of arguments from the control
988 *              method invocation itself.
989 *
990 ******************************************************************************/
991
992UINT32
993AcpiDmGetExternalMethodCount (
994    void)
995{
996    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
997    UINT32                  Count = 0;
998
999
1000    while (External)
1001    {
1002        if (External->Type == ACPI_TYPE_METHOD)
1003        {
1004            Count++;
1005        }
1006
1007        External = External->Next;
1008    }
1009
1010    return (Count);
1011}
1012
1013
1014/*******************************************************************************
1015 *
1016 * FUNCTION:    AcpiDmClearExternalList
1017 *
1018 * PARAMETERS:  None
1019 *
1020 * RETURN:      None
1021 *
1022 * DESCRIPTION: Free the entire External info list
1023 *
1024 ******************************************************************************/
1025
1026void
1027AcpiDmClearExternalList (
1028    void)
1029{
1030    ACPI_EXTERNAL_LIST      *NextExternal;
1031
1032
1033    while (AcpiGbl_ExternalList)
1034    {
1035        NextExternal = AcpiGbl_ExternalList->Next;
1036        ACPI_FREE (AcpiGbl_ExternalList->Path);
1037        ACPI_FREE (AcpiGbl_ExternalList);
1038        AcpiGbl_ExternalList = NextExternal;
1039    }
1040}
1041
1042
1043/*******************************************************************************
1044 *
1045 * FUNCTION:    AcpiDmEmitExternals
1046 *
1047 * PARAMETERS:  None
1048 *
1049 * RETURN:      None
1050 *
1051 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
1052 *              the global external info list.
1053 *
1054 ******************************************************************************/
1055
1056void
1057AcpiDmEmitExternals (
1058    void)
1059{
1060    ACPI_EXTERNAL_LIST      *NextExternal;
1061
1062
1063    if (!AcpiGbl_ExternalList)
1064    {
1065        return;
1066    }
1067
1068    /*
1069     * Determine the number of control methods in the external list, and
1070     * also how many of those externals were resolved via the namespace.
1071     */
1072    NextExternal = AcpiGbl_ExternalList;
1073    while (NextExternal)
1074    {
1075        if (NextExternal->Type == ACPI_TYPE_METHOD)
1076        {
1077            AcpiGbl_NumExternalMethods++;
1078            if (NextExternal->Flags & ACPI_EXT_RESOLVED_REFERENCE)
1079            {
1080                AcpiGbl_ResolvedExternalMethods++;
1081            }
1082        }
1083
1084        NextExternal = NextExternal->Next;
1085    }
1086
1087    /* Check if any control methods were unresolved */
1088
1089    AcpiDmUnresolvedWarning (1);
1090
1091    if (Gbl_ExternalRefFilename)
1092    {
1093        AcpiOsPrintf (
1094            "    /*\n     * External declarations were imported from\n"
1095            "     * a reference file -- %s\n     */\n\n",
1096            Gbl_ExternalRefFilename);
1097    }
1098
1099    /*
1100     * Walk and emit the list of externals found during the AML parsing
1101     */
1102    while (AcpiGbl_ExternalList)
1103    {
1104        if (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_EXTERNAL_EMITTED))
1105        {
1106            AcpiOsPrintf ("    External (%s%s)",
1107                AcpiGbl_ExternalList->Path,
1108                AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1109
1110            /* Check for "unresolved" method reference */
1111
1112            if ((AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD) &&
1113                (!(AcpiGbl_ExternalList->Flags & ACPI_EXT_RESOLVED_REFERENCE)))
1114            {
1115                AcpiOsPrintf ("    // Warning: Unknown method, "
1116                    "guessing %u arguments",
1117                    AcpiGbl_ExternalList->Value);
1118            }
1119
1120            /* Check for external from a external references file */
1121
1122            else if (AcpiGbl_ExternalList->Flags & ACPI_EXT_ORIGIN_FROM_FILE)
1123            {
1124                if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1125                {
1126                    AcpiOsPrintf ("    // %u Arguments",
1127                        AcpiGbl_ExternalList->Value);
1128                }
1129
1130                AcpiOsPrintf ("    // From external reference file");
1131            }
1132
1133            /* This is the normal external case */
1134
1135            else
1136            {
1137                /* For methods, add a comment with the number of arguments */
1138
1139                if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1140                {
1141                    AcpiOsPrintf ("    // %u Arguments",
1142                        AcpiGbl_ExternalList->Value);
1143                }
1144            }
1145
1146            AcpiOsPrintf ("\n");
1147        }
1148
1149        /* Free this external info block and move on to next external */
1150
1151        NextExternal = AcpiGbl_ExternalList->Next;
1152        if (AcpiGbl_ExternalList->Flags & ACPI_EXT_INTERNAL_PATH_ALLOCATED)
1153        {
1154            ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1155        }
1156
1157        ACPI_FREE (AcpiGbl_ExternalList->Path);
1158        ACPI_FREE (AcpiGbl_ExternalList);
1159        AcpiGbl_ExternalList = NextExternal;
1160    }
1161
1162    AcpiOsPrintf ("\n");
1163}
1164
1165
1166/*******************************************************************************
1167 *
1168 * FUNCTION:    AcpiDmUnresolvedWarning
1169 *
1170 * PARAMETERS:  Type                - Where to output the warning.
1171 *                                    0 means write to stderr
1172 *                                    1 means write to AcpiOsPrintf
1173 *
1174 * RETURN:      None
1175 *
1176 * DESCRIPTION: Issue warning message if there are unresolved external control
1177 *              methods within the disassembly.
1178 *
1179 ******************************************************************************/
1180
1181#if 0
1182Summary of the external control method problem:
1183
1184When the -e option is used with disassembly, the various SSDTs are simply
1185loaded into a global namespace for the disassembler to use in order to
1186resolve control method references (invocations).
1187
1188The disassembler tracks any such references, and will emit an External()
1189statement for these types of methods, with the proper number of arguments .
1190
1191Without the SSDTs, the AML does not contain enough information to properly
1192disassemble the control method invocation -- because the disassembler does
1193not know how many arguments to parse.
1194
1195An example: Assume we have two control methods. ABCD has one argument, and
1196EFGH has zero arguments. Further, we have two additional control methods
1197that invoke ABCD and EFGH, named T1 and T2:
1198
1199    Method (ABCD, 1)
1200    {
1201    }
1202    Method (EFGH, 0)
1203    {
1204    }
1205    Method (T1)
1206    {
1207        ABCD (Add (2, 7, Local0))
1208    }
1209    Method (T2)
1210    {
1211        EFGH ()
1212        Add (2, 7, Local0)
1213    }
1214
1215Here is the AML code that is generated for T1 and T2:
1216
1217     185:      Method (T1)
1218
12190000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1220
1221     186:      {
1222     187:          ABCD (Add (2, 7, Local0))
1223
122400000353:  41 42 43 44 ............    "ABCD"
122500000357:  72 0A 02 0A 07 60 ......    "r....`"
1226
1227     188:      }
1228
1229     190:      Method (T2)
1230
12310000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1232
1233     191:      {
1234     192:          EFGH ()
1235
123600000364:  45 46 47 48 ............    "EFGH"
1237
1238     193:          Add (2, 7, Local0)
1239
124000000368:  72 0A 02 0A 07 60 ......    "r....`"
1241     194:      }
1242
1243Note that the AML code for T1 and T2 is essentially identical. When
1244disassembling this code, the methods ABCD and EFGH must be known to the
1245disassembler, otherwise it does not know how to handle the method invocations.
1246
1247In other words, if ABCD and EFGH are actually external control methods
1248appearing in an SSDT, the disassembler does not know what to do unless
1249the owning SSDT has been loaded via the -e option.
1250#endif
1251
1252static char             ExternalWarningPart1[600];
1253static char             ExternalWarningPart2[400];
1254static char             ExternalWarningPart3[400];
1255static char             ExternalWarningPart4[200];
1256
1257void
1258AcpiDmUnresolvedWarning (
1259    UINT8                   Type)
1260{
1261    char                    *Format;
1262    char                    Pad[] = "     *";
1263    char                    NoPad[] = "";
1264
1265
1266    if (!AcpiGbl_NumExternalMethods)
1267    {
1268        return;
1269    }
1270
1271    if (AcpiGbl_NumExternalMethods == AcpiGbl_ResolvedExternalMethods)
1272    {
1273        return;
1274    }
1275
1276    Format = Type ? Pad : NoPad;
1277
1278    sprintf (ExternalWarningPart1,
1279        "%s iASL Warning: There %s %u external control method%s found during\n"
1280        "%s disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1281        "%s ACPI tables may be required to properly disassemble the code. This\n"
1282        "%s resulting disassembler output file may not compile because the\n"
1283        "%s disassembler did not know how many arguments to assign to the\n"
1284        "%s unresolved methods. Note: SSDTs can be dynamically loaded at\n"
1285        "%s runtime and may or may not be available via the host OS.\n",
1286        Format, (AcpiGbl_NumExternalMethods != 1 ? "were" : "was"),
1287        AcpiGbl_NumExternalMethods, (AcpiGbl_NumExternalMethods != 1 ? "s" : ""),
1288        Format, AcpiGbl_ResolvedExternalMethods,
1289        (AcpiGbl_ResolvedExternalMethods != 1 ? "were" : "was"),
1290        (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods),
1291        Format, Format, Format, Format, Format);
1292
1293    sprintf (ExternalWarningPart2,
1294        "%s To specify the tables needed to resolve external control method\n"
1295        "%s references, the -e option can be used to specify the filenames.\n"
1296        "%s Example iASL invocations:\n"
1297        "%s     iasl -e ssdt1.aml ssdt2.aml ssdt3.aml -d dsdt.aml\n"
1298        "%s     iasl -e dsdt.aml ssdt2.aml -d ssdt1.aml\n"
1299        "%s     iasl -e ssdt*.aml -d dsdt.aml\n",
1300        Format, Format, Format, Format, Format, Format);
1301
1302    sprintf (ExternalWarningPart3,
1303        "%s In addition, the -fe option can be used to specify a file containing\n"
1304        "%s control method external declarations with the associated method\n"
1305        "%s argument counts. Each line of the file must be of the form:\n"
1306        "%s     External (<method pathname>, MethodObj, <argument count>)\n"
1307        "%s Invocation:\n"
1308        "%s     iasl -fe refs.txt -d dsdt.aml\n",
1309        Format, Format, Format, Format, Format, Format);
1310
1311    sprintf (ExternalWarningPart4,
1312        "%s The following methods were unresolved and many not compile properly\n"
1313        "%s because the disassembler had to guess at the number of arguments\n"
1314        "%s required for each:\n",
1315        Format, Format, Format);
1316
1317    if (Type)
1318    {
1319        if (!AcpiGbl_ExternalFileList)
1320        {
1321            /* The -e option was not specified */
1322
1323           AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     *\n%s     */\n",
1324               ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3,
1325               ExternalWarningPart4);
1326        }
1327        else
1328        {
1329            /* The -e option was specified, but there are still some unresolved externals */
1330
1331            AcpiOsPrintf ("    /*\n%s     *\n%s     *\n%s     */\n",
1332               ExternalWarningPart1, ExternalWarningPart3, ExternalWarningPart4);
1333        }
1334    }
1335    else
1336    {
1337        if (!AcpiGbl_ExternalFileList)
1338        {
1339            /* The -e option was not specified */
1340
1341            fprintf (stderr, "\n%s\n%s\n%s\n",
1342               ExternalWarningPart1, ExternalWarningPart2, ExternalWarningPart3);
1343        }
1344        else
1345        {
1346            /* The -e option was specified, but there are still some unresolved externals */
1347
1348            fprintf (stderr, "\n%s\n%s\n",
1349               ExternalWarningPart1, ExternalWarningPart3);
1350        }
1351    }
1352}
1353