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