xref: /freebsd/sys/contrib/dev/acpica/common/adisasm.c (revision 3ef51c5fb9163f2aafb1c14729e06a8bf0c4d113)
1 /******************************************************************************
2  *
3  * Module Name: adisasm - Application-level disassembler routines
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 
45 #include <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acparser.h>
48 #include <contrib/dev/acpica/include/amlcode.h>
49 #include <contrib/dev/acpica/include/acdebug.h>
50 #include <contrib/dev/acpica/include/acdisasm.h>
51 #include <contrib/dev/acpica/include/acdispat.h>
52 #include <contrib/dev/acpica/include/acnamesp.h>
53 #include <contrib/dev/acpica/include/actables.h>
54 #include <contrib/dev/acpica/include/acapps.h>
55 
56 #include <stdio.h>
57 #include <time.h>
58 
59 
60 #define _COMPONENT          ACPI_TOOLS
61         ACPI_MODULE_NAME    ("adisasm")
62 
63 
64 extern int                  AslCompilerdebug;
65 
66 
67 ACPI_STATUS
68 LsDisplayNamespace (
69     void);
70 
71 void
72 LsSetupNsList (
73     void                    *Handle);
74 
75 
76 /* Local prototypes */
77 
78 static UINT32
79 AdGetFileSize (
80     FILE                    *File);
81 
82 static void
83 AdCreateTableHeader (
84     char                    *Filename,
85     ACPI_TABLE_HEADER       *Table);
86 
87 static ACPI_STATUS
88 AdDeferredParse (
89     ACPI_PARSE_OBJECT       *Op,
90     UINT8                   *Aml,
91     UINT32                  AmlLength);
92 
93 static ACPI_STATUS
94 AdParseDeferredOps (
95     ACPI_PARSE_OBJECT       *Root);
96 
97 
98 /* Stubs for ASL compiler */
99 
100 #ifndef ACPI_ASL_COMPILER
101 BOOLEAN
102 AcpiDsIsResultUsed (
103     ACPI_PARSE_OBJECT       *Op,
104     ACPI_WALK_STATE         *WalkState)
105 {
106     return TRUE;
107 }
108 
109 ACPI_STATUS
110 AcpiDsMethodError (
111     ACPI_STATUS             Status,
112     ACPI_WALK_STATE         *WalkState)
113 {
114     return (Status);
115 }
116 #endif
117 
118 ACPI_STATUS
119 AcpiNsLoadTable (
120     UINT32                  TableIndex,
121     ACPI_NAMESPACE_NODE     *Node)
122 {
123     return (AE_NOT_IMPLEMENTED);
124 }
125 
126 ACPI_STATUS
127 AcpiDsRestartControlMethod (
128     ACPI_WALK_STATE         *WalkState,
129     ACPI_OPERAND_OBJECT     *ReturnDesc)
130 {
131     return (AE_OK);
132 }
133 
134 void
135 AcpiDsTerminateControlMethod (
136     ACPI_OPERAND_OBJECT     *MethodDesc,
137     ACPI_WALK_STATE         *WalkState)
138 {
139     return;
140 }
141 
142 ACPI_STATUS
143 AcpiDsCallControlMethod (
144     ACPI_THREAD_STATE       *Thread,
145     ACPI_WALK_STATE         *WalkState,
146     ACPI_PARSE_OBJECT       *Op)
147 {
148     return (AE_OK);
149 }
150 
151 ACPI_STATUS
152 AcpiDsMethodDataInitArgs (
153     ACPI_OPERAND_OBJECT     **Params,
154     UINT32                  MaxParamCount,
155     ACPI_WALK_STATE         *WalkState)
156 {
157     return (AE_OK);
158 }
159 
160 
161 static ACPI_TABLE_DESC      LocalTables[1];
162 static ACPI_PARSE_OBJECT    *AcpiGbl_ParseOpRoot;
163 
164 
165 /*******************************************************************************
166  *
167  * FUNCTION:    AdGetFileSize
168  *
169  * PARAMETERS:  File                - Open file handle
170  *
171  * RETURN:      File Size
172  *
173  * DESCRIPTION: Get current file size. Uses seek-to-EOF. File must be open.
174  *
175  ******************************************************************************/
176 
177 static UINT32
178 AdGetFileSize (
179     FILE                    *File)
180 {
181     UINT32                  FileSize;
182     long                    Offset;
183 
184 
185     Offset = ftell (File);
186 
187     fseek (File, 0, SEEK_END);
188     FileSize = (UINT32) ftell (File);
189 
190     /* Restore file pointer */
191 
192     fseek (File, Offset, SEEK_SET);
193     return (FileSize);
194 }
195 
196 
197 /*******************************************************************************
198  *
199  * FUNCTION:    AdInitialize
200  *
201  * PARAMETERS:  None
202  *
203  * RETURN:      Status
204  *
205  * DESCRIPTION: ACPICA and local initialization
206  *
207  ******************************************************************************/
208 
209 ACPI_STATUS
210 AdInitialize (
211     void)
212 {
213     ACPI_STATUS             Status;
214 
215 
216     /* ACPI CA subsystem initialization */
217 
218     Status = AcpiOsInitialize ();
219     if (ACPI_FAILURE (Status))
220     {
221         return (Status);
222     }
223 
224     Status = AcpiUtInitGlobals ();
225     if (ACPI_FAILURE (Status))
226     {
227         return (Status);
228     }
229 
230     Status = AcpiUtMutexInitialize ();
231     if (ACPI_FAILURE (Status))
232     {
233         return (Status);
234     }
235 
236     Status = AcpiNsRootInitialize ();
237     if (ACPI_FAILURE (Status))
238     {
239         return (Status);
240     }
241 
242     /* Setup the Table Manager (cheat - there is no RSDT) */
243 
244     AcpiGbl_RootTableList.MaxTableCount = 1;
245     AcpiGbl_RootTableList.CurrentTableCount = 0;
246     AcpiGbl_RootTableList.Tables = LocalTables;
247 
248     return (Status);
249 }
250 
251 
252 /******************************************************************************
253  *
254  * FUNCTION:    AdAmlDisassemble
255  *
256  * PARAMETERS:  Filename            - AML input filename
257  *              OutToFile           - TRUE if output should go to a file
258  *              Prefix              - Path prefix for output
259  *              OutFilename         - where the filename is returned
260  *              GetAllTables        - TRUE if all tables are desired
261  *
262  * RETURN:      Status
263  *
264  * DESCRIPTION: Disassemble an entire ACPI table
265  *
266  *****************************************************************************/
267 
268 ACPI_STATUS
269 AdAmlDisassemble (
270     BOOLEAN                 OutToFile,
271     char                    *Filename,
272     char                    *Prefix,
273     char                    **OutFilename,
274     BOOLEAN                 GetAllTables)
275 {
276     ACPI_STATUS             Status;
277     char                    *DisasmFilename = NULL;
278     char                    *ExternalFilename;
279     ACPI_EXTERNAL_FILE      *ExternalFileList = AcpiGbl_ExternalFileList;
280     FILE                    *File = NULL;
281     ACPI_TABLE_HEADER       *Table = NULL;
282     ACPI_TABLE_HEADER       *ExternalTable;
283     ACPI_OWNER_ID           OwnerId;
284 
285 
286     /*
287      * Input: AML code from either a file or via GetTables (memory or
288      * registry)
289      */
290     if (Filename)
291     {
292         Status = AcpiDbGetTableFromFile (Filename, &Table);
293         if (ACPI_FAILURE (Status))
294         {
295             return Status;
296         }
297 
298         /*
299          * External filenames separated by commas
300          * Example: iasl -e file1,file2,file3 -d xxx.aml
301          */
302         while (ExternalFileList)
303         {
304             ExternalFilename = ExternalFileList->Path;
305             if (!ACPI_STRCMP (ExternalFilename, Filename))
306             {
307                 /* Next external file */
308 
309                 ExternalFileList = ExternalFileList->Next;
310 
311                 continue;
312             }
313 
314             Status = AcpiDbGetTableFromFile (ExternalFilename, &ExternalTable);
315             if (ACPI_FAILURE (Status))
316             {
317                 return Status;
318             }
319 
320             /* Load external table for symbol resolution */
321 
322             if (ExternalTable)
323             {
324                 Status = AdParseTable (ExternalTable, &OwnerId, TRUE, TRUE);
325                 if (ACPI_FAILURE (Status))
326                 {
327                     AcpiOsPrintf ("Could not parse external ACPI tables, %s\n",
328                         AcpiFormatException (Status));
329                     return Status;
330                 }
331 
332                 /*
333                  * Load namespace from names created within control methods
334                  * Set owner id of nodes in external table
335                  */
336                 AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
337                     AcpiGbl_RootNode, OwnerId);
338                 AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
339             }
340 
341             /* Next external file */
342 
343             ExternalFileList = ExternalFileList->Next;
344         }
345 
346         /* Clear external list generated by Scope in external tables */
347 
348         if (AcpiGbl_ExternalFileList)
349         {
350             AcpiDmClearExternalList ();
351         }
352     }
353     else
354     {
355         Status = AdGetLocalTables (Filename, GetAllTables);
356         if (ACPI_FAILURE (Status))
357         {
358             AcpiOsPrintf ("Could not get ACPI tables, %s\n",
359                 AcpiFormatException (Status));
360             return Status;
361         }
362 
363         if (!AcpiGbl_DbOpt_disasm)
364         {
365             return AE_OK;
366         }
367 
368         /* Obtained the local tables, just disassemble the DSDT */
369 
370         Status = AcpiGetTable (ACPI_SIG_DSDT, 0, &Table);
371         if (ACPI_FAILURE (Status))
372         {
373             AcpiOsPrintf ("Could not get DSDT, %s\n",
374                 AcpiFormatException (Status));
375             return Status;
376         }
377 
378         AcpiOsPrintf ("\nDisassembly of DSDT\n");
379         Prefix = AdGenerateFilename ("dsdt", Table->OemTableId);
380     }
381 
382     /*
383      * Output:  ASL code. Redirect to a file if requested
384      */
385     if (OutToFile)
386     {
387         /* Create/Open a disassembly output file */
388 
389         DisasmFilename = FlGenerateFilename (Prefix, FILE_SUFFIX_DISASSEMBLY);
390         if (!OutFilename)
391         {
392             fprintf (stderr, "Could not generate output filename\n");
393             Status = AE_ERROR;
394             goto Cleanup;
395         }
396 
397         File = fopen (DisasmFilename, "w+");
398         if (!File)
399         {
400             fprintf (stderr, "Could not open output file %s\n", DisasmFilename);
401             Status = AE_ERROR;
402             goto Cleanup;
403         }
404 
405         AcpiOsRedirectOutput (File);
406     }
407 
408     *OutFilename = DisasmFilename;
409 
410     if (!AcpiUtIsAmlTable (Table))
411     {
412         AdDisassemblerHeader (Filename);
413         AcpiOsPrintf (" * ACPI Data Table [%4.4s]\n *\n",
414             Table->Signature);
415         AcpiOsPrintf (" * Format: [HexOffset DecimalOffset ByteLength]  "
416             "FieldName : FieldValue\n */\n\n");
417 
418         AcpiDmDumpDataTable (Table);
419         fprintf (stderr, "Acpi Data Table [%4.4s] decoded\n",
420             Table->Signature);
421         fprintf (stderr, "Formatted output:  %s - %u bytes\n",
422             DisasmFilename, AdGetFileSize (File));
423     }
424     else
425     {
426         /* Always parse the tables, only option is what to display */
427 
428         Status = AdParseTable (Table, &OwnerId, TRUE, FALSE);
429         if (ACPI_FAILURE (Status))
430         {
431             AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
432                 AcpiFormatException (Status));
433             goto Cleanup;
434         }
435 
436         if (AslCompilerdebug)
437         {
438             AcpiOsPrintf ("/**** Before second load\n");
439 
440             LsSetupNsList (File);
441             LsDisplayNamespace ();
442             AcpiOsPrintf ("*****/\n");
443         }
444 
445         /* Load namespace from names created within control methods */
446 
447         AcpiDmFinishNamespaceLoad (AcpiGbl_ParseOpRoot,
448             AcpiGbl_RootNode, OwnerId);
449 
450         /*
451          * Cross reference the namespace here, in order to
452          * generate External() statements
453          */
454         AcpiDmCrossReferenceNamespace (AcpiGbl_ParseOpRoot,
455             AcpiGbl_RootNode, OwnerId);
456 
457         if (AslCompilerdebug)
458         {
459             AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
460         }
461 
462         /* Find possible calls to external control methods */
463 
464         AcpiDmFindOrphanMethods (AcpiGbl_ParseOpRoot);
465 
466         /*
467          * If we found any external control methods, we must reparse
468          * the entire tree with the new information (namely, the
469          * number of arguments per method)
470          */
471         if (AcpiDmGetExternalMethodCount ())
472         {
473             fprintf (stderr,
474                 "\nFound %u external control methods, "
475                 "reparsing with new information\n",
476                 AcpiDmGetExternalMethodCount ());
477 
478             /* Reparse, rebuild namespace. no need to xref namespace */
479 
480             AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
481             AcpiNsDeleteNamespaceSubtree (AcpiGbl_RootNode);
482 
483             AcpiGbl_RootNode                    = NULL;
484             AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
485             AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
486             AcpiGbl_RootNodeStruct.Type         = ACPI_TYPE_DEVICE;
487             AcpiGbl_RootNodeStruct.Parent       = NULL;
488             AcpiGbl_RootNodeStruct.Child        = NULL;
489             AcpiGbl_RootNodeStruct.Peer         = NULL;
490             AcpiGbl_RootNodeStruct.Object       = NULL;
491             AcpiGbl_RootNodeStruct.Flags        = 0;
492 
493             Status = AcpiNsRootInitialize ();
494             AcpiDmAddExternalsToNamespace ();
495 
496             /* Parse the table again. No need to reload it, however */
497 
498             Status = AdParseTable (Table, NULL, FALSE, FALSE);
499             if (ACPI_FAILURE (Status))
500             {
501                 AcpiOsPrintf ("Could not parse ACPI tables, %s\n",
502                     AcpiFormatException (Status));
503                 goto Cleanup;
504             }
505 
506             if (AslCompilerdebug)
507             {
508                 AcpiOsPrintf ("/**** After second load and resource conversion\n");
509                 LsSetupNsList (File);
510                 LsDisplayNamespace ();
511                 AcpiOsPrintf ("*****/\n");
512 
513                 AcpiDmDumpTree (AcpiGbl_ParseOpRoot);
514             }
515         }
516 
517         /*
518          * Now that the namespace is finalized, we can perform namespace
519          * transforms.
520          *
521          * 1) Convert fixed-offset references to resource descriptors
522          *    to symbolic references (Note: modifies namespace)
523          */
524         AcpiDmConvertResourceIndexes (AcpiGbl_ParseOpRoot, AcpiGbl_RootNode);
525 
526         /* Optional displays */
527 
528         if (AcpiGbl_DbOpt_disasm)
529         {
530             AdDisplayTables (Filename, Table);
531             fprintf (stderr, "Disassembly completed\n");
532             fprintf (stderr, "ASL Output:    %s - %u bytes\n",
533                 DisasmFilename, AdGetFileSize (File));
534         }
535     }
536 
537 Cleanup:
538 
539     if (Table && !AcpiUtIsAmlTable (Table))
540     {
541         ACPI_FREE (Table);
542     }
543 
544     if (DisasmFilename)
545     {
546         ACPI_FREE (DisasmFilename);
547     }
548 
549     if (OutToFile && File)
550     {
551         if (AslCompilerdebug) /* Display final namespace, with transforms */
552         {
553             LsSetupNsList (File);
554             LsDisplayNamespace ();
555         }
556 
557         fclose (File);
558         AcpiOsRedirectOutput (stdout);
559     }
560 
561     AcpiPsDeleteParseTree (AcpiGbl_ParseOpRoot);
562     AcpiGbl_ParseOpRoot = NULL;
563     return (Status);
564 }
565 
566 
567 /******************************************************************************
568  *
569  * FUNCTION:    AdDisassemblerHeader
570  *
571  * PARAMETERS:  Filename            - Input file for the table
572  *
573  * RETURN:      None
574  *
575  * DESCRIPTION: Create the disassembler header, including ACPI CA signon with
576  *              current time and date.
577  *
578  *****************************************************************************/
579 
580 void
581 AdDisassemblerHeader (
582     char                    *Filename)
583 {
584     time_t                  Timer;
585 
586     time (&Timer);
587 
588     /* Header and input table info */
589 
590     AcpiOsPrintf ("/*\n");
591     AcpiOsPrintf (ACPI_COMMON_HEADER ("AML Disassembler", " * "));
592 
593     AcpiOsPrintf (" * Disassembly of %s, %s", Filename, ctime (&Timer));
594     AcpiOsPrintf (" *\n");
595 }
596 
597 
598 /******************************************************************************
599  *
600  * FUNCTION:    AdCreateTableHeader
601  *
602  * PARAMETERS:  Filename            - Input file for the table
603  *              Table               - Pointer to the raw table
604  *
605  * RETURN:      None
606  *
607  * DESCRIPTION: Create the ASL table header, including ACPI CA signon with
608  *              current time and date.
609  *
610  *****************************************************************************/
611 
612 static void
613 AdCreateTableHeader (
614     char                    *Filename,
615     ACPI_TABLE_HEADER       *Table)
616 {
617     char                    *NewFilename;
618     UINT8                   Checksum;
619 
620 
621     /*
622      * Print file header and dump original table header
623      */
624     AdDisassemblerHeader (Filename);
625 
626     AcpiOsPrintf (" * Original Table Header:\n");
627     AcpiOsPrintf (" *     Signature        \"%4.4s\"\n",    Table->Signature);
628     AcpiOsPrintf (" *     Length           0x%8.8X (%u)\n", Table->Length, Table->Length);
629 
630     /* Print and validate the revision */
631 
632     AcpiOsPrintf (" *     Revision         0x%2.2X",      Table->Revision);
633 
634     switch (Table->Revision)
635     {
636     case 0:
637         AcpiOsPrintf (" **** Invalid Revision");
638         break;
639 
640     case 1:
641         /* Revision of DSDT controls the ACPI integer width */
642 
643         if (ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT))
644         {
645             AcpiOsPrintf (" **** 32-bit table (V1), no 64-bit math support");
646         }
647         break;
648 
649     default:
650         break;
651     }
652     AcpiOsPrintf ("\n");
653 
654     /* Print and validate the table checksum */
655 
656     AcpiOsPrintf (" *     Checksum         0x%2.2X",        Table->Checksum);
657 
658     Checksum = AcpiTbChecksum (ACPI_CAST_PTR (UINT8, Table), Table->Length);
659     if (Checksum)
660     {
661         AcpiOsPrintf (" **** Incorrect checksum, should be 0x%2.2X",
662             (UINT8) (Table->Checksum - Checksum));
663     }
664     AcpiOsPrintf ("\n");
665 
666     AcpiOsPrintf (" *     OEM ID           \"%.6s\"\n",     Table->OemId);
667     AcpiOsPrintf (" *     OEM Table ID     \"%.8s\"\n",     Table->OemTableId);
668     AcpiOsPrintf (" *     OEM Revision     0x%8.8X (%u)\n", Table->OemRevision, Table->OemRevision);
669     AcpiOsPrintf (" *     Compiler ID      \"%.4s\"\n",     Table->AslCompilerId);
670     AcpiOsPrintf (" *     Compiler Version 0x%8.8X (%u)\n", Table->AslCompilerRevision, Table->AslCompilerRevision);
671     AcpiOsPrintf (" */\n\n");
672 
673     /* Create AML output filename based on input filename */
674 
675     if (Filename)
676     {
677         NewFilename = FlGenerateFilename (Filename, "aml");
678     }
679     else
680     {
681         NewFilename = ACPI_ALLOCATE_ZEROED (9);
682         strncat (NewFilename, Table->Signature, 4);
683         strcat (NewFilename, ".aml");
684     }
685 
686     /* Open the ASL definition block */
687 
688     AcpiOsPrintf (
689         "DefinitionBlock (\"%s\", \"%4.4s\", %hu, \"%.6s\", \"%.8s\", 0x%8.8X)\n",
690         NewFilename, Table->Signature, Table->Revision,
691         Table->OemId, Table->OemTableId, Table->OemRevision);
692 
693     ACPI_FREE (NewFilename);
694 }
695 
696 
697 /******************************************************************************
698  *
699  * FUNCTION:    AdDisplayTables
700  *
701  * PARAMETERS:  Filename            - Input file for the table
702  *              Table               - Pointer to the raw table
703  *
704  * RETURN:      Status
705  *
706  * DESCRIPTION: Display (disassemble) loaded tables and dump raw tables
707  *
708  *****************************************************************************/
709 
710 ACPI_STATUS
711 AdDisplayTables (
712     char                    *Filename,
713     ACPI_TABLE_HEADER       *Table)
714 {
715 
716 
717     if (!AcpiGbl_ParseOpRoot)
718     {
719         return AE_NOT_EXIST;
720     }
721 
722     if (!AcpiGbl_DbOpt_verbose)
723     {
724         AdCreateTableHeader (Filename, Table);
725     }
726 
727     AcpiDmDisassemble (NULL, AcpiGbl_ParseOpRoot, ACPI_UINT32_MAX);
728 
729     if (AcpiGbl_DbOpt_verbose)
730     {
731         AcpiOsPrintf ("\n\nTable Header:\n");
732         AcpiUtDumpBuffer ((UINT8 *) Table, sizeof (ACPI_TABLE_HEADER),
733             DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
734 
735         AcpiOsPrintf ("Table Body (Length 0x%X)\n", Table->Length);
736         AcpiUtDumpBuffer (((UINT8 *) Table + sizeof (ACPI_TABLE_HEADER)), Table->Length,
737             DB_BYTE_DISPLAY, ACPI_UINT32_MAX);
738     }
739 
740     return AE_OK;
741 }
742 
743 
744 /******************************************************************************
745  *
746  * FUNCTION:    AdDeferredParse
747  *
748  * PARAMETERS:  Op                  - Root Op of the deferred opcode
749  *              Aml                 - Pointer to the raw AML
750  *              AmlLength           - Length of the AML
751  *
752  * RETURN:      Status
753  *
754  * DESCRIPTION: Parse one deferred opcode
755  *              (Methods, operation regions, etc.)
756  *
757  *****************************************************************************/
758 
759 static ACPI_STATUS
760 AdDeferredParse (
761     ACPI_PARSE_OBJECT       *Op,
762     UINT8                   *Aml,
763     UINT32                  AmlLength)
764 {
765     ACPI_WALK_STATE         *WalkState;
766     ACPI_STATUS             Status;
767     ACPI_PARSE_OBJECT       *SearchOp;
768     ACPI_PARSE_OBJECT       *StartOp;
769     UINT32                  BaseAmlOffset;
770     ACPI_PARSE_OBJECT       *ExtraOp;
771 
772 
773     ACPI_FUNCTION_TRACE (AdDeferredParse);
774 
775 
776     fprintf (stderr, ".");
777 
778     if (!Aml || !AmlLength)
779     {
780         return_ACPI_STATUS (AE_OK);
781     }
782 
783     ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Parsing %s [%4.4s]\n",
784         Op->Common.AmlOpName, (char *) &Op->Named.Name));
785 
786     WalkState = AcpiDsCreateWalkState (0, Op, NULL, NULL);
787     if (!WalkState)
788     {
789         return_ACPI_STATUS (AE_NO_MEMORY);
790     }
791 
792     Status = AcpiDsInitAmlWalk (WalkState, Op, NULL, Aml,
793                     AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
794     if (ACPI_FAILURE (Status))
795     {
796         return_ACPI_STATUS (Status);
797     }
798 
799     /* Parse the method */
800 
801     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
802     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
803     Status = AcpiPsParseAml (WalkState);
804 
805     /*
806      * We need to update all of the Aml offsets, since the parser thought
807      * that the method began at offset zero.  In reality, it began somewhere
808      * within the ACPI table, at the BaseAmlOffset.  Walk the entire tree that
809      * was just created and update the AmlOffset in each Op
810      */
811     BaseAmlOffset = (Op->Common.Value.Arg)->Common.AmlOffset + 1;
812     StartOp = (Op->Common.Value.Arg)->Common.Next;
813     SearchOp = StartOp;
814 
815     /* Walk the parse tree */
816 
817     while (SearchOp)
818     {
819         SearchOp->Common.AmlOffset += BaseAmlOffset;
820         SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp);
821     }
822 
823     /*
824      * Link the newly parsed subtree into the main parse tree
825      */
826     switch (Op->Common.AmlOpcode)
827     {
828     case AML_BUFFER_OP:
829     case AML_PACKAGE_OP:
830     case AML_VAR_PACKAGE_OP:
831 
832         switch (Op->Common.AmlOpcode)
833         {
834         case AML_PACKAGE_OP:
835             ExtraOp = Op->Common.Value.Arg;
836             ExtraOp = ExtraOp->Common.Next;
837             Op->Common.Value.Arg = ExtraOp->Common.Value.Arg;
838             break;
839 
840         case AML_VAR_PACKAGE_OP:
841         case AML_BUFFER_OP:
842         default:
843             ExtraOp = Op->Common.Value.Arg;
844             Op->Common.Value.Arg = ExtraOp->Common.Value.Arg;
845             break;
846         }
847 
848         /* Must point all parents to the main tree */
849 
850         StartOp = Op;
851         SearchOp = StartOp;
852         while (SearchOp)
853         {
854             if (SearchOp->Common.Parent == ExtraOp)
855             {
856                 SearchOp->Common.Parent = Op;
857             }
858             SearchOp = AcpiPsGetDepthNext (StartOp, SearchOp);
859         }
860         break;
861 
862     default:
863         break;
864     }
865 
866     return_ACPI_STATUS (AE_OK);
867 }
868 
869 
870 /******************************************************************************
871  *
872  * FUNCTION:    AdParseDeferredOps
873  *
874  * PARAMETERS:  Root                - Root of the parse tree
875  *
876  * RETURN:      Status
877  *
878  * DESCRIPTION: Parse the deferred opcodes (Methods, regions, etc.)
879  *
880  *****************************************************************************/
881 
882 static ACPI_STATUS
883 AdParseDeferredOps (
884     ACPI_PARSE_OBJECT       *Root)
885 {
886     ACPI_PARSE_OBJECT       *Op = Root;
887     ACPI_STATUS             Status = AE_OK;
888     const ACPI_OPCODE_INFO  *OpInfo;
889 
890 
891     ACPI_FUNCTION_NAME (AdParseDeferredOps);
892     fprintf (stderr, "Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)\n");
893 
894     while (Op)
895     {
896         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
897         if (!(OpInfo->Flags & AML_DEFER))
898         {
899             Op = AcpiPsGetDepthNext (Root, Op);
900             continue;
901         }
902 
903         switch (Op->Common.AmlOpcode)
904         {
905         case AML_METHOD_OP:
906         case AML_BUFFER_OP:
907         case AML_PACKAGE_OP:
908         case AML_VAR_PACKAGE_OP:
909 
910             Status = AdDeferredParse (Op, Op->Named.Data, Op->Named.Length);
911             if (ACPI_FAILURE (Status))
912             {
913                 return_ACPI_STATUS (Status);
914             }
915             break;
916 
917         case AML_REGION_OP:
918         case AML_DATA_REGION_OP:
919         case AML_CREATE_QWORD_FIELD_OP:
920         case AML_CREATE_DWORD_FIELD_OP:
921         case AML_CREATE_WORD_FIELD_OP:
922         case AML_CREATE_BYTE_FIELD_OP:
923         case AML_CREATE_BIT_FIELD_OP:
924         case AML_CREATE_FIELD_OP:
925         case AML_BANK_FIELD_OP:
926 
927             /* Nothing to do in these cases */
928 
929             break;
930 
931         default:
932             ACPI_ERROR ((AE_INFO, "Unhandled deferred opcode [%s]",
933                 Op->Common.AmlOpName));
934             break;
935         }
936 
937         Op = AcpiPsGetDepthNext (Root, Op);
938     }
939 
940     fprintf (stderr, "\n");
941     return Status;
942 }
943 
944 
945 /******************************************************************************
946  *
947  * FUNCTION:    AdGetLocalTables
948  *
949  * PARAMETERS:  Filename            - Not used
950  *              GetAllTables        - TRUE if all tables are desired
951  *
952  * RETURN:      Status
953  *
954  * DESCRIPTION: Get the ACPI tables from either memory or a file
955  *
956  *****************************************************************************/
957 
958 ACPI_STATUS
959 AdGetLocalTables (
960     char                    *Filename,
961     BOOLEAN                 GetAllTables)
962 {
963     ACPI_STATUS             Status;
964     ACPI_TABLE_HEADER       TableHeader;
965     ACPI_TABLE_HEADER       *NewTable;
966     UINT32                  NumTables;
967     UINT32                  PointerSize;
968     UINT32                  TableIndex;
969 
970 
971     if (GetAllTables)
972     {
973         ACPI_MOVE_32_TO_32 (TableHeader.Signature, ACPI_SIG_RSDT);
974         AcpiOsTableOverride (&TableHeader, &NewTable);
975         if (!NewTable)
976         {
977             fprintf (stderr, "Could not obtain RSDT\n");
978             return AE_NO_ACPI_TABLES;
979         }
980         else
981         {
982             AdWriteTable (NewTable, NewTable->Length,
983                 ACPI_SIG_RSDT, NewTable->OemTableId);
984         }
985 
986         if (ACPI_COMPARE_NAME (NewTable->Signature, ACPI_SIG_RSDT))
987         {
988             PointerSize = sizeof (UINT32);
989         }
990         else
991         {
992             PointerSize = sizeof (UINT64);
993         }
994 
995         /*
996          * Determine the number of tables pointed to by the RSDT/XSDT.
997          * This is defined by the ACPI Specification to be the number of
998          * pointers contained within the RSDT/XSDT.  The size of the pointers
999          * is architecture-dependent.
1000          */
1001         NumTables = (NewTable->Length - sizeof (ACPI_TABLE_HEADER)) / PointerSize;
1002         AcpiOsPrintf ("There are %u tables defined in the %4.4s\n\n",
1003             NumTables, NewTable->Signature);
1004 
1005         /* Get the FADT */
1006 
1007         ACPI_MOVE_32_TO_32 (TableHeader.Signature, ACPI_SIG_FADT);
1008         AcpiOsTableOverride (&TableHeader, &NewTable);
1009         if (NewTable)
1010         {
1011             AdWriteTable (NewTable, NewTable->Length,
1012                 ACPI_SIG_FADT, NewTable->OemTableId);
1013         }
1014         AcpiOsPrintf ("\n");
1015 
1016         /* Don't bother with FACS, it is usually all zeros */
1017     }
1018 
1019     /* Always get the DSDT */
1020 
1021     ACPI_MOVE_32_TO_32 (TableHeader.Signature, ACPI_SIG_DSDT);
1022     AcpiOsTableOverride (&TableHeader, &NewTable);
1023     if (NewTable)
1024     {
1025         AdWriteTable (NewTable, NewTable->Length,
1026             ACPI_SIG_DSDT, NewTable->OemTableId);
1027 
1028         /* Store DSDT in the Table Manager */
1029 
1030         Status = AcpiTbStoreTable (0, NewTable, NewTable->Length,
1031                     0, &TableIndex);
1032         if (ACPI_FAILURE (Status))
1033         {
1034             fprintf (stderr, "Could not store DSDT\n");
1035             return AE_NO_ACPI_TABLES;
1036         }
1037     }
1038     else
1039     {
1040         fprintf (stderr, "Could not obtain DSDT\n");
1041         return AE_NO_ACPI_TABLES;
1042     }
1043 
1044 #if 0
1045     /* TBD: Future implementation */
1046 
1047     AcpiOsPrintf ("\n");
1048 
1049     /* Get all SSDTs */
1050 
1051     ACPI_MOVE_32_TO_32 (TableHeader.Signature, ACPI_SIG_SSDT);
1052     do
1053     {
1054         NewTable = NULL;
1055         Status = AcpiOsTableOverride (&TableHeader, &NewTable);
1056 
1057     } while (NewTable);
1058 #endif
1059 
1060     return AE_OK;
1061 }
1062 
1063 
1064 /******************************************************************************
1065  *
1066  * FUNCTION:    AdParseTable
1067  *
1068  * PARAMETERS:  Table               - Pointer to the raw table
1069  *              OwnerId             - Returned OwnerId of the table
1070  *              LoadTable           - If add table to the global table list
1071  *              External            - If this is an external table
1072  *
1073  * RETURN:      Status
1074  *
1075  * DESCRIPTION: Parse the DSDT.
1076  *
1077  *****************************************************************************/
1078 
1079 ACPI_STATUS
1080 AdParseTable (
1081     ACPI_TABLE_HEADER       *Table,
1082     ACPI_OWNER_ID           *OwnerId,
1083     BOOLEAN                 LoadTable,
1084     BOOLEAN                 External)
1085 {
1086     ACPI_STATUS             Status = AE_OK;
1087     ACPI_WALK_STATE         *WalkState;
1088     UINT8                   *AmlStart;
1089     UINT32                  AmlLength;
1090     UINT32                  TableIndex;
1091 
1092 
1093     if (!Table)
1094     {
1095         return AE_NOT_EXIST;
1096     }
1097 
1098     /* Pass 1:  Parse everything except control method bodies */
1099 
1100     fprintf (stderr, "Pass 1 parse of [%4.4s]\n", (char *) Table->Signature);
1101 
1102     AmlLength = Table->Length - sizeof (ACPI_TABLE_HEADER);
1103     AmlStart = ((UINT8 *) Table + sizeof (ACPI_TABLE_HEADER));
1104 
1105     /* Create the root object */
1106 
1107     AcpiGbl_ParseOpRoot = AcpiPsCreateScopeOp ();
1108     if (!AcpiGbl_ParseOpRoot)
1109     {
1110         return AE_NO_MEMORY;
1111     }
1112 
1113     /* Create and initialize a new walk state */
1114 
1115     WalkState = AcpiDsCreateWalkState (0,
1116                         AcpiGbl_ParseOpRoot, NULL, NULL);
1117     if (!WalkState)
1118     {
1119         return (AE_NO_MEMORY);
1120     }
1121 
1122     Status = AcpiDsInitAmlWalk (WalkState, AcpiGbl_ParseOpRoot,
1123                 NULL, AmlStart, AmlLength, NULL, ACPI_IMODE_LOAD_PASS1);
1124     if (ACPI_FAILURE (Status))
1125     {
1126         return (Status);
1127     }
1128 
1129     WalkState->ParseFlags &= ~ACPI_PARSE_DELETE_TREE;
1130     WalkState->ParseFlags |= ACPI_PARSE_DISASSEMBLE;
1131 
1132     Status = AcpiPsParseAml (WalkState);
1133     if (ACPI_FAILURE (Status))
1134     {
1135         return Status;
1136     }
1137 
1138     /* If LoadTable is FALSE, we are parsing the last loaded table */
1139 
1140     TableIndex = AcpiGbl_RootTableList.CurrentTableCount - 1;
1141 
1142     /* Pass 2 */
1143 
1144     if (LoadTable)
1145     {
1146         Status = AcpiTbStoreTable ((ACPI_PHYSICAL_ADDRESS) Table, Table,
1147                     Table->Length, ACPI_TABLE_ORIGIN_ALLOCATED, &TableIndex);
1148         if (ACPI_FAILURE (Status))
1149         {
1150             return Status;
1151         }
1152         Status = AcpiTbAllocateOwnerId (TableIndex);
1153         if (ACPI_FAILURE (Status))
1154         {
1155             return Status;
1156         }
1157         if (OwnerId)
1158         {
1159             Status = AcpiTbGetOwnerId (TableIndex, OwnerId);
1160             if (ACPI_FAILURE (Status))
1161             {
1162                 return Status;
1163             }
1164         }
1165     }
1166 
1167     fprintf (stderr, "Pass 2 parse of [%4.4s]\n", (char *) Table->Signature);
1168 
1169     Status = AcpiNsOneCompleteParse (ACPI_IMODE_LOAD_PASS2, TableIndex, NULL);
1170     if (ACPI_FAILURE (Status))
1171     {
1172         return (Status);
1173     }
1174 
1175     /* No need to parse control methods of external table */
1176 
1177     if (External)
1178     {
1179         return AE_OK;
1180     }
1181 
1182     /* Pass 3: Parse control methods and link their parse trees into the main parse tree */
1183 
1184     Status = AdParseDeferredOps (AcpiGbl_ParseOpRoot);
1185 
1186     /* Process Resource Templates */
1187 
1188     AcpiDmFindResources (AcpiGbl_ParseOpRoot);
1189 
1190     fprintf (stderr, "Parsing completed\n");
1191     return AE_OK;
1192 }
1193 
1194 
1195