xref: /freebsd/sys/contrib/dev/acpica/components/disassembler/dmwalk.c (revision 7e00348e7605b9906601438008341ffc37c00e2c)
1 /*******************************************************************************
2  *
3  * Module Name: dmwalk - AML disassembly tree walk
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include <contrib/dev/acpica/include/acpi.h>
45 #include <contrib/dev/acpica/include/accommon.h>
46 #include <contrib/dev/acpica/include/acparser.h>
47 #include <contrib/dev/acpica/include/amlcode.h>
48 #include <contrib/dev/acpica/include/acdisasm.h>
49 #include <contrib/dev/acpica/include/acdebug.h>
50 
51 
52 #ifdef ACPI_DISASSEMBLER
53 
54 #define _COMPONENT          ACPI_CA_DEBUGGER
55         ACPI_MODULE_NAME    ("dmwalk")
56 
57 
58 #define DB_FULL_OP_INFO     "[%4.4s] @%5.5X #%4.4X:  "
59 
60 /* Stub for non-compiler code */
61 
62 #ifndef ACPI_ASL_COMPILER
63 void
64 AcpiDmEmitExternals (
65     void)
66 {
67     return;
68 }
69 #endif
70 
71 /* Local prototypes */
72 
73 static ACPI_STATUS
74 AcpiDmDescendingOp (
75     ACPI_PARSE_OBJECT       *Op,
76     UINT32                  Level,
77     void                    *Context);
78 
79 static ACPI_STATUS
80 AcpiDmAscendingOp (
81     ACPI_PARSE_OBJECT       *Op,
82     UINT32                  Level,
83     void                    *Context);
84 
85 static UINT32
86 AcpiDmBlockType (
87     ACPI_PARSE_OBJECT       *Op);
88 
89 
90 /*******************************************************************************
91  *
92  * FUNCTION:    AcpiDmDisassemble
93  *
94  * PARAMETERS:  WalkState       - Current state
95  *              Origin          - Starting object
96  *              NumOpcodes      - Max number of opcodes to be displayed
97  *
98  * RETURN:      None
99  *
100  * DESCRIPTION: Disassemble parser object and its children. This is the
101  *              main entry point of the disassembler.
102  *
103  ******************************************************************************/
104 
105 void
106 AcpiDmDisassemble (
107     ACPI_WALK_STATE         *WalkState,
108     ACPI_PARSE_OBJECT       *Origin,
109     UINT32                  NumOpcodes)
110 {
111     ACPI_PARSE_OBJECT       *Op = Origin;
112     ACPI_OP_WALK_INFO       Info;
113 
114 
115     if (!Op)
116     {
117         return;
118     }
119 
120     Info.Flags = 0;
121     Info.Level = 0;
122     Info.Count = 0;
123     Info.WalkState = WalkState;
124     AcpiDmWalkParseTree (Op, AcpiDmDescendingOp, AcpiDmAscendingOp, &Info);
125     return;
126 }
127 
128 
129 /*******************************************************************************
130  *
131  * FUNCTION:    AcpiDmWalkParseTree
132  *
133  * PARAMETERS:  Op                      - Root Op object
134  *              DescendingCallback      - Called during tree descent
135  *              AscendingCallback       - Called during tree ascent
136  *              Context                 - To be passed to the callbacks
137  *
138  * RETURN:      Status from callback(s)
139  *
140  * DESCRIPTION: Walk the entire parse tree.
141  *
142  ******************************************************************************/
143 
144 void
145 AcpiDmWalkParseTree (
146     ACPI_PARSE_OBJECT       *Op,
147     ASL_WALK_CALLBACK       DescendingCallback,
148     ASL_WALK_CALLBACK       AscendingCallback,
149     void                    *Context)
150 {
151     BOOLEAN                 NodePreviouslyVisited;
152     ACPI_PARSE_OBJECT       *StartOp = Op;
153     ACPI_STATUS             Status;
154     ACPI_PARSE_OBJECT       *Next;
155     ACPI_OP_WALK_INFO       *Info = Context;
156 
157 
158     Info->Level = 0;
159     NodePreviouslyVisited = FALSE;
160 
161     while (Op)
162     {
163         if (NodePreviouslyVisited)
164         {
165             if (AscendingCallback)
166             {
167                 Status = AscendingCallback (Op, Info->Level, Context);
168                 if (ACPI_FAILURE (Status))
169                 {
170                     return;
171                 }
172             }
173         }
174         else
175         {
176             /* Let the callback process the node */
177 
178             Status = DescendingCallback (Op, Info->Level, Context);
179             if (ACPI_SUCCESS (Status))
180             {
181                 /* Visit children first, once */
182 
183                 Next = AcpiPsGetArg (Op, 0);
184                 if (Next)
185                 {
186                     Info->Level++;
187                     Op = Next;
188                     continue;
189                 }
190             }
191             else if (Status != AE_CTRL_DEPTH)
192             {
193                 /* Exit immediately on any error */
194 
195                 return;
196             }
197         }
198 
199         /* Terminate walk at start op */
200 
201         if (Op == StartOp)
202         {
203             break;
204         }
205 
206         /* No more children, re-visit this node */
207 
208         if (!NodePreviouslyVisited)
209         {
210             NodePreviouslyVisited = TRUE;
211             continue;
212         }
213 
214         /* No more children, visit peers */
215 
216         if (Op->Common.Next)
217         {
218             Op = Op->Common.Next;
219             NodePreviouslyVisited = FALSE;
220         }
221         else
222         {
223             /* No peers, re-visit parent */
224 
225             if (Info->Level != 0 )
226             {
227                 Info->Level--;
228             }
229 
230             Op = Op->Common.Parent;
231             NodePreviouslyVisited = TRUE;
232         }
233     }
234 
235     /* If we get here, the walk completed with no errors */
236 
237     return;
238 }
239 
240 
241 /*******************************************************************************
242  *
243  * FUNCTION:    AcpiDmBlockType
244  *
245  * PARAMETERS:  Op              - Object to be examined
246  *
247  * RETURN:      BlockType - not a block, parens, braces, or even both.
248  *
249  * DESCRIPTION: Type of block for this op (parens or braces)
250  *
251  ******************************************************************************/
252 
253 static UINT32
254 AcpiDmBlockType (
255     ACPI_PARSE_OBJECT       *Op)
256 {
257     const ACPI_OPCODE_INFO  *OpInfo;
258 
259 
260     if (!Op)
261     {
262         return (BLOCK_NONE);
263     }
264 
265     switch (Op->Common.AmlOpcode)
266     {
267     case AML_ELSE_OP:
268 
269         return (BLOCK_BRACE);
270 
271     case AML_METHOD_OP:
272     case AML_DEVICE_OP:
273     case AML_SCOPE_OP:
274     case AML_PROCESSOR_OP:
275     case AML_POWER_RES_OP:
276     case AML_THERMAL_ZONE_OP:
277     case AML_IF_OP:
278     case AML_WHILE_OP:
279     case AML_FIELD_OP:
280     case AML_INDEX_FIELD_OP:
281     case AML_BANK_FIELD_OP:
282 
283         return (BLOCK_PAREN | BLOCK_BRACE);
284 
285     case AML_BUFFER_OP:
286 
287         if ((Op->Common.DisasmOpcode == ACPI_DASM_UNICODE) ||
288             (Op->Common.DisasmOpcode == ACPI_DASM_UUID))
289         {
290             return (BLOCK_NONE);
291         }
292 
293         /*lint -fallthrough */
294 
295     case AML_PACKAGE_OP:
296     case AML_VAR_PACKAGE_OP:
297 
298         return (BLOCK_PAREN | BLOCK_BRACE);
299 
300     case AML_EVENT_OP:
301 
302         return (BLOCK_PAREN);
303 
304     default:
305 
306         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
307         if (OpInfo->Flags & AML_HAS_ARGS)
308         {
309             return (BLOCK_PAREN);
310         }
311 
312         return (BLOCK_NONE);
313     }
314 }
315 
316 
317 /*******************************************************************************
318  *
319  * FUNCTION:    AcpiDmListType
320  *
321  * PARAMETERS:  Op              - Object to be examined
322  *
323  * RETURN:      ListType - has commas or not.
324  *
325  * DESCRIPTION: Type of block for this op (parens or braces)
326  *
327  ******************************************************************************/
328 
329 UINT32
330 AcpiDmListType (
331     ACPI_PARSE_OBJECT       *Op)
332 {
333     const ACPI_OPCODE_INFO  *OpInfo;
334 
335 
336     if (!Op)
337     {
338         return (BLOCK_NONE);
339     }
340 
341     switch (Op->Common.AmlOpcode)
342     {
343 
344     case AML_ELSE_OP:
345     case AML_METHOD_OP:
346     case AML_DEVICE_OP:
347     case AML_SCOPE_OP:
348     case AML_POWER_RES_OP:
349     case AML_PROCESSOR_OP:
350     case AML_THERMAL_ZONE_OP:
351     case AML_IF_OP:
352     case AML_WHILE_OP:
353     case AML_FIELD_OP:
354     case AML_INDEX_FIELD_OP:
355     case AML_BANK_FIELD_OP:
356 
357         return (BLOCK_NONE);
358 
359     case AML_BUFFER_OP:
360     case AML_PACKAGE_OP:
361     case AML_VAR_PACKAGE_OP:
362 
363         return (BLOCK_COMMA_LIST);
364 
365     default:
366 
367         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
368         if (OpInfo->Flags & AML_HAS_ARGS)
369         {
370             return (BLOCK_COMMA_LIST);
371         }
372 
373         return (BLOCK_NONE);
374     }
375 }
376 
377 
378 /*******************************************************************************
379  *
380  * FUNCTION:    AcpiDmDescendingOp
381  *
382  * PARAMETERS:  ASL_WALK_CALLBACK
383  *
384  * RETURN:      Status
385  *
386  * DESCRIPTION: First visitation of a parse object during tree descent.
387  *              Decode opcode name and begin parameter list(s), if any.
388  *
389  ******************************************************************************/
390 
391 static ACPI_STATUS
392 AcpiDmDescendingOp (
393     ACPI_PARSE_OBJECT       *Op,
394     UINT32                  Level,
395     void                    *Context)
396 {
397     ACPI_OP_WALK_INFO       *Info = Context;
398     const ACPI_OPCODE_INFO  *OpInfo;
399     UINT32                  Name;
400     ACPI_PARSE_OBJECT       *NextOp;
401 
402 
403     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
404     {
405         /* Ignore this op -- it was handled elsewhere */
406 
407         return (AE_CTRL_DEPTH);
408     }
409 
410     /* Level 0 is at the Definition Block level */
411 
412     if (Level == 0)
413     {
414         /* In verbose mode, print the AML offset, opcode and depth count */
415 
416         if (Info->WalkState)
417         {
418             VERBOSE_PRINT ((DB_FULL_OP_INFO,
419                 (Info->WalkState->MethodNode ?
420                     Info->WalkState->MethodNode->Name.Ascii : "   "),
421                 Op->Common.AmlOffset, (UINT32) Op->Common.AmlOpcode));
422         }
423 
424         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
425         {
426             /* This is the beginning of the Definition Block */
427 
428             AcpiOsPrintf ("{\n");
429 
430             /* Emit all External() declarations here */
431 
432             AcpiDmEmitExternals ();
433             return (AE_OK);
434         }
435     }
436     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
437              (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
438              (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
439     {
440             /*
441              * This is a first-level element of a term list,
442              * indent a new line
443              */
444             switch (Op->Common.AmlOpcode)
445             {
446             case AML_NOOP_OP:
447                 /*
448                  * Optionally just ignore this opcode. Some tables use
449                  * NoOp opcodes for "padding" out packages that the BIOS
450                  * changes dynamically. This can leave hundreds or
451                  * thousands of NoOp opcodes that if disassembled,
452                  * cannot be compiled because they are syntactically
453                  * incorrect.
454                  */
455                 if (AcpiGbl_IgnoreNoopOperator)
456                 {
457                     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
458                     return (AE_OK);
459                 }
460 
461                 /* Fallthrough */
462 
463             default:
464 
465                 AcpiDmIndent (Level);
466                 break;
467             }
468 
469             Info->LastLevel = Level;
470             Info->Count = 0;
471     }
472 
473     /*
474      * This is an inexpensive mechanism to try and keep lines from getting
475      * too long. When the limit is hit, start a new line at the previous
476      * indent plus one. A better but more expensive mechanism would be to
477      * keep track of the current column.
478      */
479     Info->Count++;
480     if (Info->Count /* +Info->LastLevel */ > 10)
481     {
482         Info->Count = 0;
483         AcpiOsPrintf ("\n");
484         AcpiDmIndent (Info->LastLevel + 1);
485     }
486 
487     /* Print the opcode name */
488 
489     AcpiDmDisassembleOneOp (NULL, Info, Op);
490 
491     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
492         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
493     {
494         return (AE_OK);
495     }
496 
497     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
498         (Op->Common.AmlOpcode == AML_RETURN_OP))
499     {
500         Info->Level--;
501     }
502 
503     /* Start the opcode argument list if necessary */
504 
505     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
506 
507     if ((OpInfo->Flags & AML_HAS_ARGS) ||
508         (Op->Common.AmlOpcode == AML_EVENT_OP))
509     {
510         /* This opcode has an argument list */
511 
512         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
513         {
514             AcpiOsPrintf (" (");
515         }
516 
517         /* If this is a named opcode, print the associated name value */
518 
519         if (OpInfo->Flags & AML_NAMED)
520         {
521             switch (Op->Common.AmlOpcode)
522             {
523             case AML_ALIAS_OP:
524 
525                 NextOp = AcpiPsGetDepthNext (NULL, Op);
526                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
527                 AcpiDmNamestring (NextOp->Common.Value.Name);
528                 AcpiOsPrintf (", ");
529 
530                 /*lint -fallthrough */
531 
532             default:
533 
534                 Name = AcpiPsGetName (Op);
535                 if (Op->Named.Path)
536                 {
537                     AcpiDmNamestring ((char *) Op->Named.Path);
538                 }
539                 else
540                 {
541                     AcpiDmDumpName (Name);
542                 }
543 
544                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
545                 {
546                     if (AcpiGbl_DbOpt_verbose)
547                     {
548                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
549                     }
550                 }
551                 break;
552             }
553 
554             switch (Op->Common.AmlOpcode)
555             {
556             case AML_METHOD_OP:
557 
558                 AcpiDmMethodFlags (Op);
559                 AcpiOsPrintf (")");
560 
561                 /* Emit description comment for Method() with a predefined ACPI name */
562 
563                 AcpiDmPredefinedDescription (Op);
564                 break;
565 
566 
567             case AML_NAME_OP:
568 
569                 /* Check for _HID and related EISAID() */
570 
571                 AcpiDmCheckForHardwareId (Op);
572                 AcpiOsPrintf (", ");
573                 break;
574 
575 
576             case AML_REGION_OP:
577 
578                 AcpiDmRegionFlags (Op);
579                 break;
580 
581 
582             case AML_POWER_RES_OP:
583 
584                 /* Mark the next two Ops as part of the parameter list */
585 
586                 AcpiOsPrintf (", ");
587                 NextOp = AcpiPsGetDepthNext (NULL, Op);
588                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
589 
590                 NextOp = NextOp->Common.Next;
591                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
592                 return (AE_OK);
593 
594 
595             case AML_PROCESSOR_OP:
596 
597                 /* Mark the next three Ops as part of the parameter list */
598 
599                 AcpiOsPrintf (", ");
600                 NextOp = AcpiPsGetDepthNext (NULL, Op);
601                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
602 
603                 NextOp = NextOp->Common.Next;
604                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
605 
606                 NextOp = NextOp->Common.Next;
607                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
608                 return (AE_OK);
609 
610 
611             case AML_MUTEX_OP:
612             case AML_DATA_REGION_OP:
613 
614                 AcpiOsPrintf (", ");
615                 return (AE_OK);
616 
617 
618             case AML_EVENT_OP:
619             case AML_ALIAS_OP:
620 
621                 return (AE_OK);
622 
623 
624             case AML_SCOPE_OP:
625             case AML_DEVICE_OP:
626             case AML_THERMAL_ZONE_OP:
627 
628                 AcpiOsPrintf (")");
629                 break;
630 
631 
632             default:
633 
634                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
635                     Op->Common.AmlOpcode);
636                 break;
637             }
638         }
639 
640         else switch (Op->Common.AmlOpcode)
641         {
642         case AML_FIELD_OP:
643         case AML_BANK_FIELD_OP:
644         case AML_INDEX_FIELD_OP:
645 
646             Info->BitOffset = 0;
647 
648             /* Name of the parent OperationRegion */
649 
650             NextOp = AcpiPsGetDepthNext (NULL, Op);
651             AcpiDmNamestring (NextOp->Common.Value.Name);
652             AcpiOsPrintf (", ");
653             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
654 
655             switch (Op->Common.AmlOpcode)
656             {
657             case AML_BANK_FIELD_OP:
658 
659                 /* Namestring - Bank Name */
660 
661                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
662                 AcpiDmNamestring (NextOp->Common.Value.Name);
663                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
664                 AcpiOsPrintf (", ");
665 
666                 /*
667                  * Bank Value. This is a TermArg in the middle of the parameter
668                  * list, must handle it here.
669                  *
670                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST
671                  * eliminates newline in the output.
672                  */
673                 NextOp = NextOp->Common.Next;
674 
675                 Info->Flags = ACPI_PARSEOP_PARAMLIST;
676                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
677                     AcpiDmAscendingOp, Info);
678                 Info->Flags = 0;
679                 Info->Level = Level;
680 
681                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
682                 AcpiOsPrintf (", ");
683                 break;
684 
685             case AML_INDEX_FIELD_OP:
686 
687                 /* Namestring - Data Name */
688 
689                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
690                 AcpiDmNamestring (NextOp->Common.Value.Name);
691                 AcpiOsPrintf (", ");
692                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
693                 break;
694 
695             default:
696 
697                 break;
698             }
699 
700             AcpiDmFieldFlags (NextOp);
701             break;
702 
703         case AML_BUFFER_OP:
704 
705             /* The next op is the size parameter */
706 
707             NextOp = AcpiPsGetDepthNext (NULL, Op);
708             if (!NextOp)
709             {
710                 /* Single-step support */
711 
712                 return (AE_OK);
713             }
714 
715             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
716             {
717                 /*
718                  * We have a resource list. Don't need to output
719                  * the buffer size Op. Open up a new block
720                  */
721                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
722                 NextOp = NextOp->Common.Next;
723                 AcpiOsPrintf (")");
724 
725                 /* Emit description comment for Name() with a predefined ACPI name */
726 
727                 AcpiDmPredefinedDescription (Op->Asl.Parent);
728 
729                 AcpiOsPrintf ("\n");
730                 AcpiDmIndent (Info->Level);
731                 AcpiOsPrintf ("{\n");
732                 return (AE_OK);
733             }
734 
735             /* Normal Buffer, mark size as in the parameter list */
736 
737             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
738             return (AE_OK);
739 
740         case AML_VAR_PACKAGE_OP:
741         case AML_IF_OP:
742         case AML_WHILE_OP:
743 
744             /* The next op is the size or predicate parameter */
745 
746             NextOp = AcpiPsGetDepthNext (NULL, Op);
747             if (NextOp)
748             {
749                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
750             }
751             return (AE_OK);
752 
753         case AML_PACKAGE_OP:
754 
755             /* The next op is the size parameter */
756 
757             NextOp = AcpiPsGetDepthNext (NULL, Op);
758             if (NextOp)
759             {
760                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
761             }
762             return (AE_OK);
763 
764         case AML_MATCH_OP:
765 
766             AcpiDmMatchOp (Op);
767             break;
768 
769         default:
770 
771             break;
772         }
773 
774         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
775         {
776             AcpiOsPrintf ("\n");
777             AcpiDmIndent (Level);
778             AcpiOsPrintf ("{\n");
779         }
780     }
781 
782     return (AE_OK);
783 }
784 
785 
786 /*******************************************************************************
787  *
788  * FUNCTION:    AcpiDmAscendingOp
789  *
790  * PARAMETERS:  ASL_WALK_CALLBACK
791  *
792  * RETURN:      Status
793  *
794  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
795  *              tree. Close out any parameter lists and complete the opcode.
796  *
797  ******************************************************************************/
798 
799 static ACPI_STATUS
800 AcpiDmAscendingOp (
801     ACPI_PARSE_OBJECT       *Op,
802     UINT32                  Level,
803     void                    *Context)
804 {
805     ACPI_OP_WALK_INFO       *Info = Context;
806     ACPI_PARSE_OBJECT       *ParentOp;
807 
808 
809     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
810     {
811         /* Ignore this op -- it was handled elsewhere */
812 
813         return (AE_OK);
814     }
815 
816     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
817     {
818         /* Indicates the end of the current descriptor block (table) */
819 
820         AcpiOsPrintf ("}\n\n");
821         return (AE_OK);
822     }
823 
824     switch (AcpiDmBlockType (Op))
825     {
826     case BLOCK_PAREN:
827 
828         /* Completed an op that has arguments, add closing paren */
829 
830         AcpiOsPrintf (")");
831 
832         if (Op->Common.AmlOpcode == AML_NAME_OP)
833         {
834             /* Emit description comment for Name() with a predefined ACPI name */
835 
836             AcpiDmPredefinedDescription (Op);
837         }
838         else
839         {
840             /* For Create* operators, attempt to emit resource tag description */
841 
842             AcpiDmFieldPredefinedDescription (Op);
843         }
844 
845         /* Decode Notify() values */
846 
847         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
848         {
849             AcpiDmNotifyDescription (Op);
850         }
851 
852         AcpiDmDisplayTargetPathname (Op);
853 
854         /* Could be a nested operator, check if comma required */
855 
856         if (!AcpiDmCommaIfListMember (Op))
857         {
858             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
859                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
860                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
861             {
862                 /*
863                  * This is a first-level element of a term list
864                  * start a new line
865                  */
866                 if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST))
867                 {
868                     AcpiOsPrintf ("\n");
869                 }
870             }
871         }
872         break;
873 
874     case BLOCK_BRACE:
875     case (BLOCK_BRACE | BLOCK_PAREN):
876 
877         /* Completed an op that has a term list, add closing brace */
878 
879         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
880         {
881             AcpiOsPrintf ("}");
882         }
883         else
884         {
885             AcpiDmIndent (Level);
886             AcpiOsPrintf ("}");
887         }
888 
889         AcpiDmCommaIfListMember (Op);
890 
891         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
892         {
893             AcpiOsPrintf ("\n");
894             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
895             {
896                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
897                     (Op->Common.Next) &&
898                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
899                 {
900                     break;
901                 }
902 
903                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
904                     (!Op->Common.Next))
905                 {
906                     break;
907                 }
908                 AcpiOsPrintf ("\n");
909             }
910         }
911         break;
912 
913     case BLOCK_NONE:
914     default:
915 
916         /* Could be a nested operator, check if comma required */
917 
918         if (!AcpiDmCommaIfListMember (Op))
919         {
920             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
921                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
922                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
923             {
924                 /*
925                  * This is a first-level element of a term list
926                  * start a new line
927                  */
928                 AcpiOsPrintf ("\n");
929             }
930         }
931         else if (Op->Common.Parent)
932         {
933             switch (Op->Common.Parent->Common.AmlOpcode)
934             {
935             case AML_PACKAGE_OP:
936             case AML_VAR_PACKAGE_OP:
937 
938                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
939                 {
940                     AcpiOsPrintf ("\n");
941                 }
942                 break;
943 
944             default:
945 
946                 break;
947             }
948         }
949         break;
950     }
951 
952     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)
953     {
954         if ((Op->Common.Next) &&
955             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
956         {
957             return (AE_OK);
958         }
959 
960         /*
961          * The parent Op is guaranteed to be valid because of the flag
962          * ACPI_PARSEOP_PARAMLIST -- which means that this op is part of
963          * a parameter list and thus has a valid parent.
964          */
965         ParentOp = Op->Common.Parent;
966 
967         /*
968          * Just completed a parameter node for something like "Buffer (param)".
969          * Close the paren and open up the term list block with a brace
970          */
971         if (Op->Common.Next)
972         {
973             AcpiOsPrintf (")");
974 
975             /*
976              * Emit a description comment for a Name() operator that is a
977              * predefined ACPI name. Must check the grandparent.
978              */
979             ParentOp = ParentOp->Common.Parent;
980             if (ParentOp &&
981                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
982             {
983                 AcpiDmPredefinedDescription (ParentOp);
984             }
985 
986             AcpiOsPrintf ("\n");
987             AcpiDmIndent (Level - 1);
988             AcpiOsPrintf ("{\n");
989         }
990         else
991         {
992             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
993             AcpiOsPrintf (") {");
994         }
995     }
996 
997     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
998         (Op->Common.AmlOpcode == AML_RETURN_OP))
999     {
1000         Info->Level++;
1001     }
1002     return (AE_OK);
1003 }
1004 
1005 
1006 #endif  /* ACPI_DISASSEMBLER */
1007