1 /*******************************************************************************
2  *
3  * Module Name: dmwalk - AML disassembly tree walk
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "acpi.h"
45 #include "accommon.h"
46 #include "acparser.h"
47 #include "amlcode.h"
48 #include "acdebug.h"
49 
50 
51 #ifdef ACPI_DISASSEMBLER
52 
53 #define _COMPONENT          ACPI_CA_DEBUGGER
54         ACPI_MODULE_NAME    ("dmwalk")
55 
56 
57 #define DB_FULL_OP_INFO     "[%4.4s] @%5.5X #%4.4X:  "
58 
59 /* Stub for non-compiler code */
60 
61 #ifndef ACPI_ASL_COMPILER
62 void
63 AcpiDmEmitExternals (
64     void)
65 {
66     return;
67 }
68 #endif
69 
70 /* Local prototypes */
71 
72 static ACPI_STATUS
73 AcpiDmDescendingOp (
74     ACPI_PARSE_OBJECT       *Op,
75     UINT32                  Level,
76     void                    *Context);
77 
78 static ACPI_STATUS
79 AcpiDmAscendingOp (
80     ACPI_PARSE_OBJECT       *Op,
81     UINT32                  Level,
82     void                    *Context);
83 
84 static UINT32
85 AcpiDmBlockType (
86     ACPI_PARSE_OBJECT       *Op);
87 
88 
89 /*******************************************************************************
90  *
91  * FUNCTION:    AcpiDmDisassemble
92  *
93  * PARAMETERS:  WalkState       - Current state
94  *              Origin          - Starting object
95  *              NumOpcodes      - Max number of opcodes to be displayed
96  *
97  * RETURN:      None
98  *
99  * DESCRIPTION: Disassemble parser object and its children. This is the
100  *              main entry point of the disassembler.
101  *
102  ******************************************************************************/
103 
104 void
105 AcpiDmDisassemble (
106     ACPI_WALK_STATE         *WalkState,
107     ACPI_PARSE_OBJECT       *Origin,
108     UINT32                  NumOpcodes)
109 {
110     ACPI_PARSE_OBJECT       *Op = Origin;
111     ACPI_OP_WALK_INFO       Info;
112 
113 
114     if (!Op)
115     {
116         return;
117     }
118 
119     memset (&Info, 0, sizeof (ACPI_OP_WALK_INFO));
120     Info.WalkState = WalkState;
121     Info.StartAml = Op->Common.Aml - sizeof (ACPI_TABLE_HEADER);
122     Info.AmlOffset = Op->Common.Aml - Info.StartAml;
123 
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             (Op->Common.DisasmOpcode == ACPI_DASM_PLD_METHOD))
290         {
291             return (BLOCK_NONE);
292         }
293 
294         /*lint -fallthrough */
295 
296     case AML_PACKAGE_OP:
297     case AML_VAR_PACKAGE_OP:
298 
299         return (BLOCK_PAREN | BLOCK_BRACE);
300 
301     case AML_EVENT_OP:
302 
303         return (BLOCK_PAREN);
304 
305     case AML_INT_METHODCALL_OP:
306 
307         if (Op->Common.Parent &&
308             ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
309              (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)))
310         {
311             /* This is a reference to a method, not an invocation */
312 
313             return (BLOCK_NONE);
314         }
315 
316         /*lint -fallthrough */
317 
318     default:
319 
320         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
321         if (OpInfo->Flags & AML_HAS_ARGS)
322         {
323             return (BLOCK_PAREN);
324         }
325 
326         return (BLOCK_NONE);
327     }
328 }
329 
330 
331 /*******************************************************************************
332  *
333  * FUNCTION:    AcpiDmListType
334  *
335  * PARAMETERS:  Op              - Object to be examined
336  *
337  * RETURN:      ListType - has commas or not.
338  *
339  * DESCRIPTION: Type of block for this op (parens or braces)
340  *
341  ******************************************************************************/
342 
343 UINT32
344 AcpiDmListType (
345     ACPI_PARSE_OBJECT       *Op)
346 {
347     const ACPI_OPCODE_INFO  *OpInfo;
348 
349 
350     if (!Op)
351     {
352         return (BLOCK_NONE);
353     }
354 
355     switch (Op->Common.AmlOpcode)
356     {
357 
358     case AML_ELSE_OP:
359     case AML_METHOD_OP:
360     case AML_DEVICE_OP:
361     case AML_SCOPE_OP:
362     case AML_POWER_RES_OP:
363     case AML_PROCESSOR_OP:
364     case AML_THERMAL_ZONE_OP:
365     case AML_IF_OP:
366     case AML_WHILE_OP:
367     case AML_FIELD_OP:
368     case AML_INDEX_FIELD_OP:
369     case AML_BANK_FIELD_OP:
370 
371         return (BLOCK_NONE);
372 
373     case AML_BUFFER_OP:
374     case AML_PACKAGE_OP:
375     case AML_VAR_PACKAGE_OP:
376 
377         return (BLOCK_COMMA_LIST);
378 
379     default:
380 
381         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
382         if (OpInfo->Flags & AML_HAS_ARGS)
383         {
384             return (BLOCK_COMMA_LIST);
385         }
386 
387         return (BLOCK_NONE);
388     }
389 }
390 
391 
392 /*******************************************************************************
393  *
394  * FUNCTION:    AcpiDmDescendingOp
395  *
396  * PARAMETERS:  ASL_WALK_CALLBACK
397  *
398  * RETURN:      Status
399  *
400  * DESCRIPTION: First visitation of a parse object during tree descent.
401  *              Decode opcode name and begin parameter list(s), if any.
402  *
403  ******************************************************************************/
404 
405 static ACPI_STATUS
406 AcpiDmDescendingOp (
407     ACPI_PARSE_OBJECT       *Op,
408     UINT32                  Level,
409     void                    *Context)
410 {
411     ACPI_OP_WALK_INFO       *Info = Context;
412     const ACPI_OPCODE_INFO  *OpInfo;
413     UINT32                  Name;
414     ACPI_PARSE_OBJECT       *NextOp;
415     ACPI_PARSE_OBJECT       *NextOp2;
416     UINT32                  AmlOffset;
417 
418 
419     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
420 
421     /* Listing support to dump the AML code after the ASL statement */
422 
423     if (AcpiGbl_DmOpt_Listing)
424     {
425         /* We only care about these classes of objects */
426 
427         if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) ||
428             (OpInfo->Class == AML_CLASS_CONTROL) ||
429             (OpInfo->Class == AML_CLASS_CREATE) ||
430             ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Op->Common.Next)))
431         {
432             if (AcpiGbl_DmOpt_Listing && Info->PreviousAml)
433             {
434                 /* Dump the AML byte code for the previous Op */
435 
436                 if (Op->Common.Aml > Info->PreviousAml)
437                 {
438                     AcpiOsPrintf ("\n");
439                     AcpiUtDumpBuffer (
440                         (Info->StartAml + Info->AmlOffset),
441                         (Op->Common.Aml - Info->PreviousAml),
442                         DB_BYTE_DISPLAY, Info->AmlOffset);
443                     AcpiOsPrintf ("\n");
444                 }
445 
446                 Info->AmlOffset = (Op->Common.Aml - Info->StartAml);
447             }
448 
449             Info->PreviousAml = Op->Common.Aml;
450         }
451     }
452 
453     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
454     {
455         /* Ignore this op -- it was handled elsewhere */
456 
457         return (AE_CTRL_DEPTH);
458     }
459 
460     if (AcpiDmIsTempName(Op))
461     {
462         /* Ignore compiler generated temporary names */
463 
464         return (AE_CTRL_DEPTH);
465     }
466 
467     if (Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
468     {
469         /* Ignore this op, but not it's children */
470 
471         return (AE_OK);
472     }
473 
474     if (Op->Common.AmlOpcode == AML_IF_OP)
475     {
476         NextOp = AcpiPsGetDepthNext (NULL, Op);
477         if (NextOp)
478         {
479             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
480 
481             /* Don't emit the actual embedded externals unless asked */
482 
483             if (!AcpiGbl_DmEmitExternalOpcodes)
484             {
485                 /*
486                  * A Zero predicate indicates the possibility of one or more
487                  * External() opcodes within the If() block.
488                  */
489                 if (NextOp->Common.AmlOpcode == AML_ZERO_OP)
490                 {
491                     NextOp2 = NextOp->Common.Next;
492 
493                     if (NextOp2 &&
494                         (NextOp2->Common.AmlOpcode == AML_EXTERNAL_OP))
495                     {
496                         /* Ignore the If 0 block and all children */
497 
498                         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
499                         return (AE_CTRL_DEPTH);
500                     }
501                 }
502             }
503         }
504     }
505 
506     /* Level 0 is at the Definition Block level */
507 
508     if (Level == 0)
509     {
510         /* In verbose mode, print the AML offset, opcode and depth count */
511 
512         if (Info->WalkState)
513         {
514             AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
515                 Info->WalkState->ParserState.AmlStart);
516             if (AcpiGbl_DmOpt_Verbose)
517             {
518                 AcpiOsPrintf (DB_FULL_OP_INFO,
519                     (Info->WalkState->MethodNode ?
520                         Info->WalkState->MethodNode->Name.Ascii : "   "),
521                     AmlOffset, (UINT32) Op->Common.AmlOpcode);
522             }
523         }
524 
525         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
526         {
527             /* This is the beginning of the Definition Block */
528 
529             AcpiOsPrintf ("{\n");
530 
531             /* Emit all External() declarations here */
532 
533             AcpiDmEmitExternals ();
534             return (AE_OK);
535         }
536     }
537     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
538          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
539          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)) &&
540          (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
541     {
542         /*
543          * This is a first-level element of a term list,
544          * indent a new line
545          */
546         switch (Op->Common.AmlOpcode)
547         {
548         case AML_NOOP_OP:
549             /*
550              * Optionally just ignore this opcode. Some tables use
551              * NoOp opcodes for "padding" out packages that the BIOS
552              * changes dynamically. This can leave hundreds or
553              * thousands of NoOp opcodes that if disassembled,
554              * cannot be compiled because they are syntactically
555              * incorrect.
556              */
557             if (AcpiGbl_IgnoreNoopOperator)
558             {
559                 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
560                 return (AE_OK);
561             }
562 
563             /* Fallthrough */
564 
565         default:
566 
567             AcpiDmIndent (Level);
568             break;
569         }
570 
571         Info->LastLevel = Level;
572         Info->Count = 0;
573     }
574 
575     /*
576      * This is an inexpensive mechanism to try and keep lines from getting
577      * too long. When the limit is hit, start a new line at the previous
578      * indent plus one. A better but more expensive mechanism would be to
579      * keep track of the current column.
580      */
581     Info->Count++;
582     if (Info->Count /* +Info->LastLevel */ > 12)
583     {
584         Info->Count = 0;
585         AcpiOsPrintf ("\n");
586         AcpiDmIndent (Info->LastLevel + 1);
587     }
588 
589     /* If ASL+ is enabled, check for a C-style operator */
590 
591     if (AcpiDmCheckForSymbolicOpcode (Op, Info))
592     {
593         return (AE_OK);
594     }
595 
596     /* Print the opcode name */
597 
598     AcpiDmDisassembleOneOp (NULL, Info, Op);
599 
600     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
601         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
602     {
603         return (AE_OK);
604     }
605 
606     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
607         (Op->Common.AmlOpcode == AML_RETURN_OP))
608     {
609         Info->Level--;
610     }
611 
612     /* Start the opcode argument list if necessary */
613 
614     if ((OpInfo->Flags & AML_HAS_ARGS) ||
615         (Op->Common.AmlOpcode == AML_EVENT_OP))
616     {
617         /* This opcode has an argument list */
618 
619         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
620         {
621             AcpiOsPrintf (" (");
622         }
623 
624         /* If this is a named opcode, print the associated name value */
625 
626         if (OpInfo->Flags & AML_NAMED)
627         {
628             switch (Op->Common.AmlOpcode)
629             {
630             case AML_ALIAS_OP:
631 
632                 NextOp = AcpiPsGetDepthNext (NULL, Op);
633                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
634                 AcpiDmNamestring (NextOp->Common.Value.Name);
635                 AcpiOsPrintf (", ");
636 
637                 /*lint -fallthrough */
638 
639             default:
640 
641                 Name = AcpiPsGetName (Op);
642                 if (Op->Named.Path)
643                 {
644                     AcpiDmNamestring ((char *) Op->Named.Path);
645                 }
646                 else
647                 {
648                     AcpiDmDumpName (Name);
649                 }
650 
651                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
652                 {
653                     if (AcpiGbl_DmOpt_Verbose)
654                     {
655                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
656                     }
657                 }
658                 break;
659             }
660 
661             switch (Op->Common.AmlOpcode)
662             {
663             case AML_METHOD_OP:
664 
665                 AcpiDmMethodFlags (Op);
666                 AcpiOsPrintf (")");
667 
668                 /* Emit description comment for Method() with a predefined ACPI name */
669 
670                 AcpiDmPredefinedDescription (Op);
671                 break;
672 
673             case AML_NAME_OP:
674 
675                 /* Check for _HID and related EISAID() */
676 
677                 AcpiDmCheckForHardwareId (Op);
678                 AcpiOsPrintf (", ");
679                 break;
680 
681             case AML_REGION_OP:
682 
683                 AcpiDmRegionFlags (Op);
684                 break;
685 
686             case AML_POWER_RES_OP:
687 
688                 /* Mark the next two Ops as part of the parameter list */
689 
690                 AcpiOsPrintf (", ");
691                 NextOp = AcpiPsGetDepthNext (NULL, Op);
692                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
693 
694                 NextOp = NextOp->Common.Next;
695                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
696                 return (AE_OK);
697 
698             case AML_PROCESSOR_OP:
699 
700                 /* Mark the next three Ops as part of the parameter list */
701 
702                 AcpiOsPrintf (", ");
703                 NextOp = AcpiPsGetDepthNext (NULL, Op);
704                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
705 
706                 NextOp = NextOp->Common.Next;
707                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
708 
709                 NextOp = NextOp->Common.Next;
710                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
711                 return (AE_OK);
712 
713             case AML_MUTEX_OP:
714             case AML_DATA_REGION_OP:
715 
716                 AcpiOsPrintf (", ");
717                 return (AE_OK);
718 
719             case AML_EVENT_OP:
720             case AML_ALIAS_OP:
721 
722                 return (AE_OK);
723 
724             case AML_SCOPE_OP:
725             case AML_DEVICE_OP:
726             case AML_THERMAL_ZONE_OP:
727 
728                 AcpiOsPrintf (")");
729                 break;
730 
731             default:
732 
733                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
734                     Op->Common.AmlOpcode);
735                 break;
736             }
737         }
738 
739         else switch (Op->Common.AmlOpcode)
740         {
741         case AML_FIELD_OP:
742         case AML_BANK_FIELD_OP:
743         case AML_INDEX_FIELD_OP:
744 
745             Info->BitOffset = 0;
746 
747             /* Name of the parent OperationRegion */
748 
749             NextOp = AcpiPsGetDepthNext (NULL, Op);
750             AcpiDmNamestring (NextOp->Common.Value.Name);
751             AcpiOsPrintf (", ");
752             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
753 
754             switch (Op->Common.AmlOpcode)
755             {
756             case AML_BANK_FIELD_OP:
757 
758                 /* Namestring - Bank Name */
759 
760                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
761                 AcpiDmNamestring (NextOp->Common.Value.Name);
762                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
763                 AcpiOsPrintf (", ");
764 
765                 /*
766                  * Bank Value. This is a TermArg in the middle of the parameter
767                  * list, must handle it here.
768                  *
769                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMETER_LIST
770                  * eliminates newline in the output.
771                  */
772                 NextOp = NextOp->Common.Next;
773 
774                 Info->Flags = ACPI_PARSEOP_PARAMETER_LIST;
775                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
776                     AcpiDmAscendingOp, Info);
777                 Info->Flags = 0;
778                 Info->Level = Level;
779 
780                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
781                 AcpiOsPrintf (", ");
782                 break;
783 
784             case AML_INDEX_FIELD_OP:
785 
786                 /* Namestring - Data Name */
787 
788                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
789                 AcpiDmNamestring (NextOp->Common.Value.Name);
790                 AcpiOsPrintf (", ");
791                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
792                 break;
793 
794             default:
795 
796                 break;
797             }
798 
799             AcpiDmFieldFlags (NextOp);
800             break;
801 
802         case AML_BUFFER_OP:
803 
804             /* The next op is the size parameter */
805 
806             NextOp = AcpiPsGetDepthNext (NULL, Op);
807             if (!NextOp)
808             {
809                 /* Single-step support */
810 
811                 return (AE_OK);
812             }
813 
814             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
815             {
816                 /*
817                  * We have a resource list. Don't need to output
818                  * the buffer size Op. Open up a new block
819                  */
820                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
821                 NextOp = NextOp->Common.Next;
822                 AcpiOsPrintf (")");
823 
824                 /* Emit description comment for Name() with a predefined ACPI name */
825 
826                 AcpiDmPredefinedDescription (Op->Asl.Parent);
827 
828                 AcpiOsPrintf ("\n");
829                 AcpiDmIndent (Info->Level);
830                 AcpiOsPrintf ("{\n");
831                 return (AE_OK);
832             }
833 
834             /* Normal Buffer, mark size as in the parameter list */
835 
836             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
837             return (AE_OK);
838 
839         case AML_IF_OP:
840         case AML_VAR_PACKAGE_OP:
841         case AML_WHILE_OP:
842 
843             /* The next op is the size or predicate parameter */
844 
845             NextOp = AcpiPsGetDepthNext (NULL, Op);
846             if (NextOp)
847             {
848                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
849             }
850             return (AE_OK);
851 
852         case AML_PACKAGE_OP:
853 
854             /* The next op is the size parameter */
855 
856             NextOp = AcpiPsGetDepthNext (NULL, Op);
857             if (NextOp)
858             {
859                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
860             }
861             return (AE_OK);
862 
863         case AML_MATCH_OP:
864 
865             AcpiDmMatchOp (Op);
866             break;
867 
868         default:
869 
870             break;
871         }
872 
873         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
874         {
875             AcpiOsPrintf ("\n");
876             AcpiDmIndent (Level);
877             AcpiOsPrintf ("{\n");
878         }
879     }
880 
881     return (AE_OK);
882 }
883 
884 
885 /*******************************************************************************
886  *
887  * FUNCTION:    AcpiDmAscendingOp
888  *
889  * PARAMETERS:  ASL_WALK_CALLBACK
890  *
891  * RETURN:      Status
892  *
893  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
894  *              tree. Close out any parameter lists and complete the opcode.
895  *
896  ******************************************************************************/
897 
898 static ACPI_STATUS
899 AcpiDmAscendingOp (
900     ACPI_PARSE_OBJECT       *Op,
901     UINT32                  Level,
902     void                    *Context)
903 {
904     ACPI_OP_WALK_INFO       *Info = Context;
905     ACPI_PARSE_OBJECT       *ParentOp;
906 
907 
908     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE ||
909         Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
910     {
911         /* Ignore this op -- it was handled elsewhere */
912 
913         return (AE_OK);
914     }
915 
916     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
917     {
918         /* Indicates the end of the current descriptor block (table) */
919 
920         AcpiOsPrintf ("}\n\n");
921         return (AE_OK);
922     }
923 
924     switch (AcpiDmBlockType (Op))
925     {
926     case BLOCK_PAREN:
927 
928         /* Completed an op that has arguments, add closing paren if needed */
929 
930         AcpiDmCloseOperator (Op);
931 
932         if (Op->Common.AmlOpcode == AML_NAME_OP)
933         {
934             /* Emit description comment for Name() with a predefined ACPI name */
935 
936             AcpiDmPredefinedDescription (Op);
937         }
938         else
939         {
940             /* For Create* operators, attempt to emit resource tag description */
941 
942             AcpiDmFieldPredefinedDescription (Op);
943         }
944 
945         /* Decode Notify() values */
946 
947         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
948         {
949             AcpiDmNotifyDescription (Op);
950         }
951 
952         AcpiDmDisplayTargetPathname (Op);
953 
954         /* Could be a nested operator, check if comma required */
955 
956         if (!AcpiDmCommaIfListMember (Op))
957         {
958             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
959                  (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
960                  (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
961             {
962                 /*
963                  * This is a first-level element of a term list
964                  * start a new line
965                  */
966                 if (!(Info->Flags & ACPI_PARSEOP_PARAMETER_LIST))
967                 {
968                     AcpiOsPrintf ("\n");
969                 }
970             }
971         }
972         break;
973 
974     case BLOCK_BRACE:
975     case (BLOCK_BRACE | BLOCK_PAREN):
976 
977         /* Completed an op that has a term list, add closing brace */
978 
979         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
980         {
981             AcpiOsPrintf ("}");
982         }
983         else
984         {
985             AcpiDmIndent (Level);
986             AcpiOsPrintf ("}");
987         }
988 
989         AcpiDmCommaIfListMember (Op);
990 
991         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
992         {
993             AcpiOsPrintf ("\n");
994             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
995             {
996                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
997                     (Op->Common.Next) &&
998                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
999                 {
1000                     break;
1001                 }
1002 
1003                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1004                     (!Op->Common.Next))
1005                 {
1006                     break;
1007                 }
1008                 AcpiOsPrintf ("\n");
1009             }
1010         }
1011         break;
1012 
1013     case BLOCK_NONE:
1014     default:
1015 
1016         /* Could be a nested operator, check if comma required */
1017 
1018         if (!AcpiDmCommaIfListMember (Op))
1019         {
1020             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1021                  (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
1022                  (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
1023             {
1024                 /*
1025                  * This is a first-level element of a term list
1026                  * start a new line
1027                  */
1028                 AcpiOsPrintf ("\n");
1029             }
1030         }
1031         else if (Op->Common.Parent)
1032         {
1033             switch (Op->Common.Parent->Common.AmlOpcode)
1034             {
1035             case AML_PACKAGE_OP:
1036             case AML_VAR_PACKAGE_OP:
1037 
1038                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1039                 {
1040                     AcpiOsPrintf ("\n");
1041                 }
1042                 break;
1043 
1044             default:
1045 
1046                 break;
1047             }
1048         }
1049         break;
1050     }
1051 
1052     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)
1053     {
1054         if ((Op->Common.Next) &&
1055             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1056         {
1057             return (AE_OK);
1058         }
1059 
1060         /*
1061          * The parent Op is guaranteed to be valid because of the flag
1062          * ACPI_PARSEOP_PARAMETER_LIST -- which means that this op is part of
1063          * a parameter list and thus has a valid parent.
1064          */
1065         ParentOp = Op->Common.Parent;
1066 
1067         /*
1068          * Just completed a parameter node for something like "Buffer (param)".
1069          * Close the paren and open up the term list block with a brace.
1070          *
1071          * Switch predicates don't have a Next node but require a closing paren
1072          * and opening brace.
1073          */
1074         if (Op->Common.Next || Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1075         {
1076             AcpiOsPrintf (")");
1077 
1078             /*
1079              * Emit a description comment for a Name() operator that is a
1080              * predefined ACPI name. Must check the grandparent.
1081              */
1082             ParentOp = ParentOp->Common.Parent;
1083             if (ParentOp &&
1084                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
1085             {
1086                 AcpiDmPredefinedDescription (ParentOp);
1087             }
1088 
1089             /* Correct the indentation level for Switch and Case predicates */
1090 
1091             if (Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1092             {
1093                 --Level;
1094             }
1095 
1096             AcpiOsPrintf ("\n");
1097             AcpiDmIndent (Level - 1);
1098             AcpiOsPrintf ("{\n");
1099         }
1100         else
1101         {
1102             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
1103             AcpiOsPrintf (") {");
1104         }
1105     }
1106 
1107     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
1108         (Op->Common.AmlOpcode == AML_RETURN_OP))
1109     {
1110         Info->Level++;
1111     }
1112 
1113     /*
1114      * For ASL+, check for and emit a C-style symbol. If valid, the
1115      * symbol string has been deferred until after the first operand
1116      */
1117     if (AcpiGbl_CstyleDisassembly)
1118     {
1119         if (Op->Asl.OperatorSymbol)
1120         {
1121             AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol);
1122             Op->Asl.OperatorSymbol = NULL;
1123         }
1124     }
1125 
1126     return (AE_OK);
1127 }
1128 
1129 #endif  /* ACPI_DISASSEMBLER */
1130