]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/common/dmextern.c
Import ACPICA 20121220.
[FreeBSD/FreeBSD.git] / source / common / dmextern.c
1 /******************************************************************************
2  *
3  * Module Name: dmextern - Support for External() ASL statements
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2012, 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 "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 #include "acdisasm.h"
49
50
51 /*
52  * This module is used for application-level code (iASL disassembler) only.
53  *
54  * It contains the code to create and emit any necessary External() ASL
55  * statements for the module being disassembled.
56  */
57 #define _COMPONENT          ACPI_CA_DISASSEMBLER
58         ACPI_MODULE_NAME    ("dmextern")
59
60
61 /*
62  * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
63  * ObjectTypeKeyword. Used to generate typed external declarations
64  */
65 static const char           *AcpiGbl_DmTypeNames[] =
66 {
67     /* 00 */ "",                    /* Type ANY */
68     /* 01 */ ", IntObj",
69     /* 02 */ ", StrObj",
70     /* 03 */ ", BuffObj",
71     /* 04 */ ", PkgObj",
72     /* 05 */ ", FieldUnitObj",
73     /* 06 */ ", DeviceObj",
74     /* 07 */ ", EventObj",
75     /* 08 */ ", MethodObj",
76     /* 09 */ ", MutexObj",
77     /* 10 */ ", OpRegionObj",
78     /* 11 */ ", PowerResObj",
79     /* 12 */ ", ProcessorObj",
80     /* 13 */ ", ThermalZoneObj",
81     /* 14 */ ", BuffFieldObj",
82     /* 15 */ ", DDBHandleObj",
83     /* 16 */ "",                    /* Debug object */
84     /* 17 */ ", FieldUnitObj",
85     /* 18 */ ", FieldUnitObj",
86     /* 19 */ ", FieldUnitObj"
87 };
88
89
90 /* Local prototypes */
91
92 static const char *
93 AcpiDmGetObjectTypeName (
94     ACPI_OBJECT_TYPE        Type);
95
96 static char *
97 AcpiDmNormalizeParentPrefix (
98     ACPI_PARSE_OBJECT       *Op,
99     char                    *Path);
100
101
102 /*******************************************************************************
103  *
104  * FUNCTION:    AcpiDmGetObjectTypeName
105  *
106  * PARAMETERS:  Type                - An ACPI_OBJECT_TYPE
107  *
108  * RETURN:      Pointer to a string
109  *
110  * DESCRIPTION: Map an object type to the ASL object type string.
111  *
112  ******************************************************************************/
113
114 static const char *
115 AcpiDmGetObjectTypeName (
116     ACPI_OBJECT_TYPE        Type)
117 {
118
119     if (Type == ACPI_TYPE_LOCAL_SCOPE)
120     {
121         Type = ACPI_TYPE_DEVICE;
122     }
123
124     else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
125     {
126         return ("");
127     }
128
129     return (AcpiGbl_DmTypeNames[Type]);
130 }
131
132
133 /*******************************************************************************
134  *
135  * FUNCTION:    AcpiDmNormalizeParentPrefix
136  *
137  * PARAMETERS:  Op                  - Parse op
138  *              Path                - Path with parent prefix
139  *
140  * RETURN:      The full pathname to the object (from the namespace root)
141  *
142  * DESCRIPTION: Returns the full pathname of a path with parent prefix
143  *              The caller must free the fullpath returned.
144  *
145  ******************************************************************************/
146
147 static char *
148 AcpiDmNormalizeParentPrefix (
149     ACPI_PARSE_OBJECT       *Op,
150     char                    *Path)
151 {
152     ACPI_NAMESPACE_NODE     *Node;
153     char                    *Fullpath;
154     char                    *ParentPath;
155     ACPI_SIZE               Length;
156     UINT32                  Index = 0;
157
158
159     if (!Op)
160     {
161         return (NULL);
162     }
163
164     /* Search upwards in the parse tree until we reach the next namespace node */
165
166     Op = Op->Common.Parent;
167     while (Op)
168     {
169         if (Op->Common.Node)
170         {
171             break;
172         }
173
174         Op = Op->Common.Parent;
175     }
176
177     if (!Op)
178     {
179         return (NULL);
180     }
181
182     /*
183      * Find the actual parent node for the reference:
184      * Remove all carat prefixes from the input path.
185      * There may be multiple parent prefixes (For example, ^^^M000)
186      */
187     Node = Op->Common.Node;
188     while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
189     {
190         Node = Node->Parent;
191         Path++;
192     }
193
194     if (!Node)
195     {
196         return (NULL);
197     }
198
199     /* Get the full pathname for the parent node */
200
201     ParentPath = AcpiNsGetExternalPathname (Node);
202     if (!ParentPath)
203     {
204         return (NULL);
205     }
206
207     Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
208     if (ParentPath[1])
209     {
210         /*
211          * If ParentPath is not just a simple '\', increment the length
212          * for the required dot separator (ParentPath.Path)
213          */
214         Length++;
215
216         /* For External() statements, we do not want a leading '\' */
217
218         if (*ParentPath == AML_ROOT_PREFIX)
219         {
220             Index = 1;
221         }
222     }
223
224     Fullpath = ACPI_ALLOCATE_ZEROED (Length);
225     if (!Fullpath)
226     {
227         goto Cleanup;
228     }
229
230     /*
231      * Concatenate parent fullpath and path. For example,
232      * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
233      *
234      * Copy the parent path
235      */
236     ACPI_STRCPY (Fullpath, &ParentPath[Index]);
237
238     /*
239      * Add dot separator
240      * (don't need dot if parent fullpath is a single backslash)
241      */
242     if (ParentPath[1])
243     {
244         ACPI_STRCAT (Fullpath, ".");
245     }
246
247     /* Copy child path (carat parent prefix(es) were skipped above) */
248
249     ACPI_STRCAT (Fullpath, Path);
250
251 Cleanup:
252     ACPI_FREE (ParentPath);
253     return (Fullpath);
254 }
255
256
257 /*******************************************************************************
258  *
259  * FUNCTION:    AcpiDmAddToExternalFileList
260  *
261  * PARAMETERS:  PathList            - Single path or list separated by comma
262  *
263  * RETURN:      None
264  *
265  * DESCRIPTION: Add external files to global list
266  *
267  ******************************************************************************/
268
269 ACPI_STATUS
270 AcpiDmAddToExternalFileList (
271     char                    *PathList)
272 {
273     ACPI_EXTERNAL_FILE      *ExternalFile;
274     char                    *Path;
275     char                    *TmpPath;
276
277
278     if (!PathList)
279     {
280         return (AE_OK);
281     }
282
283     Path = strtok (PathList, ",");
284
285     while (Path)
286     {
287         TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
288         if (!TmpPath)
289         {
290             return (AE_NO_MEMORY);
291         }
292
293         ACPI_STRCPY (TmpPath, Path);
294
295         ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
296         if (!ExternalFile)
297         {
298             ACPI_FREE (TmpPath);
299             return (AE_NO_MEMORY);
300         }
301
302         ExternalFile->Path = TmpPath;
303
304         if (AcpiGbl_ExternalFileList)
305         {
306             ExternalFile->Next = AcpiGbl_ExternalFileList;
307         }
308
309         AcpiGbl_ExternalFileList = ExternalFile;
310         Path = strtok (NULL, ",");
311     }
312
313     return (AE_OK);
314 }
315
316
317 /*******************************************************************************
318  *
319  * FUNCTION:    AcpiDmClearExternalFileList
320  *
321  * PARAMETERS:  None
322  *
323  * RETURN:      None
324  *
325  * DESCRIPTION: Clear the external file list
326  *
327  ******************************************************************************/
328
329 void
330 AcpiDmClearExternalFileList (
331     void)
332 {
333     ACPI_EXTERNAL_FILE      *NextExternal;
334
335
336     while (AcpiGbl_ExternalFileList)
337     {
338         NextExternal = AcpiGbl_ExternalFileList->Next;
339         ACPI_FREE (AcpiGbl_ExternalFileList->Path);
340         ACPI_FREE (AcpiGbl_ExternalFileList);
341         AcpiGbl_ExternalFileList = NextExternal;
342     }
343 }
344
345
346 /*******************************************************************************
347  *
348  * FUNCTION:    AcpiDmAddToExternalList
349  *
350  * PARAMETERS:  Op                  - Current parser Op
351  *              Path                - Internal (AML) path to the object
352  *              Type                - ACPI object type to be added
353  *              Value               - Arg count if adding a Method object
354  *
355  * RETURN:      None
356  *
357  * DESCRIPTION: Insert a new name into the global list of Externals which
358  *              will in turn be later emitted as an External() declaration
359  *              in the disassembled output.
360  *
361  ******************************************************************************/
362
363 void
364 AcpiDmAddToExternalList (
365     ACPI_PARSE_OBJECT       *Op,
366     char                    *Path,
367     UINT8                   Type,
368     UINT32                  Value)
369 {
370     char                    *ExternalPath;
371     char                    *Fullpath = NULL;
372     ACPI_EXTERNAL_LIST      *NewExternal;
373     ACPI_EXTERNAL_LIST      *NextExternal;
374     ACPI_EXTERNAL_LIST      *PrevExternal = NULL;
375     ACPI_STATUS             Status;
376
377
378     if (!Path)
379     {
380         return;
381     }
382
383     /*
384      * We don't want External() statements to contain a leading '\'.
385      * This prevents duplicate external statements of the form:
386      *
387      *    External (\ABCD)
388      *    External (ABCD)
389      *
390      * This would cause a compile time error when the disassembled
391      * output file is recompiled.
392      */
393     if ((*Path == AML_ROOT_PREFIX) && (Path[1]))
394     {
395         Path++;
396     }
397
398     /* Externalize the ACPI pathname */
399
400     Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
401                 NULL, &ExternalPath);
402     if (ACPI_FAILURE (Status))
403     {
404         return;
405     }
406
407     /*
408      * Get the full pathname from the root if "Path" has one or more
409      * parent prefixes (^). Note: path will not contain a leading '\'.
410      */
411     if (*Path == (UINT8) AML_PARENT_PREFIX)
412     {
413         Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
414         if (Fullpath)
415         {
416             /* Set new external path */
417
418             ACPI_FREE (ExternalPath);
419             ExternalPath = Fullpath;
420         }
421     }
422
423     /* Check all existing externals to ensure no duplicates */
424
425     NextExternal = AcpiGbl_ExternalList;
426     while (NextExternal)
427     {
428         if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
429         {
430             /* Duplicate method, check that the Value (ArgCount) is the same */
431
432             if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
433                 (NextExternal->Value != Value))
434             {
435                 ACPI_ERROR ((AE_INFO,
436                     "Argument count mismatch for method %s %u %u",
437                     NextExternal->Path, NextExternal->Value, Value));
438             }
439
440             /* Allow upgrade of type from ANY */
441
442             else if (NextExternal->Type == ACPI_TYPE_ANY)
443             {
444                 NextExternal->Type = Type;
445                 NextExternal->Value = Value;
446             }
447
448             ACPI_FREE (ExternalPath);
449             return;
450         }
451
452         NextExternal = NextExternal->Next;
453     }
454
455     /* Allocate and init a new External() descriptor */
456
457     NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
458     if (!NewExternal)
459     {
460         ACPI_FREE (ExternalPath);
461         return;
462     }
463
464     NewExternal->Path = ExternalPath;
465     NewExternal->Type = Type;
466     NewExternal->Value = Value;
467     NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
468
469     /* Was the external path with parent prefix normalized to a fullpath? */
470
471     if (Fullpath == ExternalPath)
472     {
473         /* Get new internal path */
474
475         Status = AcpiNsInternalizeName (ExternalPath, &Path);
476         if (ACPI_FAILURE (Status))
477         {
478             ACPI_FREE (ExternalPath);
479             ACPI_FREE (NewExternal);
480             return;
481         }
482
483         /* Set flag to indicate External->InternalPath need to be freed */
484
485         NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
486     }
487
488     NewExternal->InternalPath = Path;
489
490     /* Link the new descriptor into the global list, alphabetically ordered */
491
492     NextExternal = AcpiGbl_ExternalList;
493     while (NextExternal)
494     {
495         if (AcpiUtStricmp (NewExternal->Path, NextExternal->Path) < 0)
496         {
497             if (PrevExternal)
498             {
499                 PrevExternal->Next = NewExternal;
500             }
501             else
502             {
503                 AcpiGbl_ExternalList = NewExternal;
504             }
505
506             NewExternal->Next = NextExternal;
507             return;
508         }
509
510         PrevExternal = NextExternal;
511         NextExternal = NextExternal->Next;
512     }
513
514     if (PrevExternal)
515     {
516         PrevExternal->Next = NewExternal;
517     }
518     else
519     {
520         AcpiGbl_ExternalList = NewExternal;
521     }
522 }
523
524
525 /*******************************************************************************
526  *
527  * FUNCTION:    AcpiDmAddExternalsToNamespace
528  *
529  * PARAMETERS:  None
530  *
531  * RETURN:      None
532  *
533  * DESCRIPTION: Add all externals to the namespace. Allows externals to be
534  *              "resolved".
535  *
536  ******************************************************************************/
537
538 void
539 AcpiDmAddExternalsToNamespace (
540     void)
541 {
542     ACPI_STATUS             Status;
543     ACPI_NAMESPACE_NODE     *Node;
544     ACPI_OPERAND_OBJECT     *ObjDesc;
545     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
546
547
548     while (External)
549     {
550         /* Add the external name (object) into the namespace */
551
552         Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
553                    ACPI_IMODE_LOAD_PASS1,
554                    ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
555                    NULL, &Node);
556
557         if (ACPI_FAILURE (Status))
558         {
559             ACPI_EXCEPTION ((AE_INFO, Status,
560                 "while adding external to namespace [%s]",
561                 External->Path));
562         }
563
564         else switch (External->Type)
565         {
566         case ACPI_TYPE_METHOD:
567
568             /* For methods, we need to save the argument count */
569
570             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
571             ObjDesc->Method.ParamCount = (UINT8) External->Value;
572             Node->Object = ObjDesc;
573             break;
574
575         case ACPI_TYPE_REGION:
576
577             /* Regions require a region sub-object */
578
579             ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_REGION);
580             ObjDesc->Region.Node = Node;
581             Node->Object = ObjDesc;
582             break;
583
584         default:
585             break;
586         }
587
588         External = External->Next;
589     }
590 }
591
592
593 /*******************************************************************************
594  *
595  * FUNCTION:    AcpiDmGetExternalMethodCount
596  *
597  * PARAMETERS:  None
598  *
599  * RETURN:      The number of control method externals in the external list
600  *
601  * DESCRIPTION: Return the number of method externals that have been generated.
602  *              If any control method externals have been found, we must
603  *              re-parse the entire definition block with the new information
604  *              (number of arguments for the methods.) This is limitation of
605  *              AML, we don't know the number of arguments from the control
606  *              method invocation itself.
607  *
608  ******************************************************************************/
609
610 UINT32
611 AcpiDmGetExternalMethodCount (
612     void)
613 {
614     ACPI_EXTERNAL_LIST      *External = AcpiGbl_ExternalList;
615     UINT32                  Count = 0;
616
617
618     while (External)
619     {
620         if (External->Type == ACPI_TYPE_METHOD)
621         {
622             Count++;
623         }
624
625         External = External->Next;
626     }
627
628     return (Count);
629 }
630
631
632 /*******************************************************************************
633  *
634  * FUNCTION:    AcpiDmClearExternalList
635  *
636  * PARAMETERS:  None
637  *
638  * RETURN:      None
639  *
640  * DESCRIPTION: Free the entire External info list
641  *
642  ******************************************************************************/
643
644 void
645 AcpiDmClearExternalList (
646     void)
647 {
648     ACPI_EXTERNAL_LIST      *NextExternal;
649
650
651     while (AcpiGbl_ExternalList)
652     {
653         NextExternal = AcpiGbl_ExternalList->Next;
654         ACPI_FREE (AcpiGbl_ExternalList->Path);
655         ACPI_FREE (AcpiGbl_ExternalList);
656         AcpiGbl_ExternalList = NextExternal;
657     }
658 }
659
660
661 /*******************************************************************************
662  *
663  * FUNCTION:    AcpiDmEmitExternals
664  *
665  * PARAMETERS:  None
666  *
667  * RETURN:      None
668  *
669  * DESCRIPTION: Emit an External() ASL statement for each of the externals in
670  *              the global external info list.
671  *
672  ******************************************************************************/
673
674 void
675 AcpiDmEmitExternals (
676     void)
677 {
678     ACPI_EXTERNAL_LIST      *NextExternal;
679
680
681     if (!AcpiGbl_ExternalList)
682     {
683         return;
684     }
685
686     /*
687      * Walk the list of externals (unresolved references)
688      * found during the AML parsing
689      */
690     while (AcpiGbl_ExternalList)
691     {
692         AcpiOsPrintf ("    External (%s%s",
693             AcpiGbl_ExternalList->Path,
694             AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
695
696         if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
697         {
698             AcpiOsPrintf (")    // %u Arguments\n",
699                 AcpiGbl_ExternalList->Value);
700         }
701         else
702         {
703             AcpiOsPrintf (")\n");
704         }
705
706         /* Free this external info block and move on to next external */
707
708         NextExternal = AcpiGbl_ExternalList->Next;
709         if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
710         {
711             ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
712         }
713
714         ACPI_FREE (AcpiGbl_ExternalList->Path);
715         ACPI_FREE (AcpiGbl_ExternalList);
716         AcpiGbl_ExternalList = NextExternal;
717     }
718
719     AcpiOsPrintf ("\n");
720 }