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