Sync ACPICA with Intel's version 20151124.
[dragonfly.git] / sys / contrib / dev / acpica / source / common / adisasm.c
1 /******************************************************************************
2  *
3  * Module Name: adisasm - Application-level disassembler routines
4  *
5  *****************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2015, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43
44 #include "aslcompiler.h"
45 #include "amlcode.h"
46 #include "acdisasm.h"
47 #include "acdispat.h"
48 #include "acnamesp.h"
49 #include "acparser.h"
50 #include "acapps.h"
51
52 #include <stdio.h>
53
54
55 #define _COMPONENT          ACPI_TOOLS
56         ACPI_MODULE_NAME    ("adisasm")
57
58 /* Local prototypes */
59
60 static ACPI_STATUS
61 AdDoExternalFileList (
62     char                    *Filename);
63
64 static ACPI_STATUS
65 AdDisassembleOneTable (
66     ACPI_TABLE_HEADER       *Table,
67     FILE                    *File,
68     char                    *Filename,
69     char                    *DisasmFilename);
70
71 static ACPI_STATUS
72 AdReparseOneTable (
73     ACPI_TABLE_HEADER       *Table,
74     FILE                    *File,
75     ACPI_OWNER_ID           OwnerId);
76
77
78 ACPI_TABLE_DESC             LocalTables[1];
79 ACPI_PARSE_OBJECT           *AcpiGbl_ParseOpRoot;
80
81
82 /* Stubs for everything except ASL compiler */
83
84 #ifndef ACPI_ASL_COMPILER
85 BOOLEAN
86 AcpiDsIsResultUsed (
87     ACPI_PARSE_OBJECT       *Op,
88     ACPI_WALK_STATE         *WalkState)
89 {
90     return (TRUE);
91 }
92
93 ACPI_STATUS
94 AcpiDsMethodError (
95     ACPI_STATUS             Status,
96     ACPI_WALK_STATE         *WalkState)
97 {
98     return (Status);
99 }
100 #endif
101
102
103 /*******************************************************************************
104  *
105  * FUNCTION:    AdInitialize
106  *
107  * PARAMETERS:  None
108  *
109  * RETURN:      Status
110  *
111  * DESCRIPTION: ACPICA and local initialization
112  *
113  ******************************************************************************/
114
115 ACPI_STATUS
116 AdInitialize (
117     void)
118 {
119     ACPI_STATUS             Status;
120
121
122     /* ACPICA subsystem initialization */
123
124     Status = AcpiOsInitialize ();
125     if (ACPI_FAILURE (Status))
126     {
127         return (Status);
128     }
129
130     Status = AcpiUtInitGlobals ();
131     if (ACPI_FAILURE (Status))
132     {
133         return (Status);
134     }
135
136     Status = AcpiUtMutexInitialize ();
137     if (ACPI_FAILURE (Status))
138     {
139         return (Status);
140     }
141
142     Status = AcpiNsRootInitialize ();
143     if (ACPI_FAILURE (Status))
144     {
145         return (Status);
146     }
147
148     /* Setup the Table Manager (cheat - there is no RSDT) */
149
150     AcpiGbl_RootTableList.MaxTableCount = 1;
151     AcpiGbl_RootTableList.CurrentTableCount = 0;
152     AcpiGbl_RootTableList.Tables = LocalTables;
153
154     return (Status);
155 }
156
157
158 /******************************************************************************
159  *
160  * FUNCTION:    AdAmlDisassemble
161  *
162  * PARAMETERS:  Filename            - AML input filename
163  *              OutToFile           - TRUE if output should go to a file
164  *              Prefix              - Path prefix for output
165  *              OutFilename         - where the filename is returned
166  *
167  * RETURN:      Status
168  *
169  * DESCRIPTION: Disassembler entry point. Disassemble an entire ACPI table.
170  *
171  *****************************************************************************/
172
173 ACPI_STATUS
174 AdAmlDisassemble (
175     BOOLEAN                 OutToFile,
176     char                    *Filename,
177     char                    *Prefix,
178     char                    **OutFilename)
179 {
180     ACPI_STATUS             Status;
181     char                    *DisasmFilename = NULL;
182     FILE                    *File = NULL;
183     ACPI_TABLE_HEADER       *Table = NULL;
184     ACPI_NEW_TABLE_DESC     *ListHead = NULL;
185
186
187     /*
188      * Input: AML code from either a file or via GetTables (memory or
189      * registry)
190      */
191     if (Filename)
192     {
193         /* Get the list of all AML tables in the file */
194
195         Status = AcpiAcGetAllTablesFromFile (Filename,
196             ACPI_GET_ALL_TABLES, &ListHead);
197         if (ACPI_FAILURE (Status))
198         {
199             return (Status);
200         }
201
202         /* Process any user-specified files for external objects */
203
204         Status = AdDoExternalFileList (Filename);
205         if (ACPI_FAILURE (Status))
206         {
207             return (Status);
208         }
209     }
210     else
211     {
212         Status = AdGetLocalTables ();
213         if (ACPI_FAILURE (Status))
214         {
215             AcpiOsPrintf ("Could not get ACPI tables, %s\n",
216                 AcpiFormatException (Status));
217             return (Status);
218         }
219
220         if (!AcpiGbl_DmOpt_Disasm)
221         {
222             return (AE_OK);
223         }
224
225         /* Obtained the local tables, just disassemble the DSDT */
226
227         Status = AcpiGetTable (ACPI_SIG_DSDT, 0, &Table);
228         if (ACPI_FAILURE (Status))
229         {
230             AcpiOsPrintf ("Could not get DSDT, %s\n",
231                 AcpiFormatException (Status));
232             return (Status);
233         }
234
235         AcpiOsPrintf ("\nDisassembly of DSDT\n");
236         Prefix = AdGenerateFilename ("dsdt", Table->OemTableId);
237     }
238
239     /*
240      * Output: ASL code. Redirect to a file if requested
241      */
242     if (OutToFile)
243     {
244         /* Create/Open a disassembly output file */
245
246         DisasmFilename = FlGenerateFilename (Prefix, FILE_SUFFIX_DISASSEMBLY);
247         if (!DisasmFilename)
248         {
249             fprintf (stderr, "Could not generate output filename\n");
250             Status = AE_ERROR;
251             goto Cleanup;
252         }
253
254         File = fopen (DisasmFilename, "w+");
255         if (!File)
256         {
257             fprintf (stderr, "Could not open output file %s\n",
258                 DisasmFilename);
259             Status = AE_ERROR;
260             goto Cleanup;
261         }
262
263         AcpiOsRedirectOutput (File);
264     }
265
266     *OutFilename = DisasmFilename;
267
268     /* Disassemble all AML tables within the file */
269
270     while (ListHead)
271     {
272         Status = AdDisassembleOneTable (ListHead->Table,
273             File, Filename, DisasmFilename);
274         if (ACPI_FAILURE (Status))
275         {
276             break;
277         }
278
279         ListHead = ListHead->Next;
280     }
281
282 Cleanup:
283
284 // check!
285 #if 0
286     if (Table && !AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
287     {
288         ACPI_FREE (Table);
289     }
290 #endif
291
292     if (File)
293     {
294         fclose (File);
295         AcpiOsRedirectOutput (stdout);
296     }
297
298     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
299     AcpiGbl_ParseOpRoot = NULL;
300     return (Status);
301 }
302
303
304 /******************************************************************************
305  *
306  * FUNCTION:    AdDisassembleOneTable
307  *
308  * PARAMETERS:  Table               - Raw AML table
309  *              File                - Pointer for the input file
310  *              Filename            - AML input filename
311  *              DisasmFilename      - Output filename
312  *
313  * RETURN:      Status
314  *
315  * DESCRIPTION: Disassemble a single ACPI table. AML or data table.
316  *
317  *****************************************************************************/
318
319 static ACPI_STATUS
320 AdDisassembleOneTable (
321     ACPI_TABLE_HEADER       *Table,
322     FILE                    *File,
323     char                    *Filename,
324     char                    *DisasmFilename)
325 {
326     ACPI_STATUS             Status;
327     ACPI_OWNER_ID           OwnerId;
328
329
330     /* ForceAmlDisassembly means to assume the table contains valid AML */
331
332     if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
333     {
334         AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
335
336         /* This is a "Data Table" (non-AML table) */
337
338         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
339             Table->Signature);
340         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
341             "FieldName : FieldValue\n */\n\n");
342
343         AcpiDmDumpDataTable (Table);
344         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
345             Table->Signature);
346
347         if (File)
348         {
349             fprintf (stderr, "Formatted output:  %s - %u bytes\n",
350                 DisasmFilename, CmGetFileSize (File));
351         }
352
353         return (AE_OK);
354     }
355
356     /*
357      * This is an AML table (DSDT or SSDT).
358      * Always parse the tables, only option is what to display
359      */
360     Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
361     if (ACPI_FAILURE (Status))
362     {
363         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
364             AcpiFormatException (Status));
365         return (Status);
366     }
367
368     /* Debug output, namespace and parse tree */
369
370     if (AslCompilerdebug && File)
371     {
372         AcpiOsPrintf ("/**** Before second load\n");
373
374         NsSetupNamespaceListing (File);
375         NsDisplayNamespace ();
376
377         AcpiOsPrintf ("*****/\n");
378     }
379
380     /* Load namespace from names created within control methods */
381
382     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
383         AcpiGbl_RootNode, OwnerId);
384
385     /*
386      * Cross reference the namespace here, in order to
387      * generate External() statements
388      */
389     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
390         AcpiGbl_RootNode, OwnerId);
391
392     if (AslCompilerdebug)
393     {
394         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
395     }
396
397     /* Find possible calls to external control methods */
398
399     AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
400
401     /*
402      * If we found any external control methods, we must reparse
403      * the entire tree with the new information (namely, the
404      * number of arguments per method)
405      */
406     if (AcpiDmGetExternalMethodCount ())
407     {
408         Status = AdReparseOneTable (Table, File, OwnerId);
409         if (ACPI_FAILURE (Status))
410         {
411             return (Status);
412         }
413     }
414
415     /*
416      * Now that the namespace is finalized, we can perform namespace
417      * transforms.
418      *
419      * 1) Convert fixed-offset references to resource descriptors
420      *    to symbolic references (Note: modifies namespace)
421      */
422     AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
423
424     /* Optional displays */
425
426     if (AcpiGbl_DmOpt_Disasm)
427     {
428         /* This is the real disassembly */
429
430         AdDisplayTables (Filename, Table);
431
432         /* Dump hex table if requested (-vt) */
433
434         AcpiDmDumpDataTable (Table);
435
436         fprintf (stderr, "Disassembly completed\n");
437         if (File)
438         {
439             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
440                 DisasmFilename, CmGetFileSize (File));
441         }
442
443         if (Gbl_MapfileFlag)
444         {
445             fprintf (stderr, "%14s %s - %u bytes\n",
446                 Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription,
447                 Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename,
448                 FlGetFileSize (ASL_FILE_MAP_OUTPUT));
449         }
450     }
451
452     return (AE_OK);
453 }
454
455
456 /******************************************************************************
457  *
458  * FUNCTION:    AdReparseOneTable
459  *
460  * PARAMETERS:  Table               - Raw AML table
461  *              File                - Pointer for the input file
462  *              OwnerId             - ID for this table
463  *
464  * RETURN:      Status
465  *
466  * DESCRIPTION: Reparse a table that has already been loaded. Used to
467  *              integrate information about external control methods.
468  *              These methods may have been previously parsed incorrectly.
469  *
470  *****************************************************************************/
471
472 static ACPI_STATUS
473 AdReparseOneTable (
474     ACPI_TABLE_HEADER       *Table,
475     FILE                    *File,
476     ACPI_OWNER_ID           OwnerId)
477 {
478     ACPI_STATUS             Status;
479
480
481     fprintf (stderr,
482         "\nFound %u external control methods, "
483         "reparsing with new information\n",
484         AcpiDmGetExternalMethodCount ());
485
486     /* Reparse, rebuild namespace */
487
488     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
489     AcpiGbl_ParseOpRoot = NULL;
490     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
491
492     AcpiGbl_RootNode                    = NULL;
493     AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
494     AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
495     AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
496     AcpiGbl_RootNodeStruct.Parent       = NULL;
497     AcpiGbl_RootNodeStruct.Child        = NULL;
498     AcpiGbl_RootNodeStruct.Peer         = NULL;
499     AcpiGbl_RootNodeStruct.Object       = NULL;
500     AcpiGbl_RootNodeStruct.Flags        = 0;
501
502     Status = AcpiNsRootInitialize ();
503     if (ACPI_FAILURE (Status))
504     {
505         return (Status);
506     }
507
508     /* New namespace, add the external definitions first */
509
510     AcpiDmAddExternalsToNamespace ();
511
512     /* Parse the table again. No need to reload it, however */
513
514     Status = AdParseTable (Table, NULL, FALSE, FALSE);
515     if (ACPI_FAILURE (Status))
516     {
517         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
518             AcpiFormatException (Status));
519         return (Status);
520     }
521
522     /* Cross reference the namespace again */
523
524     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
525         AcpiGbl_RootNode, OwnerId);
526
527     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
528         AcpiGbl_RootNode, OwnerId);
529
530     /* Debug output - namespace and parse tree */
531
532     if (AslCompilerdebug)
533     {
534         AcpiOsPrintf ("/**** After second load and resource conversion\n");
535         if (File)
536         {
537             NsSetupNamespaceListing (File);
538             NsDisplayNamespace ();
539         }
540
541         AcpiOsPrintf ("*****/\n");
542         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
543     }
544
545     return (AE_OK);
546 }
547
548
549 /******************************************************************************
550  *
551  * FUNCTION:    AdDoExternalFileList
552  *
553  * PARAMETERS:  Filename            - Input file for the table
554  *
555  * RETURN:      Status
556  *
557  * DESCRIPTION: Process all tables found in the -e external files list
558  *
559  *****************************************************************************/
560
561 static ACPI_STATUS
562 AdDoExternalFileList (
563     char                    *Filename)
564 {
565     ACPI_EXTERNAL_FILE      *ExternalFileList;
566     char                    *ExternalFilename;
567     ACPI_NEW_TABLE_DESC     *ExternalListHead = NULL;
568     ACPI_STATUS             Status;
569     ACPI_STATUS             GlobalStatus = AE_OK;
570     ACPI_OWNER_ID           OwnerId;
571
572
573     /*
574      * External filenames are specified on the command line like this:
575      * Example: iasl -e file1,file2,file3 -d xxx.aml
576      */
577     ExternalFileList = AcpiGbl_ExternalFileList;
578
579     /* Process each external file */
580
581     while (ExternalFileList)
582     {
583         ExternalFilename = ExternalFileList->Path;
584         if (!strcmp (ExternalFilename, Filename))
585         {
586             /* Next external file */
587
588             ExternalFileList = ExternalFileList->Next;
589             continue;
590         }
591
592         AcpiOsPrintf ("External object resolution file %16s\n",
593             ExternalFilename);
594
595         Status = AcpiAcGetAllTablesFromFile (
596             ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead);
597         if (ACPI_FAILURE (Status))
598         {
599             if (Status == AE_TYPE)
600             {
601                 ExternalFileList = ExternalFileList->Next;
602                 GlobalStatus = AE_TYPE;
603                 Status = AE_OK;
604                 continue;
605             }
606
607             return (Status);
608         }
609
610         /* Load external tables for symbol resolution */
611
612         while (ExternalListHead)
613         {
614             Status = AdParseTable (
615                 ExternalListHead->Table, &OwnerId, TRUE, TRUE);
616             if (ACPI_FAILURE (Status))
617             {
618                 AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
619                     AcpiFormatException (Status));
620                 return (Status);
621             }
622
623             /*
624              * Load namespace from names created within control methods
625              * Set owner id of nodes in external table
626              */
627             AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
628                 AcpiGbl_RootNode, OwnerId);
629             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
630
631             ExternalListHead = ExternalListHead->Next;
632         }
633
634         /* Next external file */
635
636         ExternalFileList = ExternalFileList->Next;
637     }
638
639     if (ACPI_FAILURE (GlobalStatus))
640     {
641         return (GlobalStatus);
642     }
643
644     /* Clear external list generated by Scope in external tables */
645
646     if (AcpiGbl_ExternalFileList)
647     {
648         AcpiDmClearExternalList ();
649     }
650
651     /* Load any externals defined in the optional external ref file */
652
653     AcpiDmGetExternalsFromFile ();
654     return (AE_OK);
655 }