xref: /freebsd/sys/contrib/dev/acpica/common/adisasm.c (revision 076ad2f8)
1 /******************************************************************************
2  *
3  * Module Name: adisasm - Application-level disassembler routines
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2017, 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/compiler/aslcompiler.h>
45 #include <contrib/dev/acpica/include/amlcode.h>
46 #include <contrib/dev/acpica/include/acdisasm.h>
47 #include <contrib/dev/acpica/include/acdispat.h>
48 #include <contrib/dev/acpica/include/acnamesp.h>
49 #include <contrib/dev/acpica/include/acparser.h>
50 #include <contrib/dev/acpica/include/acapps.h>
51 
52 
53 #define _COMPONENT          ACPI_TOOLS
54         ACPI_MODULE_NAME    ("adisasm")
55 
56 /* Local prototypes */
57 
58 static ACPI_STATUS
59 AdDoExternalFileList (
60     char                    *Filename);
61 
62 static ACPI_STATUS
63 AdDisassembleOneTable (
64     ACPI_TABLE_HEADER       *Table,
65     FILE                    *File,
66     char                    *Filename,
67     char                    *DisasmFilename);
68 
69 static ACPI_STATUS
70 AdReparseOneTable (
71     ACPI_TABLE_HEADER       *Table,
72     FILE                    *File,
73     ACPI_OWNER_ID           OwnerId);
74 
75 
76 ACPI_TABLE_DESC             LocalTables[1];
77 ACPI_PARSE_OBJECT           *AcpiGbl_ParseOpRoot;
78 
79 
80 /* Stubs for everything except ASL compiler */
81 
82 #ifndef ACPI_ASL_COMPILER
83 BOOLEAN
84 AcpiDsIsResultUsed (
85     ACPI_PARSE_OBJECT       *Op,
86     ACPI_WALK_STATE         *WalkState)
87 {
88     return (TRUE);
89 }
90 
91 ACPI_STATUS
92 AcpiDsMethodError (
93     ACPI_STATUS             Status,
94     ACPI_WALK_STATE         *WalkState)
95 {
96     return (Status);
97 }
98 #endif
99 
100 
101 /*******************************************************************************
102  *
103  * FUNCTION:    AdInitialize
104  *
105  * PARAMETERS:  None
106  *
107  * RETURN:      Status
108  *
109  * DESCRIPTION: ACPICA and local initialization
110  *
111  ******************************************************************************/
112 
113 ACPI_STATUS
114 AdInitialize (
115     void)
116 {
117     ACPI_STATUS             Status;
118 
119 
120     /* ACPICA subsystem initialization */
121 
122     Status = AcpiOsInitialize ();
123     if (ACPI_FAILURE (Status))
124     {
125         return (Status);
126     }
127 
128     Status = AcpiUtInitGlobals ();
129     if (ACPI_FAILURE (Status))
130     {
131         return (Status);
132     }
133 
134     Status = AcpiUtMutexInitialize ();
135     if (ACPI_FAILURE (Status))
136     {
137         return (Status);
138     }
139 
140     Status = AcpiNsRootInitialize ();
141     if (ACPI_FAILURE (Status))
142     {
143         return (Status);
144     }
145 
146     /* Setup the Table Manager (cheat - there is no RSDT) */
147 
148     AcpiGbl_RootTableList.MaxTableCount = 1;
149     AcpiGbl_RootTableList.CurrentTableCount = 0;
150     AcpiGbl_RootTableList.Tables = LocalTables;
151 
152     return (Status);
153 }
154 
155 
156 /******************************************************************************
157  *
158  * FUNCTION:    AdAmlDisassemble
159  *
160  * PARAMETERS:  Filename            - AML input filename
161  *              OutToFile           - TRUE if output should go to a file
162  *              Prefix              - Path prefix for output
163  *              OutFilename         - where the filename is returned
164  *
165  * RETURN:      Status
166  *
167  * DESCRIPTION: Disassembler entry point. Disassemble an entire ACPI table.
168  *
169  *****************************************************************************/
170 
171 ACPI_STATUS
172 AdAmlDisassemble (
173     BOOLEAN                 OutToFile,
174     char                    *Filename,
175     char                    *Prefix,
176     char                    **OutFilename)
177 {
178     ACPI_STATUS             Status;
179     char                    *DisasmFilename = NULL;
180     FILE                    *File = NULL;
181     ACPI_TABLE_HEADER       *Table = NULL;
182     ACPI_NEW_TABLE_DESC     *ListHead = NULL;
183 
184 
185     /*
186      * Input: AML code from either a file or via GetTables (memory or
187      * registry)
188      */
189     if (Filename)
190     {
191         /* Get the list of all AML tables in the file */
192 
193         Status = AcGetAllTablesFromFile (Filename,
194             ACPI_GET_ALL_TABLES, &ListHead);
195         if (ACPI_FAILURE (Status))
196         {
197             AcpiOsPrintf ("Could not get ACPI tables from %s, %s\n",
198                 Filename, AcpiFormatException (Status));
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     if (Table &&
285         !AcpiGbl_ForceAmlDisassembly &&
286         !AcpiUtIsAmlTable (Table))
287     {
288         ACPI_FREE (Table);
289     }
290 
291     if (File)
292     {
293         fclose (File);
294         AcpiOsRedirectOutput (stdout);
295     }
296 
297     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
298     AcpiGbl_ParseOpRoot = NULL;
299     return (Status);
300 }
301 
302 
303 /******************************************************************************
304  *
305  * FUNCTION:    AdDisassembleOneTable
306  *
307  * PARAMETERS:  Table               - Raw AML table
308  *              File                - Pointer for the input file
309  *              Filename            - AML input filename
310  *              DisasmFilename      - Output filename
311  *
312  * RETURN:      Status
313  *
314  * DESCRIPTION: Disassemble a single ACPI table. AML or data table.
315  *
316  *****************************************************************************/
317 
318 static ACPI_STATUS
319 AdDisassembleOneTable (
320     ACPI_TABLE_HEADER       *Table,
321     FILE                    *File,
322     char                    *Filename,
323     char                    *DisasmFilename)
324 {
325     ACPI_STATUS             Status;
326     ACPI_OWNER_ID           OwnerId;
327 
328 
329     /* ForceAmlDisassembly means to assume the table contains valid AML */
330 
331     if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
332     {
333         AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
334 
335         /* This is a "Data Table" (non-AML table) */
336 
337         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
338             Table->Signature);
339         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
340             "FieldName : FieldValue\n */\n\n");
341 
342         AcpiDmDumpDataTable (Table);
343         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
344             Table->Signature);
345 
346         if (File)
347         {
348             fprintf (stderr, "Formatted output:  %s - %u bytes\n",
349                 DisasmFilename, CmGetFileSize (File));
350         }
351 
352         return (AE_OK);
353     }
354 
355     /*
356      * This is an AML table (DSDT or SSDT).
357      * Always parse the tables, only option is what to display
358      */
359     Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
360     if (ACPI_FAILURE (Status))
361     {
362         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
363             AcpiFormatException (Status));
364         return (Status);
365     }
366 
367     /* Debug output, namespace and parse tree */
368 
369     if (AslCompilerdebug && File)
370     {
371         AcpiOsPrintf ("/**** Before second load\n");
372 
373         NsSetupNamespaceListing (File);
374         NsDisplayNamespace ();
375 
376         AcpiOsPrintf ("*****/\n");
377     }
378 
379     /* Load namespace from names created within control methods */
380 
381     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
382         AcpiGbl_RootNode, OwnerId);
383 
384     /*
385      * Cross reference the namespace here, in order to
386      * generate External() statements
387      */
388     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
389         AcpiGbl_RootNode, OwnerId);
390 
391     if (AslCompilerdebug)
392     {
393         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
394     }
395 
396     /* Find possible calls to external control methods */
397 
398     AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
399 
400     /*
401      * If we found any external control methods, we must reparse
402      * the entire tree with the new information (namely, the
403      * number of arguments per method)
404      */
405     if (AcpiDmGetExternalMethodCount ())
406     {
407         Status = AdReparseOneTable (Table, File, OwnerId);
408         if (ACPI_FAILURE (Status))
409         {
410             return (Status);
411         }
412     }
413 
414     /*
415      * Now that the namespace is finalized, we can perform namespace
416      * transforms.
417      *
418      * 1) Convert fixed-offset references to resource descriptors
419      *    to symbolic references (Note: modifies namespace)
420      */
421     AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
422 
423     /* Optional displays */
424 
425     if (AcpiGbl_DmOpt_Disasm)
426     {
427         /* This is the real disassembly */
428 
429         AdDisplayTables (Filename, Table);
430 
431         /* Dump hex table if requested (-vt) */
432 
433         AcpiDmDumpDataTable (Table);
434 
435         fprintf (stderr, "Disassembly completed\n");
436         if (File)
437         {
438             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
439                 DisasmFilename, CmGetFileSize (File));
440         }
441 
442         if (Gbl_MapfileFlag)
443         {
444             fprintf (stderr, "%14s %s - %u bytes\n",
445                 Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription,
446                 Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename,
447                 FlGetFileSize (ASL_FILE_MAP_OUTPUT));
448         }
449     }
450 
451     return (AE_OK);
452 }
453 
454 
455 /******************************************************************************
456  *
457  * FUNCTION:    AdReparseOneTable
458  *
459  * PARAMETERS:  Table               - Raw AML table
460  *              File                - Pointer for the input file
461  *              OwnerId             - ID for this table
462  *
463  * RETURN:      Status
464  *
465  * DESCRIPTION: Reparse a table that has already been loaded. Used to
466  *              integrate information about external control methods.
467  *              These methods may have been previously parsed incorrectly.
468  *
469  *****************************************************************************/
470 
471 static ACPI_STATUS
472 AdReparseOneTable (
473     ACPI_TABLE_HEADER       *Table,
474     FILE                    *File,
475     ACPI_OWNER_ID           OwnerId)
476 {
477     ACPI_STATUS             Status;
478 
479 
480     fprintf (stderr,
481         "\nFound %u external control methods, "
482         "reparsing with new information\n",
483         AcpiDmGetExternalMethodCount ());
484 
485     /* Reparse, rebuild namespace */
486 
487     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
488     AcpiGbl_ParseOpRoot = NULL;
489     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
490 
491     AcpiGbl_RootNode                    = NULL;
492     AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
493     AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
494     AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
495     AcpiGbl_RootNodeStruct.Parent       = NULL;
496     AcpiGbl_RootNodeStruct.Child        = NULL;
497     AcpiGbl_RootNodeStruct.Peer         = NULL;
498     AcpiGbl_RootNodeStruct.Object       = NULL;
499     AcpiGbl_RootNodeStruct.Flags        = 0;
500 
501     Status = AcpiNsRootInitialize ();
502     if (ACPI_FAILURE (Status))
503     {
504         return (Status);
505     }
506 
507     /* New namespace, add the external definitions first */
508 
509     AcpiDmAddExternalsToNamespace ();
510 
511     /* Parse the table again. No need to reload it, however */
512 
513     Status = AdParseTable (Table, NULL, FALSE, FALSE);
514     if (ACPI_FAILURE (Status))
515     {
516         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
517             AcpiFormatException (Status));
518         return (Status);
519     }
520 
521     /* Cross reference the namespace again */
522 
523     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
524         AcpiGbl_RootNode, OwnerId);
525 
526     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
527         AcpiGbl_RootNode, OwnerId);
528 
529     /* Debug output - namespace and parse tree */
530 
531     if (AslCompilerdebug)
532     {
533         AcpiOsPrintf ("/**** After second load and resource conversion\n");
534         if (File)
535         {
536             NsSetupNamespaceListing (File);
537             NsDisplayNamespace ();
538         }
539 
540         AcpiOsPrintf ("*****/\n");
541         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
542     }
543 
544     return (AE_OK);
545 }
546 
547 
548 /******************************************************************************
549  *
550  * FUNCTION:    AdDoExternalFileList
551  *
552  * PARAMETERS:  Filename            - Input file for the table
553  *
554  * RETURN:      Status
555  *
556  * DESCRIPTION: Process all tables found in the -e external files list
557  *
558  *****************************************************************************/
559 
560 static ACPI_STATUS
561 AdDoExternalFileList (
562     char                    *Filename)
563 {
564     ACPI_EXTERNAL_FILE      *ExternalFileList;
565     char                    *ExternalFilename;
566     ACPI_NEW_TABLE_DESC     *ExternalListHead = NULL;
567     ACPI_STATUS             Status;
568     ACPI_STATUS             GlobalStatus = AE_OK;
569     ACPI_OWNER_ID           OwnerId;
570 
571 
572     /*
573      * External filenames are specified on the command line like this:
574      * Example: iasl -e file1,file2,file3 -d xxx.aml
575      */
576     ExternalFileList = AcpiGbl_ExternalFileList;
577 
578     /* Process each external file */
579 
580     while (ExternalFileList)
581     {
582         ExternalFilename = ExternalFileList->Path;
583         if (!strcmp (ExternalFilename, Filename))
584         {
585             /* Next external file */
586 
587             ExternalFileList = ExternalFileList->Next;
588             continue;
589         }
590 
591         AcpiOsPrintf ("External object resolution file %16s\n",
592             ExternalFilename);
593 
594         Status = AcGetAllTablesFromFile (
595             ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead);
596         if (ACPI_FAILURE (Status))
597         {
598             if (Status == AE_TYPE)
599             {
600                 ExternalFileList = ExternalFileList->Next;
601                 GlobalStatus = AE_TYPE;
602                 Status = AE_OK;
603                 continue;
604             }
605 
606             return (Status);
607         }
608 
609         /* Load external tables for symbol resolution */
610 
611         while (ExternalListHead)
612         {
613             Status = AdParseTable (
614                 ExternalListHead->Table, &OwnerId, TRUE, TRUE);
615             if (ACPI_FAILURE (Status))
616             {
617                 AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
618                     AcpiFormatException (Status));
619                 return (Status);
620             }
621 
622             /*
623              * Load namespace from names created within control methods
624              * Set owner id of nodes in external table
625              */
626             AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
627                 AcpiGbl_RootNode, OwnerId);
628             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
629 
630             ExternalListHead = ExternalListHead->Next;
631         }
632 
633         /* Next external file */
634 
635         ExternalFileList = ExternalFileList->Next;
636     }
637 
638     if (ACPI_FAILURE (GlobalStatus))
639     {
640         return (GlobalStatus);
641     }
642 
643     /* Clear external list generated by Scope in external tables */
644 
645     if (AcpiGbl_ExternalFileList)
646     {
647         AcpiDmClearExternalList ();
648     }
649 
650     /* Load any externals defined in the optional external ref file */
651 
652     AcpiDmGetExternalsFromFile ();
653     return (AE_OK);
654 }
655