xref: /dflybsd-src/sys/contrib/dev/acpica/source/common/adisasm.c (revision d638c6eedc81671c3ceddd06ef20463940cb6a43)
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 "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 
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 #ifdef ACPI_ASL_COMPILER
330 
331     /*
332      * For ASL-/ASL+ converter: replace the temporary "XXXX"
333      * table signature with the original. This "XXXX" makes
334      * it harder for the AML interpreter to run the badaml
335      * (.xxx) file produced from the converter in case if
336      * it fails to get deleted.
337      */
338     if (Gbl_CaptureComments)
339     {
340         strncpy (Table->Signature, AcpiGbl_TableSig, 4);
341     }
342 #endif
343 
344     /* ForceAmlDisassembly means to assume the table contains valid AML */
345 
346     if (!AcpiGbl_ForceAmlDisassembly && !AcpiUtIsAmlTable (Table))
347     {
348         AdDisassemblerHeader (Filename, ACPI_IS_DATA_TABLE);
349 
350         /* This is a "Data Table" (non-AML table) */
351 
352         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
353             Table->Signature);
354         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
355             "FieldName : FieldValue\n */\n\n");
356 
357         AcpiDmDumpDataTable (Table);
358         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
359             Table->Signature);
360 
361         if (File)
362         {
363             fprintf (stderr, "Formatted output:  %s - %u bytes\n",
364                 DisasmFilename, CmGetFileSize (File));
365         }
366 
367         return (AE_OK);
368     }
369 
370     /*
371      * This is an AML table (DSDT or SSDT).
372      * Always parse the tables, only option is what to display
373      */
374     Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
375     if (ACPI_FAILURE (Status))
376     {
377         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
378             AcpiFormatException (Status));
379         return (Status);
380     }
381 
382     /* Debug output, namespace and parse tree */
383 
384     if (AslCompilerdebug && File)
385     {
386         AcpiOsPrintf ("/**** Before second load\n");
387 
388         NsSetupNamespaceListing (File);
389         NsDisplayNamespace ();
390 
391         AcpiOsPrintf ("*****/\n");
392     }
393 
394     /* Load namespace from names created within control methods */
395 
396     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
397         AcpiGbl_RootNode, OwnerId);
398 
399     /*
400      * Cross reference the namespace here, in order to
401      * generate External() statements
402      */
403     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
404         AcpiGbl_RootNode, OwnerId);
405 
406     if (AslCompilerdebug)
407     {
408         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
409     }
410 
411     /* Find possible calls to external control methods */
412 
413     AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
414 
415     /*
416      * If we found any external control methods, we must reparse
417      * the entire tree with the new information (namely, the
418      * number of arguments per method)
419      */
420     if (AcpiDmGetExternalMethodCount ())
421     {
422         Status = AdReparseOneTable (Table, File, OwnerId);
423         if (ACPI_FAILURE (Status))
424         {
425             return (Status);
426         }
427     }
428 
429     /*
430      * Now that the namespace is finalized, we can perform namespace
431      * transforms.
432      *
433      * 1) Convert fixed-offset references to resource descriptors
434      *    to symbolic references (Note: modifies namespace)
435      */
436     AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
437 
438     /* Optional displays */
439 
440     if (AcpiGbl_DmOpt_Disasm)
441     {
442         /* This is the real disassembly */
443 
444         AdDisplayTables (Filename, Table);
445 
446         /* Dump hex table if requested (-vt) */
447 
448         AcpiDmDumpDataTable (Table);
449 
450         fprintf (stderr, "Disassembly completed\n");
451         if (File)
452         {
453             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
454                 DisasmFilename, CmGetFileSize (File));
455         }
456 
457         if (Gbl_MapfileFlag)
458         {
459             fprintf (stderr, "%14s %s - %u bytes\n",
460                 Gbl_Files[ASL_FILE_MAP_OUTPUT].ShortDescription,
461                 Gbl_Files[ASL_FILE_MAP_OUTPUT].Filename,
462                 FlGetFileSize (ASL_FILE_MAP_OUTPUT));
463         }
464     }
465 
466     return (AE_OK);
467 }
468 
469 
470 /******************************************************************************
471  *
472  * FUNCTION:    AdReparseOneTable
473  *
474  * PARAMETERS:  Table               - Raw AML table
475  *              File                - Pointer for the input file
476  *              OwnerId             - ID for this table
477  *
478  * RETURN:      Status
479  *
480  * DESCRIPTION: Reparse a table that has already been loaded. Used to
481  *              integrate information about external control methods.
482  *              These methods may have been previously parsed incorrectly.
483  *
484  *****************************************************************************/
485 
486 static ACPI_STATUS
487 AdReparseOneTable (
488     ACPI_TABLE_HEADER       *Table,
489     FILE                    *File,
490     ACPI_OWNER_ID           OwnerId)
491 {
492     ACPI_STATUS             Status;
493     ACPI_COMMENT_ADDR_NODE  *AddrListHead;
494 
495 
496     fprintf (stderr,
497         "\nFound %u external control methods, "
498         "reparsing with new information\n",
499         AcpiDmGetExternalMethodCount ());
500 
501     /* Reparse, rebuild namespace */
502 
503     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
504     AcpiGbl_ParseOpRoot = NULL;
505     AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
506 
507     AcpiGbl_RootNode                    = NULL;
508     AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
509     AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
510     AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
511     AcpiGbl_RootNodeStruct.Parent       = NULL;
512     AcpiGbl_RootNodeStruct.Child        = NULL;
513     AcpiGbl_RootNodeStruct.Peer         = NULL;
514     AcpiGbl_RootNodeStruct.Object       = NULL;
515     AcpiGbl_RootNodeStruct.Flags        = 0;
516 
517     Status = AcpiNsRootInitialize ();
518     if (ACPI_FAILURE (Status))
519     {
520         return (Status);
521     }
522 
523     /* New namespace, add the external definitions first */
524 
525     AcpiDmAddExternalsToNamespace ();
526 
527     /* For -ca option: clear the list of comment addresses. */
528 
529     while (AcpiGbl_CommentAddrListHead)
530     {
531         AddrListHead= AcpiGbl_CommentAddrListHead;
532         AcpiGbl_CommentAddrListHead = AcpiGbl_CommentAddrListHead->Next;
533         AcpiOsFree(AddrListHead);
534     }
535 
536     /* Parse the table again. No need to reload it, however */
537 
538     Status = AdParseTable (Table, NULL, FALSE, FALSE);
539     if (ACPI_FAILURE (Status))
540     {
541         AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
542             AcpiFormatException (Status));
543         return (Status);
544     }
545 
546     /* Cross reference the namespace again */
547 
548     AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
549         AcpiGbl_RootNode, OwnerId);
550 
551     AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
552         AcpiGbl_RootNode, OwnerId);
553 
554     /* Debug output - namespace and parse tree */
555 
556     if (AslCompilerdebug)
557     {
558         AcpiOsPrintf ("/**** After second load and resource conversion\n");
559         if (File)
560         {
561             NsSetupNamespaceListing (File);
562             NsDisplayNamespace ();
563         }
564 
565         AcpiOsPrintf ("*****/\n");
566         AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
567     }
568 
569     return (AE_OK);
570 }
571 
572 
573 /******************************************************************************
574  *
575  * FUNCTION:    AdDoExternalFileList
576  *
577  * PARAMETERS:  Filename            - Input file for the table
578  *
579  * RETURN:      Status
580  *
581  * DESCRIPTION: Process all tables found in the -e external files list
582  *
583  *****************************************************************************/
584 
585 static ACPI_STATUS
586 AdDoExternalFileList (
587     char                    *Filename)
588 {
589     ACPI_EXTERNAL_FILE      *ExternalFileList;
590     char                    *ExternalFilename;
591     ACPI_NEW_TABLE_DESC     *ExternalListHead = NULL;
592     ACPI_STATUS             Status;
593     ACPI_STATUS             GlobalStatus = AE_OK;
594     ACPI_OWNER_ID           OwnerId;
595 
596 
597     /*
598      * External filenames are specified on the command line like this:
599      * Example: iasl -e file1,file2,file3 -d xxx.aml
600      */
601     ExternalFileList = AcpiGbl_ExternalFileList;
602 
603     /* Process each external file */
604 
605     while (ExternalFileList)
606     {
607         ExternalFilename = ExternalFileList->Path;
608         if (!strcmp (ExternalFilename, Filename))
609         {
610             /* Next external file */
611 
612             ExternalFileList = ExternalFileList->Next;
613             continue;
614         }
615 
616         AcpiOsPrintf ("External object resolution file %16s\n",
617             ExternalFilename);
618 
619         Status = AcGetAllTablesFromFile (
620             ExternalFilename, ACPI_GET_ONLY_AML_TABLES, &ExternalListHead);
621         if (ACPI_FAILURE (Status))
622         {
623             if (Status == AE_TYPE)
624             {
625                 ExternalFileList = ExternalFileList->Next;
626                 GlobalStatus = AE_TYPE;
627                 Status = AE_OK;
628                 continue;
629             }
630 
631             return (Status);
632         }
633 
634         /* Load external tables for symbol resolution */
635 
636         while (ExternalListHead)
637         {
638             Status = AdParseTable (
639                 ExternalListHead->Table, &OwnerId, TRUE, TRUE);
640             if (ACPI_FAILURE (Status))
641             {
642                 AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
643                     AcpiFormatException (Status));
644                 return (Status);
645             }
646 
647             /*
648              * Load namespace from names created within control methods
649              * Set owner id of nodes in external table
650              */
651             AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
652                 AcpiGbl_RootNode, OwnerId);
653             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
654 
655             ExternalListHead = ExternalListHead->Next;
656         }
657 
658         /* Next external file */
659 
660         ExternalFileList = ExternalFileList->Next;
661     }
662 
663     if (ACPI_FAILURE (GlobalStatus))
664     {
665         return (GlobalStatus);
666     }
667 
668     /* Clear external list generated by Scope in external tables */
669 
670     if (AcpiGbl_ExternalFileList)
671     {
672         AcpiDmClearExternalList ();
673     }
674 
675     /* Load any externals defined in the optional external ref file */
676 
677     AcpiDmGetExternalsFromFile ();
678     return (AE_OK);
679 }
680