1/******************************************************************************
2 *
3 * Module Name: dmextern - Support for External() ASL statements
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include <contrib/dev/acpica/include/acpi.h>
45#include <contrib/dev/acpica/include/accommon.h>
46#include <contrib/dev/acpica/include/amlcode.h>
47#include <contrib/dev/acpica/include/acnamesp.h>
48#include <contrib/dev/acpica/include/acdisasm.h>
49#include <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 */ "",                    /* 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
107AcpiDmAddToExternalListFromFile (
108    char                    *Path,
109    UINT8                   Type,
110    UINT32                  Value);
111
112
113/*******************************************************************************
114 *
115 * FUNCTION:    AcpiDmGetObjectTypeName
116 *
117 * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
118 *
119 * RETURN:      Pointer to a string
120 *
121 * DESCRIPTION: Map an object type to the ASL object type string.
122 *
123 ******************************************************************************/
124
125static const char *
126AcpiDmGetObjectTypeName (
127    ACPI_OBJECT_TYPE        Type)
128{
129
130    if (Type == ACPI_TYPE_LOCAL_SCOPE)
131    {
132        Type = ACPI_TYPE_DEVICE;
133    }
134
135    else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
136    {
137        return ("");
138    }
139
140    return (AcpiGbl_DmTypeNames[Type]);
141}
142
143
144/*******************************************************************************
145 *
146 * FUNCTION:    AcpiDmNormalizeParentPrefix
147 *
148 * PARAMETERS:  Op                  - Parse op
149 *              Path                - Path with parent prefix
150 *
151 * RETURN:      The full pathname to the object (from the namespace root)
152 *
153 * DESCRIPTION: Returns the full pathname of a path with parent prefix
154 *              The caller must free the fullpath returned.
155 *
156 ******************************************************************************/
157
158static char *
159AcpiDmNormalizeParentPrefix (
160    ACPI_PARSE_OBJECT       *Op,
161    char                    *Path)
162{
163    ACPI_NAMESPACE_NODE     *Node;
164    char                    *Fullpath;
165    char                    *ParentPath;
166    ACPI_SIZE               Length;
167    UINT32                  Index = 0;
168
169
170    if (!Op)
171    {
172        return (NULL);
173    }
174
175    /* Search upwards in the parse tree until we reach the next namespace node */
176
177    Op = Op->Common.Parent;
178    while (Op)
179    {
180        if (Op->Common.Node)
181        {
182            break;
183        }
184
185        Op = Op->Common.Parent;
186    }
187
188    if (!Op)
189    {
190        return (NULL);
191    }
192
193    /*
194     * Find the actual parent node for the reference:
195     * Remove all carat prefixes from the input path.
196     * There may be multiple parent prefixes (For example, ^^^M000)
197     */
198    Node = Op->Common.Node;
199    while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
200    {
201        Node = Node->Parent;
202        Path++;
203    }
204
205    if (!Node)
206    {
207        return (NULL);
208    }
209
210    /* Get the full pathname for the parent node */
211
212    ParentPath = AcpiNsGetExternalPathname (Node);
213    if (!ParentPath)
214    {
215        return (NULL);
216    }
217
218    Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
219    if (ParentPath[1])
220    {
221        /*
222         * If ParentPath is not just a simple '\', increment the length
223         * for the required dot separator (ParentPath.Path)
224         */
225        Length++;
226
227        /* For External() statements, we do not want a leading '\' */
228
229        if (*ParentPath == AML_ROOT_PREFIX)
230        {
231            Index = 1;
232        }
233    }
234
235    Fullpath = ACPI_ALLOCATE_ZEROED (Length);
236    if (!Fullpath)
237    {
238        goto Cleanup;
239    }
240
241    /*
242     * Concatenate parent fullpath and path. For example,
243     * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
244     *
245     * Copy the parent path
246     */
247    ACPI_STRCPY (Fullpath, &ParentPath[Index]);
248
249    /*
250     * Add dot separator
251     * (don't need dot if parent fullpath is a single backslash)
252     */
253    if (ParentPath[1])
254    {
255        ACPI_STRCAT (Fullpath, ".");
256    }
257
258    /* Copy child path (carat parent prefix(es) were skipped above) */
259
260    ACPI_STRCAT (Fullpath, Path);
261
262Cleanup:
263    ACPI_FREE (ParentPath);
264    return (Fullpath);
265}
266
267
268/*******************************************************************************
269 *
270 * FUNCTION:    AcpiDmAddToExternalFileList
271 *
272 * PARAMETERS:  PathList            - Single path or list separated by comma
273 *
274 * RETURN:      None
275 *
276 * DESCRIPTION: Add external files to global list
277 *
278 ******************************************************************************/
279
280ACPI_STATUS
281AcpiDmAddToExternalFileList (
282    char                    *PathList)
283{
284    ACPI_EXTERNAL_FILE      *ExternalFile;
285    char                    *Path;
286    char                    *TmpPath;
287
288
289    if (!PathList)
290    {
291        return (AE_OK);
292    }
293
294    Path = strtok (PathList, ",");
295
296    while (Path)
297    {
298        TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
299        if (!TmpPath)
300        {
301            return (AE_NO_MEMORY);
302        }
303
304        ACPI_STRCPY (TmpPath, Path);
305
306        ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
307        if (!ExternalFile)
308        {
309            ACPI_FREE (TmpPath);
310            return (AE_NO_MEMORY);
311        }
312
313        ExternalFile->Path = TmpPath;
314
315        if (AcpiGbl_ExternalFileList)
316        {
317            ExternalFile->Next = AcpiGbl_ExternalFileList;
318        }
319
320        AcpiGbl_ExternalFileList = ExternalFile;
321        Path = strtok (NULL, ",");
322    }
323
324    return (AE_OK);
325}
326
327
328/*******************************************************************************
329 *
330 * FUNCTION:    AcpiDmClearExternalFileList
331 *
332 * PARAMETERS:  None
333 *
334 * RETURN:      None
335 *
336 * DESCRIPTION: Clear the external file list
337 *
338 ******************************************************************************/
339
340void
341AcpiDmClearExternalFileList (
342    void)
343{
344    ACPI_EXTERNAL_FILE      *NextExternal;
345
346
347    while (AcpiGbl_ExternalFileList)
348    {
349        NextExternal = AcpiGbl_ExternalFileList->Next;
350        ACPI_FREE (AcpiGbl_ExternalFileList->Path);
351        ACPI_FREE (AcpiGbl_ExternalFileList);
352        AcpiGbl_ExternalFileList = NextExternal;
353    }
354}
355
356
357/*******************************************************************************
358 *
359 * FUNCTION:    AcpiDmAddToExternalList
360 *
361 * PARAMETERS:  Op                  - Current parser Op
362 *              Path                - Internal (AML) path to the object
363 *              Type                - ACPI object type to be added
364 *              Value               - Arg count if adding a Method object
365 *
366 * RETURN:      None
367 *
368 * DESCRIPTION: Insert a new name into the global list of Externals which
369 *              will in turn be later emitted as an External() declaration
370 *              in the disassembled output.
371 *
372 ******************************************************************************/
373
374void
375AcpiDmAddToExternalList (
376    ACPI_PARSE_OBJECT       *Op,
377    char                    *Path,
378    UINT8                   Type,
379    UINT32                  Value)
380{
381    char                    *ExternalPath;
382    char                    *Fullpath = NULL;
383    ACPI_EXTERNAL_LIST      *NewExternal;
384    ACPI_EXTERNAL_LIST      *NextExternal;
385    ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
386    ACPI_STATUS             Status;
387    BOOLEAN                 Resolved = FALSE;
388
389
390    if (!Path)
391    {
392        return;
393    }
394
395    if (Type == ACPI_TYPE_METHOD)
396    {
397        if (Value & 0x80)
398        {
399            Resolved = TRUE;
400        }
401        Value &= 0x07;
402    }
403
404    /*
405     * We don't want External() statements to contain a leading '\'.
406     * This prevents duplicate external statements of the form:
407     *
408     *    External (\ABCD)
409     *    External (ABCD)
410     *
411     * This would cause a compile time error when the disassembled
412     * output file is recompiled.
413     */
414    if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
415    {
416        Path++;
417    }
418
419    /* Externalize the ACPI pathname */
420
421    Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
422                NULL, &ExternalPath);
423    if (ACPI_FAILURE (Status))
424    {
425        return;
426    }
427
428    /*
429     * Get the full pathname from the root if "Path" has one or more
430     * parent prefixes (^). Note: path will not contain a leading '\'.
431     */
432    if (*Path == (UINT8) AML_PARENT_PREFIX)
433    {
434        Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
435        if (Fullpath)
436        {
437            /* Set new external path */
438
439            ACPI_FREE (ExternalPath);
440            ExternalPath = Fullpath;
441        }
442    }
443
444    /* Check all existing externals to ensure no duplicates */
445
446    NextExternal = AcpiGbl_ExternalList;
447    while (NextExternal)
448    {
449        if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
450        {
451            /* Duplicate method, check that the Value (ArgCount) is the same */
452
453            if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
454                (NextExternal->Value != Value))
455            {
456                ACPI_ERROR ((AE_INFO,
457                    "External method arg count mismatch %s: Current %u, attempted %u",
458                    NextExternal->Path, NextExternal->Value, Value));
459            }
460
461            /* Allow upgrade of type from ANY */
462
463            else if (NextExternal->Type == ACPI_TYPE_ANY)
464            {
465                NextExternal->Type = Type;
466                NextExternal->Value = Value;
467            }
468
469            ACPI_FREE (ExternalPath);
470            return;
471        }
472
473        NextExternal = NextExternal->Next;
474    }
475
476    /* Allocate and init a new External() descriptor */
477
478    NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
479    if (!NewExternal)
480    {
481        ACPI_FREE (ExternalPath);
482        return;
483    }
484
485    NewExternal->Path = ExternalPath;
486    NewExternal->Type = Type;
487    NewExternal->Value = Value;
488    NewExternal->Resolved = Resolved;
489    NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
490
491    /* Was the external path with parent prefix normalized to a fullpath? */
492
493    if (Fullpath == ExternalPath)
494    {
495        /* Get new internal path */
496
497        Status = AcpiNsInternalizeName (ExternalPath, &Path);
498        if (ACPI_FAILURE (Status))
499        {
500            ACPI_FREE (ExternalPath);
501            ACPI_FREE (NewExternal);
502            return;
503        }
504
505        /* Set flag to indicate External->InternalPath need to be freed */
506
507        NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
508    }
509
510    NewExternal->InternalPath = Path;
511
512    /* Link the new descriptor into the global list, alphabetically ordered */
513
514    NextExternal = AcpiGbl_ExternalList;
515    while (NextExternal)
516    {
517        if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
518        {
519            if (PrevExternal)
520            {
521                PrevExternal->Next = NewExternal;
522            }
523            else
524            {
525                AcpiGbl_ExternalList = NewExternal;
526            }
527
528            NewExternal->Next = NextExternal;
529            return;
530        }
531
532        PrevExternal = NextExternal;
533        NextExternal = NextExternal->Next;
534    }
535
536    if (PrevExternal)
537    {
538        PrevExternal->Next = NewExternal;
539    }
540    else
541    {
542        AcpiGbl_ExternalList = NewExternal;
543    }
544}
545
546
547/*******************************************************************************
548 *
549 * FUNCTION:    AcpiDmGetExternalsFromFile
550 *
551 * PARAMETERS:  None
552 *
553 * RETURN:      None
554 *
555 * DESCRIPTION: Process the optional external reference file.
556 *
557 * Each line in the file should be of the form:
558 *      External (<Method namepath>, MethodObj, <ArgCount>)
559 *
560 * Example:
561 *      External (_SB_.PCI0.XHC_.PS0X, MethodObj, 4)
562 *
563 ******************************************************************************/
564
565void
566AcpiDmGetExternalsFromFile (
567    void)
568{
569    FILE                    *ExternalRefFile;
570    char                    *Token;
571    char                    *MethodName;
572    UINT32                  ArgCount;
573    UINT32                  ImportCount = 0;
574
575
576    if (!Gbl_ExternalRefFilename)
577    {
578        return;
579    }
580
581    /* Open the file */
582
583    ExternalRefFile = fopen (Gbl_ExternalRefFilename, "r");
584    if (!ExternalRefFile)
585    {
586        fprintf (stderr, "Could not open external reference file \"%s\"\n",
587            Gbl_ExternalRefFilename);
588        return;
589    }
590
591    /* Each line defines a method */
592
593    while (fgets (StringBuffer, ASL_MSG_BUFFER_SIZE, ExternalRefFile))
594    {
595        Token = strtok (StringBuffer, METHOD_SEPARATORS);   /* "External" */
596        if (!Token) continue;
597        if (strcmp (Token, "External")) continue;
598
599        MethodName = strtok (NULL, METHOD_SEPARATORS);      /* Method namepath */
600        if (!MethodName) continue;
601
602        Token = strtok (NULL, METHOD_SEPARATORS);           /* "MethodObj" */
603        if (!Token) continue;
604        if (strcmp (Token, "MethodObj")) continue;
605
606        Token = strtok (NULL, METHOD_SEPARATORS);           /* Arg count */
607        if (!Token) continue;
608
609        /* Convert arg count string to an integer */
610
611        errno = 0;
612        ArgCount = strtoul (Token, NULL, 0);
613        if (errno)
614        {
615            fprintf (stderr, "Invalid argument count (%s)\n", Token);
616            continue;
617        }
618        if (ArgCount > 7)
619        {
620            fprintf (stderr, "Invalid argument count (%u)\n", ArgCount);
621            continue;
622        }
623
624        /* Add this external to the global list */
625
626        AcpiOsPrintf ("%s: Importing method external (%u arguments) %s\n",
627            Gbl_ExternalRefFilename, ArgCount, MethodName);
628
629        AcpiDmAddToExternalListFromFile (MethodName, ACPI_TYPE_METHOD, ArgCount | 0x80);
630        ImportCount++;
631    }
632
633    if (!ImportCount)
634    {
635        fprintf (stderr, "Did not find any external methods in reference file \"%s\"\n",
636            Gbl_ExternalRefFilename);
637    }
638    else
639    {
640        /* Add the external(s) to the namespace */
641
642        AcpiDmAddExternalsToNamespace ();
643
644        AcpiOsPrintf ("%s: Imported %u external method definitions\n",
645            Gbl_ExternalRefFilename, ImportCount);
646    }
647
648    fclose (ExternalRefFile);
649}
650
651
652/*******************************************************************************
653 *
654 * FUNCTION:    AcpiDmAddToExternalListFromFile
655 *
656 * PARAMETERS:  Path                - Internal (AML) path to the object
657 *              Type                - ACPI object type to be added
658 *              Value               - Arg count if adding a Method object
659 *
660 * RETURN:      None
661 *
662 * DESCRIPTION: Insert a new name into the global list of Externals which
663 *              will in turn be later emitted as an External() declaration
664 *              in the disassembled output.
665 *
666 ******************************************************************************/
667
668static void
669AcpiDmAddToExternalListFromFile (
670    char                    *Path,
671    UINT8                   Type,
672    UINT32                  Value)
673{
674    char                    *InternalPath;
675    char                    *ExternalPath;
676    ACPI_EXTERNAL_LIST      *NewExternal;
677    ACPI_EXTERNAL_LIST      *NextExternal;
678    ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
679    ACPI_STATUS             Status;
680    BOOLEAN                 Resolved = FALSE;
681
682
683    if (!Path)
684    {
685        return;
686    }
687
688    /* TBD: Add a flags parameter */
689
690    if (Type == ACPI_TYPE_METHOD)
691    {
692        if (Value & 0x80)
693        {
694            Resolved = TRUE;
695        }
696        Value &= 0x07;
697    }
698
699    /*
700     * We don't want External() statements to contain a leading '\'.
701     * This prevents duplicate external statements of the form:
702     *
703     *    External (\ABCD)
704     *    External (ABCD)
705     *
706     * This would cause a compile time error when the disassembled
707     * output file is recompiled.
708     */
709    if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
710    {
711        Path++;
712    }
713
714    /* Check all existing externals to ensure no duplicates */
715
716    NextExternal = AcpiGbl_ExternalList;
717    while (NextExternal)
718    {
719        if (!ACPI_STRCMP (Path, NextExternal->Path))
720        {
721            /* Duplicate method, check that the Value (ArgCount) is the same */
722
723            if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
724                (NextExternal->Value != Value))
725            {
726                ACPI_ERROR ((AE_INFO,
727                    "(File) External method arg count mismatch %s: Current %u, override to %u",
728                    NextExternal->Path, NextExternal->Value, Value));
729
730                /* Override, since new value came from external reference file */
731
732                NextExternal->Value = Value;
733            }
734
735            /* Allow upgrade of type from ANY */
736
737            else if (NextExternal->Type == ACPI_TYPE_ANY)
738            {
739                NextExternal->Type = Type;
740                NextExternal->Value = Value;
741            }
742
743            return;
744        }
745
746        NextExternal = NextExternal->Next;
747    }
748
749    /* Get the internal pathname (AML format) */
750
751    Status = AcpiNsInternalizeName (Path, &InternalPath);
752    if (ACPI_FAILURE (Status))
753    {
754        return;
755    }
756
757    /* Allocate and init a new External() descriptor */
758
759    NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
760    if (!NewExternal)
761    {
762        ACPI_FREE (InternalPath);
763        return;
764    }
765
766    /* Must copy and normalize the input path */
767
768    AcpiNsExternalizeName (ACPI_UINT32_MAX, InternalPath, NULL, &ExternalPath);
769
770    NewExternal->Path = ExternalPath;
771    NewExternal->Type = Type;
772    NewExternal->Value = Value;
773    NewExternal->Resolved = Resolved;
774    NewExternal->Length = (UINT16) ACPI_STRLEN (Path);
775    NewExternal->InternalPath = InternalPath;
776
777    /* Set flag to indicate External->InternalPath needs to be freed */
778
779    NewExternal->Flags |= ACPI_IPATH_ALLOCATED | ACPI_FROM_REFERENCE_FILE;
780
781    /* Link the new descriptor into the global list, alphabetically ordered */
782
783    NextExternal = AcpiGbl_ExternalList;
784    while (NextExternal)
785    {
786        if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
787        {
788            if (PrevExternal)
789            {
790                PrevExternal->Next = NewExternal;
791            }
792            else
793            {
794                AcpiGbl_ExternalList = NewExternal;
795            }
796
797            NewExternal->Next = NextExternal;
798            return;
799        }
800
801        PrevExternal = NextExternal;
802        NextExternal = NextExternal->Next;
803    }
804
805    if (PrevExternal)
806    {
807        PrevExternal->Next = NewExternal;
808    }
809    else
810    {
811        AcpiGbl_ExternalList = NewExternal;
812    }
813}
814
815
816/*******************************************************************************
817 *
818 * FUNCTION:    AcpiDmAddExternalsToNamespace
819 *
820 * PARAMETERS:  None
821 *
822 * RETURN:      None
823 *
824 * DESCRIPTION: Add all externals to the namespace. Allows externals to be
825 *              "resolved".
826 *
827 ******************************************************************************/
828
829void
830AcpiDmAddExternalsToNamespace (
831    void)
832{
833    ACPI_STATUS             Status;
834    ACPI_NAMESPACE_NODE     *Node;
835    ACPI_OPERAND_OBJECT     *ObjDesc;
836    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
837
838
839    while (External)
840    {
841        /* Add the external name (object) into the namespace */
842
843        Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
844                   ACPI_IMODE_LOAD_PASS1,
845                   ACPI_NS_ERROR_IF_FOUND | ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
846                   NULL, &Node);
847
848        if (ACPI_FAILURE (Status))
849        {
850            ACPI_EXCEPTION ((AE_INFO, Status,
851                "while adding external to namespace [%s]",
852                External->Path));
853        }
854
855        else switch (External->Type)
856        {
857        case ACPI_TYPE_METHOD:
858
859            /* For methods, we need to save the argument count */
860
861            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
862            ObjDesc->Method.ParamCount = (UINT8) External->Value;
863            Node->Object = ObjDesc;
864            break;
865
866        case ACPI_TYPE_REGION:
867
868            /* Regions require a region sub-object */
869
870            ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
871            ObjDesc->Region.Node = Node;
872            Node->Object = ObjDesc;
873            break;
874
875        default:
876
877            break;
878        }
879
880        External = External->Next;
881    }
882}
883
884
885/*******************************************************************************
886 *
887 * FUNCTION:    AcpiDmGetExternalMethodCount
888 *
889 * PARAMETERS:  None
890 *
891 * RETURN:      The number of control method externals in the external list
892 *
893 * DESCRIPTION: Return the number of method externals that have been generated.
894 *              If any control method externals have been found, we must
895 *              re-parse the entire definition block with the new information
896 *              (number of arguments for the methods.) This is limitation of
897 *              AML, we don't know the number of arguments from the control
898 *              method invocation itself.
899 *
900 ******************************************************************************/
901
902UINT32
903AcpiDmGetExternalMethodCount (
904    void)
905{
906    ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
907    UINT32                  Count = 0;
908
909
910    while (External)
911    {
912        if (External->Type == ACPI_TYPE_METHOD)
913        {
914            Count++;
915        }
916
917        External = External->Next;
918    }
919
920    return (Count);
921}
922
923
924/*******************************************************************************
925 *
926 * FUNCTION:    AcpiDmClearExternalList
927 *
928 * PARAMETERS:  None
929 *
930 * RETURN:      None
931 *
932 * DESCRIPTION: Free the entire External info list
933 *
934 ******************************************************************************/
935
936void
937AcpiDmClearExternalList (
938    void)
939{
940    ACPI_EXTERNAL_LIST      *NextExternal;
941
942
943    while (AcpiGbl_ExternalList)
944    {
945        NextExternal = AcpiGbl_ExternalList->Next;
946        ACPI_FREE (AcpiGbl_ExternalList->Path);
947        ACPI_FREE (AcpiGbl_ExternalList);
948        AcpiGbl_ExternalList = NextExternal;
949    }
950}
951
952
953/*******************************************************************************
954 *
955 * FUNCTION:    AcpiDmEmitExternals
956 *
957 * PARAMETERS:  None
958 *
959 * RETURN:      None
960 *
961 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
962 *              the global external info list.
963 *
964 ******************************************************************************/
965
966void
967AcpiDmEmitExternals (
968    void)
969{
970    ACPI_EXTERNAL_LIST      *NextExternal;
971
972
973    if (!AcpiGbl_ExternalList)
974    {
975        return;
976    }
977
978    /*
979     * Determine the number of control methods in the external list, and
980     * also how many of those externals were resolved via the namespace.
981     */
982    NextExternal = AcpiGbl_ExternalList;
983    while (NextExternal)
984    {
985        if (NextExternal->Type == ACPI_TYPE_METHOD)
986        {
987            AcpiGbl_NumExternalMethods++;
988            if (NextExternal->Resolved)
989            {
990                AcpiGbl_ResolvedExternalMethods++;
991            }
992        }
993
994        NextExternal = NextExternal->Next;
995    }
996
997    /* Check if any control methods were unresolved */
998
999    AcpiDmUnresolvedWarning (1);
1000
1001    /* Emit any unresolved method externals in a single text block */
1002
1003    NextExternal = AcpiGbl_ExternalList;
1004    while (NextExternal)
1005    {
1006        if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
1007            (!NextExternal->Resolved))
1008        {
1009            AcpiOsPrintf ("    External (%s%s",
1010                NextExternal->Path,
1011                AcpiDmGetObjectTypeName (NextExternal->Type));
1012
1013            AcpiOsPrintf (
1014                ")    // Warning: Unresolved Method, "
1015                "guessing %u arguments (may be incorrect, see warning above)\n",
1016                NextExternal->Value);
1017
1018            NextExternal->Emitted = TRUE;
1019        }
1020
1021        NextExternal = NextExternal->Next;
1022    }
1023
1024    AcpiOsPrintf ("\n");
1025
1026
1027    /* Emit externals that were imported from a file */
1028
1029    if (Gbl_ExternalRefFilename)
1030    {
1031        AcpiOsPrintf (
1032            "    /*\n     * External declarations that were imported from\n"
1033            "     * the reference file [%s]\n     */\n",
1034            Gbl_ExternalRefFilename);
1035
1036        NextExternal = AcpiGbl_ExternalList;
1037        while (NextExternal)
1038        {
1039            if (!NextExternal->Emitted && (NextExternal->Flags & ACPI_FROM_REFERENCE_FILE))
1040            {
1041                AcpiOsPrintf ("    External (%s%s",
1042                    NextExternal->Path,
1043                    AcpiDmGetObjectTypeName (NextExternal->Type));
1044
1045                if (NextExternal->Type == ACPI_TYPE_METHOD)
1046                {
1047                    AcpiOsPrintf (")    // %u Arguments\n",
1048                        NextExternal->Value);
1049                }
1050                else
1051                {
1052                    AcpiOsPrintf (")\n");
1053                }
1054                NextExternal->Emitted = TRUE;
1055            }
1056
1057            NextExternal = NextExternal->Next;
1058        }
1059
1060        AcpiOsPrintf ("\n");
1061    }
1062
1063    /*
1064     * Walk the list of externals found during the AML parsing
1065     */
1066    while (AcpiGbl_ExternalList)
1067    {
1068        if (!AcpiGbl_ExternalList->Emitted)
1069        {
1070            AcpiOsPrintf ("    External (%s%s",
1071                AcpiGbl_ExternalList->Path,
1072                AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
1073
1074            /* For methods, add a comment with the number of arguments */
1075
1076            if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
1077            {
1078                AcpiOsPrintf (")    // %u Arguments\n",
1079                    AcpiGbl_ExternalList->Value);
1080            }
1081            else
1082            {
1083                AcpiOsPrintf (")\n");
1084            }
1085        }
1086
1087        /* Free this external info block and move on to next external */
1088
1089        NextExternal = AcpiGbl_ExternalList->Next;
1090        if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
1091        {
1092            ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
1093        }
1094
1095        ACPI_FREE (AcpiGbl_ExternalList->Path);
1096        ACPI_FREE (AcpiGbl_ExternalList);
1097        AcpiGbl_ExternalList = NextExternal;
1098    }
1099
1100    AcpiOsPrintf ("\n");
1101}
1102
1103
1104/*******************************************************************************
1105 *
1106 * FUNCTION:    AcpiDmUnresolvedWarning
1107 *
1108 * PARAMETERS:  Type                - Where to output the warning.
1109 *                                    0 means write to stderr
1110 *                                    1 means write to AcpiOsPrintf
1111 *
1112 * RETURN:      None
1113 *
1114 * DESCRIPTION: Issue warning message if there are unresolved external control
1115 *              methods within the disassembly.
1116 *
1117 ******************************************************************************/
1118
1119#if 0
1120Summary of the external control method problem:
1121
1122When the -e option is used with disassembly, the various SSDTs are simply
1123loaded into a global namespace for the disassembler to use in order to
1124resolve control method references (invocations).
1125
1126The disassembler tracks any such references, and will emit an External()
1127statement for these types of methods, with the proper number of arguments .
1128
1129Without the SSDTs, the AML does not contain enough information to properly
1130disassemble the control method invocation -- because the disassembler does
1131not know how many arguments to parse.
1132
1133An example: Assume we have two control methods. ABCD has one argument, and
1134EFGH has zero arguments. Further, we have two additional control methods
1135that invoke ABCD and EFGH, named T1 and T2:
1136
1137    Method (ABCD, 1)
1138    {
1139    }
1140    Method (EFGH, 0)
1141    {
1142    }
1143    Method (T1)
1144    {
1145        ABCD (Add (2, 7, Local0))
1146    }
1147    Method (T2)
1148    {
1149        EFGH ()
1150        Add (2, 7, Local0)
1151    }
1152
1153Here is the AML code that is generated for T1 and T2:
1154
1155     185:      Method (T1)
1156
11570000034C:  14 10 54 31 5F 5F 00 ...    "..T1__."
1158
1159     186:      {
1160     187:          ABCD (Add (2, 7, Local0))
1161
116200000353:  41 42 43 44 ............    "ABCD"
116300000357:  72 0A 02 0A 07 60 ......    "r....`"
1164
1165     188:      }
1166
1167     190:      Method (T2)
1168
11690000035D:  14 10 54 32 5F 5F 00 ...    "..T2__."
1170
1171     191:      {
1172     192:          EFGH ()
1173
117400000364:  45 46 47 48 ............    "EFGH"
1175
1176     193:          Add (2, 7, Local0)
1177
117800000368:  72 0A 02 0A 07 60 ......    "r....`"
1179     194:      }
1180
1181Note that the AML code for T1 and T2 is essentially identical. When
1182disassembling this code, the methods ABCD and EFGH must be known to the
1183disassembler, otherwise it does not know how to handle the method invocations.
1184
1185In other words, if ABCD and EFGH are actually external control methods
1186appearing in an SSDT, the disassembler does not know what to do unless
1187the owning SSDT has been loaded via the -e option.
1188#endif
1189
1190void
1191AcpiDmUnresolvedWarning (
1192    UINT8                   Type)
1193{
1194
1195    if (!AcpiGbl_NumExternalMethods)
1196    {
1197        return;
1198    }
1199
1200    if (Type)
1201    {
1202        if (!AcpiGbl_ExternalFileList)
1203        {
1204            /* The -e option was not specified */
1205
1206           AcpiOsPrintf ("    /*\n"
1207                "     * iASL Warning: There were %u external control methods found during\n"
1208                "     * disassembly, but additional ACPI tables to resolve these externals\n"
1209                "     * were not specified. This resulting disassembler output file may not\n"
1210                "     * compile because the disassembler did not know how many arguments\n"
1211                "     * to assign to these methods. To specify the tables needed to resolve\n"
1212                "     * external control method references, use the one of the following\n"
1213                "     * example iASL invocations:\n"
1214                "     *     iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
1215                "     *     iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n"
1216                "     */\n",
1217                AcpiGbl_NumExternalMethods);
1218        }
1219        else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1220        {
1221            /* The -e option was specified, but there are still some unresolved externals */
1222
1223            AcpiOsPrintf ("    /*\n"
1224                "     * iASL Warning: There were %u external control methods found during\n"
1225                "     * disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1226                "     * ACPI tables are required to properly disassemble the code. This\n"
1227                "     * resulting disassembler output file may not compile because the\n"
1228                "     * disassembler did not know how many arguments to assign to the\n"
1229                "     * unresolved methods.\n"
1230                "     */\n",
1231                AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1232                (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1233                (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1234        }
1235    }
1236    else
1237    {
1238        if (!AcpiGbl_ExternalFileList)
1239        {
1240            /* The -e option was not specified */
1241
1242            fprintf (stderr, "\n"
1243                "iASL Warning: There were %u external control methods found during\n"
1244                "disassembly, but additional ACPI tables to resolve these externals\n"
1245                "were not specified. The resulting disassembler output file may not\n"
1246                "compile because the disassembler did not know how many arguments\n"
1247                "to assign to these methods. To specify the tables needed to resolve\n"
1248                "external control method references, use the one of the following\n"
1249                "example iASL invocations:\n"
1250                "    iasl -e <ssdt1.aml,ssdt2.aml...> -d <dsdt.aml>\n"
1251                "    iasl -e <dsdt.aml,ssdt2.aml...> -d <ssdt1.aml>\n",
1252                AcpiGbl_NumExternalMethods);
1253        }
1254        else if (AcpiGbl_NumExternalMethods != AcpiGbl_ResolvedExternalMethods)
1255        {
1256            /* The -e option was specified, but there are still some unresolved externals */
1257
1258            fprintf (stderr, "\n"
1259                "iASL Warning: There were %u external control methods found during\n"
1260                "disassembly, but only %u %s resolved (%u unresolved). Additional\n"
1261                "ACPI tables are required to properly disassemble the code. The\n"
1262                "resulting disassembler output file may not compile because the\n"
1263                "disassembler did not know how many arguments to assign to the\n"
1264                "unresolved methods.\n",
1265                AcpiGbl_NumExternalMethods, AcpiGbl_ResolvedExternalMethods,
1266                (AcpiGbl_ResolvedExternalMethods > 1 ? "were" : "was"),
1267                (AcpiGbl_NumExternalMethods - AcpiGbl_ResolvedExternalMethods));
1268        }
1269    }
1270}
1271