xref: /illumos-gate/usr/src/cmd/acpi/common/adisasm.c (revision bc36eafd)
1 /******************************************************************************
2  *
3  * Module Name: adisasm - Application-level disassembler routines
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 = AcGetAllTablesFromFile (Filename,
196             ACPI_GET_ALL_TABLES, &ListHead);
197         if (ACPI_FAILURE (Status))
198         {
199             AcpiOsPrintf ("Could not get ACPI tables from %s, %s\n",
200                 Filename, AcpiFormatException (Status));
201             return (Status);
202         }
203 
204         /* Process any user-specified files for external objects */
205 
206         Status = AdDoExternalFileList (Filename);
207         if (ACPI_FAILURE (Status))
208         {
209             return (Status);
210         }
211     }
212     else
213     {
214         Status = AdGetLocalTables ();
215         if (ACPI_FAILURE (Status))
216         {
217             AcpiOsPrintf ("Could not get ACPI tables, %s\n",
218                 AcpiFormatException (Status));
219             return (Status);
220         }
221 
222         if (!AcpiGbl_DmOpt_Disasm)
223         {
224             return (AE_OK);
225         }
226 
227         /* Obtained the local tables, just disassemble the DSDT */
228 
229         Status = AcpiGetTable (ACPI_SIG_DSDT, 0, &Table);
230         if (ACPI_FAILURE (Status))
231         {
232             AcpiOsPrintf ("Could not get DSDT, %s\n",
233                 AcpiFormatException (Status));
234             return (Status);
235         }
236 
237         AcpiOsPrintf ("\nDisassembly of DSDT\n");
238         Prefix = AdGenerateFilename ("dsdt", Table->OemTableId);
239     }
240 
241     /*
242      * Output: ASL code. Redirect to a file if requested
243      */
244     if (OutToFile)
245     {
246         /* Create/Open a disassembly output file */
247 
248         DisasmFilename = FlGenerateFilename (Prefix, FILE_SUFFIX_DISASSEMBLY);
249         if (!DisasmFilename)
250         {
251             fprintf (stderr, "Could not generate output filename\n");
252             Status = AE_ERROR;
253             goto Cleanup;
254         }
255 
256         File = fopen (DisasmFilename, "w+");
257         if (!File)
258         {
259             fprintf (stderr, "Could not open output file %s\n",
260                 DisasmFilename);
261             Status = AE_ERROR;
262             goto Cleanup;
263         }
264 
265         AcpiOsRedirectOutput (File);
266     }
267 
268     *OutFilename = DisasmFilename;
269 
270     /* Disassemble all AML tables within the file */
271 
272     while (ListHead)
273     {
274         Status = AdDisassembleOneTable (ListHead->Table,
275             File, Filename, DisasmFilename);
276         if (ACPI_FAILURE (Status))
277         {
278             break;
279         }
280 
281         ListHead = ListHead->Next;
282     }
283 
284 Cleanup:
285 
286     if (Table &&
287         !AcpiGbl_ForceAmlDisassembly &&
288         !AcpiUtIsAmlTable (Table))
289     {
290         ACPI_FREE (Table);
291     }
292 
293     if (File)
294     {
295         fclose (File);
296         AcpiOsRedirectOutput (stdout);
297     }
298 
299     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
300     AcpiGbl_ParseOpRoot = NULL;
301     return (Status);
302 }
303 
304 
305 /******************************************************************************
306  *
307  * FUNCTION:    AdDisassembleOneTable
308  *
309  * PARAMETERS:  Table               - Raw AML table
310  *              File                - Pointer for the input file
311  *              Filename            - AML input filename
312  *              DisasmFilename      - Output filename
313  *
314  * RETURN:      Status
315  *
316  * DESCRIPTION: Disassemble a single ACPI table. AML or data table.
317  *
318  *****************************************************************************/
319 
320 static ACPI_STATUS
321 AdDisassembleOneTable (
322     ACPI_TABLE_HEADER       *Table,
323     FILE                    *File,
324     char                    *Filename,
325     char                    *DisasmFilename)
326 {
327     ACPI_STATUS             Status;
328     ACPI_OWNER_ID           OwnerId;
329 
330 
331     /* ForceAmlDisassembly means to assume the table contains valid AML */
332 
333     if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
334     {
335         AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
336 
337         /* This is a "Data Table" (non-AML table) */
338 
339         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
340             Table->Signature);
341         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
342             "FieldName : FieldValue\n */\n\n");
343 
344         AcpiDmDumpDataTable (Table);
345         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
346             Table->Signature);
347 
348         if (File)
349         {
350             fprintf (stderr, "Formatted output:  %s - %u bytes\n",
351                 DisasmFilename, CmGetFileSize (File));
352         }
353 
354         return (AE_OK);
355     }
356 
357     /*
358      * This is an AML table (DSDT or SSDT).
359      * Always parse the tables, only option is what to display
360      */
361     Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
362     if (ACPI_FAILURE (Status))
363     {
364         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
365             AcpiFormatException (Status));
366         return (Status);
367     }
368 
369     /* Debug output, namespace and parse tree */
370 
371     if (AslCompilerdebug && File)
372     {
373         AcpiOsPrintf ("/**** Before second load\n");
374 
375         NsSetupNamespaceListing (File);
376         NsDisplayNamespace ();
377 
378         AcpiOsPrintf ("*****/\n");
379     }
380 
381     /* Load namespace from names created within control methods */
382 
383     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
384         AcpiGbl_RootNode, OwnerId);
385 
386     /*
387      * Cross reference the namespace here, in order to
388      * generate External() statements
389      */
390     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
391         AcpiGbl_RootNode, OwnerId);
392 
393     if (AslCompilerdebug)
394     {
395         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
396     }
397 
398     /* Find possible calls to external control methods */
399 
400     AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
401 
402     /*
403      * If we found any external control methods, we must reparse
404      * the entire tree with the new information (namely, the
405      * number of arguments per method)
406      */
407     if (AcpiDmGetExternalMethodCount ())
408     {
409         Status = AdReparseOneTable (Table, File, OwnerId);
410         if (ACPI_FAILURE (Status))
411         {
412             return (Status);
413         }
414     }
415 
416     /*
417      * Now that the namespace is finalized, we can perform namespace
418      * transforms.
419      *
420      * 1) Convert fixed-offset references to resource descriptors
421      *    to symbolic references (Note: modifies namespace)
422      */
423     AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
424 
425     /* Optional displays */
426 
427     if (AcpiGbl_DmOpt_Disasm)
428     {
429         /* This is the real disassembly */
430 
431         AdDisplayTables (Filename, Table);
432 
433         /* Dump hex table if requested (-vt) */
434 
435         AcpiDmDumpDataTable (Table);
436 
437         fprintf (stderr, "Disassembly completed\n");
438         if (File)
439         {
440             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
441                 DisasmFilename, CmGetFileSize (File));
442         }
443 
444         if (Gbl_MapfileFlag)
445         {
446             fprintf (stderr, "%14s %s - %u bytes\n",
447                 Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription,
448                 Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename,
449                 FlGetFileSize (ASL_FILE_MAP_OUTPUT));
450         }
451     }
452 
453     return (AE_OK);
454 }
455 
456 
457 /******************************************************************************
458  *
459  * FUNCTION:    AdReparseOneTable
460  *
461  * PARAMETERS:  Table               - Raw AML table
462  *              File                - Pointer for the input file
463  *              OwnerId             - ID for this table
464  *
465  * RETURN:      Status
466  *
467  * DESCRIPTION: Reparse a table that has already been loaded. Used to
468  *              integrate information about external control methods.
469  *              These methods may have been previously parsed incorrectly.
470  *
471  *****************************************************************************/
472 
473 static ACPI_STATUS
474 AdReparseOneTable (
475     ACPI_TABLE_HEADER       *Table,
476     FILE                    *File,
477     ACPI_OWNER_ID           OwnerId)
478 {
479     ACPI_STATUS             Status;
480 
481 
482     fprintf (stderr,
483         "\nFound %u external control methods, "
484         "reparsing with new information\n",
485         AcpiDmGetExternalMethodCount ());
486 
487     /* Reparse, rebuild namespace */
488 
489     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
490     AcpiGbl_ParseOpRoot = NULL;
491     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
492 
493     AcpiGbl_RootNode                    = NULL;
494     AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
495     AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
496     AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
497     AcpiGbl_RootNodeStruct.Parent       = NULL;
498     AcpiGbl_RootNodeStruct.Child        = NULL;
499     AcpiGbl_RootNodeStruct.Peer         = NULL;
500     AcpiGbl_RootNodeStruct.Object       = NULL;
501     AcpiGbl_RootNodeStruct.Flags        = 0;
502 
503     Status = AcpiNsRootInitialize ();
504     if (ACPI_FAILURE (Status))
505     {
506         return (Status);
507     }
508 
509     /* New namespace, add the external definitions first */
510 
511     AcpiDmAddExternalsToNamespace ();
512 
513     /* Parse the table again. No need to reload it, however */
514 
515     Status = AdParseTable (Table, NULL, FALSE, FALSE);
516     if (ACPI_FAILURE (Status))
517     {
518         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
519             AcpiFormatException (Status));
520         return (Status);
521     }
522 
523     /* Cross reference the namespace again */
524 
525     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
526         AcpiGbl_RootNode, OwnerId);
527 
528     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
529         AcpiGbl_RootNode, OwnerId);
530 
531     /* Debug output - namespace and parse tree */
532 
533     if (AslCompilerdebug)
534     {
535         AcpiOsPrintf ("/**** After second load and resource conversion\n");
536         if (File)
537         {
538             NsSetupNamespaceListing (File);
539             NsDisplayNamespace ();
540         }
541 
542         AcpiOsPrintf ("*****/\n");
543         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
544     }
545 
546     return (AE_OK);
547 }
548 
549 
550 /******************************************************************************
551  *
552  * FUNCTION:    AdDoExternalFileList
553  *
554  * PARAMETERS:  Filename            - Input file for the table
555  *
556  * RETURN:      Status
557  *
558  * DESCRIPTION: Process all tables found in the -e external files list
559  *
560  *****************************************************************************/
561 
562 static ACPI_STATUS
563 AdDoExternalFileList (
564     char                    *Filename)
565 {
566     ACPI_EXTERNAL_FILE      *ExternalFileList;
567     char                    *ExternalFilename;
568     ACPI_NEW_TABLE_DESC     *ExternalListHead = NULL;
569     ACPI_STATUS             Status;
570     ACPI_STATUS             GlobalStatus = AE_OK;
571     ACPI_OWNER_ID           OwnerId;
572 
573 
574     /*
575      * External filenames are specified on the command line like this:
576      * Example: iasl -e file1,file2,file3 -d xxx.aml
577      */
578     ExternalFileList = AcpiGbl_ExternalFileList;
579 
580     /* Process each external file */
581 
582     while (ExternalFileList)
583     {
584         ExternalFilename = ExternalFileList->Path;
585         if (!strcmp (ExternalFilename, Filename))
586         {
587             /* Next external file */
588 
589             ExternalFileList = ExternalFileList->Next;
590             continue;
591         }
592 
593         AcpiOsPrintf ("External object resolution file %16s\n",
594             ExternalFilename);
595 
596         Status = AcGetAllTablesFromFile (
597             ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead);
598         if (ACPI_FAILURE (Status))
599         {
600             if (Status == AE_TYPE)
601             {
602                 ExternalFileList = ExternalFileList->Next;
603                 GlobalStatus = AE_TYPE;
604                 Status = AE_OK;
605                 continue;
606             }
607 
608             return (Status);
609         }
610 
611         /* Load external tables for symbol resolution */
612 
613         while (ExternalListHead)
614         {
615             Status = AdParseTable (
616                 ExternalListHead->Table, &OwnerId, TRUE, TRUE);
617             if (ACPI_FAILURE (Status))
618             {
619                 AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
620                     AcpiFormatException (Status));
621                 return (Status);
622             }
623 
624             /*
625              * Load namespace from names created within control methods
626              * Set owner id of nodes in external table
627              */
628             AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
629                 AcpiGbl_RootNode, OwnerId);
630             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
631 
632             ExternalListHead = ExternalListHead->Next;
633         }
634 
635         /* Next external file */
636 
637         ExternalFileList = ExternalFileList->Next;
638     }
639 
640     if (ACPI_FAILURE (GlobalStatus))
641     {
642         return (GlobalStatus);
643     }
644 
645     /* Clear external list generated by Scope in external tables */
646 
647     if (AcpiGbl_ExternalFileList)
648     {
649         AcpiDmClearExternalList ();
650     }
651 
652     /* Load any externals defined in the optional external ref file */
653 
654     AcpiDmGetExternalsFromFile ();
655     return (AE_OK);
656 }
657