1 /*******************************************************************************
2  *
3  * Module Name: dmwalk - AML disassembly tree walk
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 MERCHANTABILITY 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 #include "acconvert.h"
50 
51 
52 #define _COMPONENT          ACPI_CA_DEBUGGER
53         ACPI_MODULE_NAME    ("dmwalk")
54 
55 
56 /* Stub for non-compiler code */
57 
58 #ifndef ACPI_ASL_COMPILER
59 void
AcpiDmEmitExternals(void)60 AcpiDmEmitExternals (
61     void)
62 {
63     return;
64 }
65 
66 void
AcpiDmEmitExternal(ACPI_PARSE_OBJECT * NameOp,ACPI_PARSE_OBJECT * TypeOp)67 AcpiDmEmitExternal (
68     ACPI_PARSE_OBJECT       *NameOp,
69     ACPI_PARSE_OBJECT       *TypeOp)
70 {
71     return;
72 }
73 #endif
74 
75 /* Local prototypes */
76 
77 static ACPI_STATUS
78 AcpiDmDescendingOp (
79     ACPI_PARSE_OBJECT       *Op,
80     UINT32                  Level,
81     void                    *Context);
82 
83 static ACPI_STATUS
84 AcpiDmAscendingOp (
85     ACPI_PARSE_OBJECT       *Op,
86     UINT32                  Level,
87     void                    *Context);
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
AcpiDmDisassemble(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Origin,UINT32 NumOpcodes)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     memset (&Info, 0, sizeof (ACPI_OP_WALK_INFO));
121     Info.WalkState = WalkState;
122     Info.StartAml = Op->Common.Aml - sizeof (ACPI_TABLE_HEADER);
123     Info.AmlOffset = Op->Common.Aml - Info.StartAml;
124 
125     AcpiDmWalkParseTree (Op, AcpiDmDescendingOp, AcpiDmAscendingOp, &Info);
126     return;
127 }
128 
129 
130 /*******************************************************************************
131  *
132  * FUNCTION:    AcpiDmWalkParseTree
133  *
134  * PARAMETERS:  Op                      - Root Op object
135  *              DescendingCallback      - Called during tree descent
136  *              AscendingCallback       - Called during tree ascent
137  *              Context                 - To be passed to the callbacks
138  *
139  * RETURN:      Status from callback(s)
140  *
141  * DESCRIPTION: Walk the entire parse tree.
142  *
143  ******************************************************************************/
144 
145 void
AcpiDmWalkParseTree(ACPI_PARSE_OBJECT * Op,ASL_WALK_CALLBACK DescendingCallback,ASL_WALK_CALLBACK AscendingCallback,void * Context)146 AcpiDmWalkParseTree (
147     ACPI_PARSE_OBJECT       *Op,
148     ASL_WALK_CALLBACK       DescendingCallback,
149     ASL_WALK_CALLBACK       AscendingCallback,
150     void                    *Context)
151 {
152     BOOLEAN                 NodePreviouslyVisited;
153     ACPI_PARSE_OBJECT       *StartOp = Op;
154     ACPI_STATUS             Status;
155     ACPI_PARSE_OBJECT       *Next;
156     ACPI_OP_WALK_INFO       *Info = Context;
157 
158 
159     Info->Level = 0;
160     NodePreviouslyVisited = FALSE;
161 
162     while (Op)
163     {
164         if (NodePreviouslyVisited)
165         {
166             if (AscendingCallback)
167             {
168                 Status = AscendingCallback (Op, Info->Level, Context);
169                 if (ACPI_FAILURE (Status))
170                 {
171                     return;
172                 }
173             }
174         }
175         else
176         {
177             /* Let the callback process the node */
178 
179             Status = DescendingCallback (Op, Info->Level, Context);
180             if (ACPI_SUCCESS (Status))
181             {
182                 /* Visit children first, once */
183 
184                 Next = AcpiPsGetArg (Op, 0);
185                 if (Next)
186                 {
187                     Info->Level++;
188                     Op = Next;
189                     continue;
190                 }
191             }
192             else if (Status != AE_CTRL_DEPTH)
193             {
194                 /* Exit immediately on any error */
195 
196                 return;
197             }
198         }
199 
200         /* Terminate walk at start op */
201 
202         if (Op == StartOp)
203         {
204             break;
205         }
206 
207         /* No more children, re-visit this node */
208 
209         if (!NodePreviouslyVisited)
210         {
211             NodePreviouslyVisited = TRUE;
212             continue;
213         }
214 
215         /* No more children, visit peers */
216 
217         if (Op->Common.Next)
218         {
219             Op = Op->Common.Next;
220             NodePreviouslyVisited = FALSE;
221         }
222         else
223         {
224             /* No peers, re-visit parent */
225 
226             if (Info->Level != 0 )
227             {
228                 Info->Level--;
229             }
230 
231             Op = Op->Common.Parent;
232             NodePreviouslyVisited = TRUE;
233         }
234     }
235 
236     /* If we get here, the walk completed with no errors */
237 
238     return;
239 }
240 
241 
242 /*******************************************************************************
243  *
244  * FUNCTION:    AcpiDmBlockType
245  *
246  * PARAMETERS:  Op              - Object to be examined
247  *
248  * RETURN:      BlockType - not a block, parens, braces, or even both.
249  *
250  * DESCRIPTION: Type of block for this op (parens or braces)
251  *
252  ******************************************************************************/
253 
254 UINT32
AcpiDmBlockType(ACPI_PARSE_OBJECT * Op)255 AcpiDmBlockType (
256     ACPI_PARSE_OBJECT       *Op)
257 {
258     const ACPI_OPCODE_INFO  *OpInfo;
259 
260 
261     if (!Op)
262     {
263         return (BLOCK_NONE);
264     }
265 
266     switch (Op->Common.AmlOpcode)
267     {
268     case AML_ELSE_OP:
269 
270         return (BLOCK_BRACE);
271 
272     case AML_METHOD_OP:
273     case AML_DEVICE_OP:
274     case AML_SCOPE_OP:
275     case AML_PROCESSOR_OP:
276     case AML_POWER_RESOURCE_OP:
277     case AML_THERMAL_ZONE_OP:
278     case AML_IF_OP:
279     case AML_WHILE_OP:
280     case AML_FIELD_OP:
281     case AML_INDEX_FIELD_OP:
282     case AML_BANK_FIELD_OP:
283 
284         return (BLOCK_PAREN | BLOCK_BRACE);
285 
286     case AML_BUFFER_OP:
287 
288         if ((Op->Common.DisasmOpcode == ACPI_DASM_UNICODE) ||
289             (Op->Common.DisasmOpcode == ACPI_DASM_UUID) ||
290             (Op->Common.DisasmOpcode == ACPI_DASM_PLD_METHOD))
291         {
292             return (BLOCK_NONE);
293         }
294 
295         ACPI_FALLTHROUGH;
296 
297     case AML_PACKAGE_OP:
298     case AML_VARIABLE_PACKAGE_OP:
299 
300         return (BLOCK_PAREN | BLOCK_BRACE);
301 
302     case AML_EVENT_OP:
303 
304         return (BLOCK_PAREN);
305 
306     case AML_INT_METHODCALL_OP:
307 
308         if (Op->Common.Parent &&
309             ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
310              (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP)))
311         {
312             /* This is a reference to a method, not an invocation */
313 
314             return (BLOCK_NONE);
315         }
316 
317         ACPI_FALLTHROUGH;
318 
319     default:
320 
321         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
322         if (OpInfo->Flags & AML_HAS_ARGS)
323         {
324             return (BLOCK_PAREN);
325         }
326 
327         return (BLOCK_NONE);
328     }
329 }
330 
331 
332 /*******************************************************************************
333  *
334  * FUNCTION:    AcpiDmListType
335  *
336  * PARAMETERS:  Op              - Object to be examined
337  *
338  * RETURN:      ListType - has commas or not.
339  *
340  * DESCRIPTION: Type of block for this op (parens or braces)
341  *
342  ******************************************************************************/
343 
344 UINT32
AcpiDmListType(ACPI_PARSE_OBJECT * Op)345 AcpiDmListType (
346     ACPI_PARSE_OBJECT       *Op)
347 {
348     const ACPI_OPCODE_INFO  *OpInfo;
349 
350 
351     if (!Op)
352     {
353         return (BLOCK_NONE);
354     }
355 
356     switch (Op->Common.AmlOpcode)
357     {
358 
359     case AML_ELSE_OP:
360     case AML_METHOD_OP:
361     case AML_DEVICE_OP:
362     case AML_SCOPE_OP:
363     case AML_POWER_RESOURCE_OP:
364     case AML_PROCESSOR_OP:
365     case AML_THERMAL_ZONE_OP:
366     case AML_IF_OP:
367     case AML_WHILE_OP:
368     case AML_FIELD_OP:
369     case AML_INDEX_FIELD_OP:
370     case AML_BANK_FIELD_OP:
371 
372         return (BLOCK_NONE);
373 
374     case AML_BUFFER_OP:
375     case AML_PACKAGE_OP:
376     case AML_VARIABLE_PACKAGE_OP:
377 
378         return (BLOCK_COMMA_LIST);
379 
380     default:
381 
382         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
383         if (OpInfo->Flags & AML_HAS_ARGS)
384         {
385             return (BLOCK_COMMA_LIST);
386         }
387 
388         return (BLOCK_NONE);
389     }
390 }
391 
392 
393 /*******************************************************************************
394  *
395  * FUNCTION:    AcpiDmDescendingOp
396  *
397  * PARAMETERS:  ASL_WALK_CALLBACK
398  *
399  * RETURN:      Status
400  *
401  * DESCRIPTION: First visitation of a parse object during tree descent.
402  *              Decode opcode name and begin parameter list(s), if any.
403  *
404  ******************************************************************************/
405 
406 static ACPI_STATUS
AcpiDmDescendingOp(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)407 AcpiDmDescendingOp (
408     ACPI_PARSE_OBJECT       *Op,
409     UINT32                  Level,
410     void                    *Context)
411 {
412     ACPI_OP_WALK_INFO       *Info = Context;
413     const ACPI_OPCODE_INFO  *OpInfo;
414     UINT32                  Name;
415     ACPI_PARSE_OBJECT       *NextOp;
416     ACPI_PARSE_OBJECT       *NextOp2;
417     UINT32                  AmlOffset;
418 
419 
420     /* Determine which file this parse node is contained in. */
421 
422     if (AcpiGbl_CaptureComments)
423     {
424         ASL_CV_LABEL_FILENODE (Op);
425 
426         if (Level != 0 && ASL_CV_FILE_HAS_SWITCHED (Op))
427         {
428             ASL_CV_SWITCH_FILES (Level, Op);
429         }
430 
431         /* If this parse node has regular comments, print them here. */
432 
433         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_STANDARD, NULL, Level);
434     }
435 
436     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
437 
438     /* Listing support to dump the AML code after the ASL statement */
439 
440     if (AcpiGbl_DmOpt_Listing)
441     {
442         /* We only care about these classes of objects */
443 
444         if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) ||
445             (OpInfo->Class == AML_CLASS_CONTROL) ||
446             (OpInfo->Class == AML_CLASS_CREATE) ||
447             ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Op->Common.Next)))
448         {
449             if (AcpiGbl_DmOpt_Listing && Info->PreviousAml)
450             {
451                 /* Dump the AML byte code for the previous Op */
452 
453                 if (Op->Common.Aml > Info->PreviousAml)
454                 {
455                     AcpiOsPrintf ("\n");
456                     AcpiUtDumpBuffer (
457                         (Info->StartAml + Info->AmlOffset),
458                         (Op->Common.Aml - Info->PreviousAml),
459                         DB_BYTE_DISPLAY, Info->AmlOffset);
460                     AcpiOsPrintf ("\n");
461                 }
462 
463                 Info->AmlOffset = (Op->Common.Aml - Info->StartAml);
464             }
465 
466             Info->PreviousAml = Op->Common.Aml;
467         }
468     }
469 
470     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
471     {
472         /* Ignore this op -- it was handled elsewhere */
473 
474         return (AE_CTRL_DEPTH);
475     }
476 
477     if (Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
478     {
479         /* Ignore this op, but not it's children */
480 
481         return (AE_OK);
482     }
483 
484     if (Op->Common.AmlOpcode == AML_IF_OP)
485     {
486         NextOp = AcpiPsGetDepthNext (NULL, Op);
487         if (NextOp)
488         {
489             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
490 
491             /* Don't emit the actual embedded externals unless asked */
492 
493             if (!AcpiGbl_DmEmitExternalOpcodes)
494             {
495                 /*
496                  * A Zero predicate indicates the possibility of one or more
497                  * External() opcodes within the If() block.
498                  */
499                 if (NextOp->Common.AmlOpcode == AML_ZERO_OP)
500                 {
501                     NextOp2 = NextOp->Common.Next;
502 
503                     if (NextOp2 &&
504                         (NextOp2->Common.AmlOpcode == AML_EXTERNAL_OP))
505                     {
506                         /* Ignore the If 0 block and all children */
507 
508                         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
509                         return (AE_CTRL_DEPTH);
510                     }
511                 }
512             }
513         }
514     }
515 
516     /* Level 0 is at the Definition Block level */
517 
518     if (Level == 0)
519     {
520         /* In verbose mode, print the AML offset, opcode and depth count */
521 
522         if (Info->WalkState)
523         {
524             AmlOffset = (UINT32) ACPI_PTR_DIFF (Op->Common.Aml,
525                 Info->WalkState->ParserState.AmlStart);
526             if (AcpiGbl_DmOpt_Verbose)
527             {
528                 if (AcpiGbl_CmSingleStep)
529                 {
530                     AcpiOsPrintf ("%5.5X/%4.4X: ",
531                         AmlOffset, (UINT32) Op->Common.AmlOpcode);
532                 }
533                 else
534                 {
535                     AcpiOsPrintf ("AML Offset %5.5X, Opcode %4.4X: ",
536                         AmlOffset, (UINT32) Op->Common.AmlOpcode);
537                 }
538             }
539         }
540 
541         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
542         {
543             /* This is the beginning of the Definition Block */
544 
545             AcpiOsPrintf ("{\n");
546 
547             /* Emit all External() declarations here */
548 
549             if (!AcpiGbl_DmEmitExternalOpcodes)
550             {
551                 AcpiDmEmitExternals ();
552             }
553 
554             return (AE_OK);
555         }
556     }
557     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
558          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
559          (!(Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)) &&
560          (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
561     {
562         /*
563          * This is a first-level element of a term list,
564          * indent a new line
565          */
566         switch (Op->Common.AmlOpcode)
567         {
568         case AML_NOOP_OP:
569             /*
570              * Optionally just ignore this opcode. Some tables use
571              * NoOp opcodes for "padding" out packages that the BIOS
572              * changes dynamically. This can leave hundreds or
573              * thousands of NoOp opcodes that if disassembled,
574              * cannot be compiled because they are syntactically
575              * incorrect.
576              */
577             if (AcpiGbl_IgnoreNoopOperator)
578             {
579                 Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
580                 return (AE_OK);
581             }
582 
583             ACPI_FALLTHROUGH;
584 
585         default:
586 
587             AcpiDmIndent (Level);
588             break;
589         }
590 
591         Info->LastLevel = Level;
592         Info->Count = 0;
593     }
594 
595     /*
596      * This is an inexpensive mechanism to try and keep lines from getting
597      * too long. When the limit is hit, start a new line at the previous
598      * indent plus one. A better but more expensive mechanism would be to
599      * keep track of the current column.
600      */
601     Info->Count++;
602     if (Info->Count /* +Info->LastLevel */ > 12)
603     {
604         Info->Count = 0;
605         AcpiOsPrintf ("\n");
606         AcpiDmIndent (Info->LastLevel + 1);
607     }
608 
609     /* If ASL+ is enabled, check for a C-style operator */
610 
611     if (AcpiDmCheckForSymbolicOpcode (Op, Info))
612     {
613         return (AE_OK);
614     }
615 
616     /* Print the opcode name */
617 
618     AcpiDmDisassembleOneOp (NULL, Info, Op);
619 
620     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
621         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
622     {
623         return (AE_OK);
624     }
625 
626     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
627         (Op->Common.AmlOpcode == AML_RETURN_OP))
628     {
629         Info->Level--;
630     }
631 
632     if (Op->Common.AmlOpcode == AML_EXTERNAL_OP)
633     {
634         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
635         return (AE_CTRL_DEPTH);
636     }
637 
638     /* Start the opcode argument list if necessary */
639 
640     if ((OpInfo->Flags & AML_HAS_ARGS) ||
641         (Op->Common.AmlOpcode == AML_EVENT_OP))
642     {
643         /* This opcode has an argument list */
644 
645         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
646         {
647             AcpiOsPrintf (" (");
648             if (!(AcpiDmBlockType (Op) & BLOCK_BRACE))
649             {
650                 ASL_CV_PRINT_ONE_COMMENT (Op, AMLCOMMENT_INLINE, " ", 0);
651             }
652         }
653 
654         /* If this is a named opcode, print the associated name value */
655 
656         if (OpInfo->Flags & AML_NAMED)
657         {
658             switch (Op->Common.AmlOpcode)
659             {
660             case AML_ALIAS_OP:
661 
662                 NextOp = AcpiPsGetDepthNext (NULL, Op);
663                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
664                 AcpiDmNamestring (NextOp->Common.Value.Name);
665                 AcpiOsPrintf (", ");
666 
667                 ACPI_FALLTHROUGH;
668 
669             default:
670 
671                 Name = AcpiPsGetName (Op);
672                 if (Op->Named.Path)
673                 {
674                     AcpiDmNamestring (Op->Named.Path);
675                 }
676                 else
677                 {
678                     AcpiDmDumpName (Name);
679                 }
680 
681                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
682                 {
683                     if (AcpiGbl_DmOpt_Verbose)
684                     {
685                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
686                     }
687                 }
688                 break;
689             }
690 
691             switch (Op->Common.AmlOpcode)
692             {
693             case AML_METHOD_OP:
694 
695                 AcpiDmMethodFlags (Op);
696                 ASL_CV_CLOSE_PAREN (Op, Level);
697 
698                 /* Emit description comment for Method() with a predefined ACPI name */
699 
700                 AcpiDmPredefinedDescription (Op);
701                 break;
702 
703             case AML_NAME_OP:
704 
705                 /* Check for _HID and related EISAID() */
706 
707                 AcpiDmCheckForHardwareId (Op);
708                 AcpiOsPrintf (", ");
709                 ASL_CV_PRINT_ONE_COMMENT (Op, AML_NAMECOMMENT, NULL, 0);
710                 break;
711 
712             case AML_REGION_OP:
713 
714                 AcpiDmRegionFlags (Op);
715                 break;
716 
717             case AML_POWER_RESOURCE_OP:
718 
719                 /* Mark the next two Ops as part of the parameter list */
720 
721                 AcpiOsPrintf (", ");
722                 NextOp = AcpiPsGetDepthNext (NULL, Op);
723                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
724 
725                 NextOp = NextOp->Common.Next;
726                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
727                 return (AE_OK);
728 
729             case AML_PROCESSOR_OP:
730 
731                 /* Mark the next three Ops as part of the parameter list */
732 
733                 AcpiOsPrintf (", ");
734                 NextOp = AcpiPsGetDepthNext (NULL, Op);
735                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
736 
737                 NextOp = NextOp->Common.Next;
738                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
739 
740                 NextOp = NextOp->Common.Next;
741                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
742                 return (AE_OK);
743 
744             case AML_MUTEX_OP:
745             case AML_DATA_REGION_OP:
746 
747                 AcpiOsPrintf (", ");
748                 return (AE_OK);
749 
750             case AML_EVENT_OP:
751             case AML_ALIAS_OP:
752 
753                 return (AE_OK);
754 
755             case AML_SCOPE_OP:
756             case AML_DEVICE_OP:
757             case AML_THERMAL_ZONE_OP:
758 
759                 ASL_CV_CLOSE_PAREN (Op, Level);
760                 break;
761 
762             default:
763 
764                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
765                     Op->Common.AmlOpcode);
766                 break;
767             }
768         }
769 
770         else switch (Op->Common.AmlOpcode)
771         {
772         case AML_FIELD_OP:
773         case AML_BANK_FIELD_OP:
774         case AML_INDEX_FIELD_OP:
775 
776             Info->BitOffset = 0;
777 
778             /* Name of the parent OperationRegion */
779 
780             NextOp = AcpiPsGetDepthNext (NULL, Op);
781             AcpiDmNamestring (NextOp->Common.Value.Name);
782             AcpiOsPrintf (", ");
783             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
784 
785             switch (Op->Common.AmlOpcode)
786             {
787             case AML_BANK_FIELD_OP:
788 
789                 /* Namestring - Bank Name */
790 
791                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
792                 AcpiDmNamestring (NextOp->Common.Value.Name);
793                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
794                 AcpiOsPrintf (", ");
795 
796                 /*
797                  * Bank Value. This is a TermArg in the middle of the parameter
798                  * list, must handle it here.
799                  *
800                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMETER_LIST
801                  * eliminates newline in the output.
802                  */
803                 NextOp = NextOp->Common.Next;
804 
805                 Info->Flags = ACPI_PARSEOP_PARAMETER_LIST;
806                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
807                     AcpiDmAscendingOp, Info);
808                 Info->Flags = 0;
809                 Info->Level = Level;
810 
811                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
812                 AcpiOsPrintf (", ");
813                 break;
814 
815             case AML_INDEX_FIELD_OP:
816 
817                 /* Namestring - Data Name */
818 
819                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
820                 AcpiDmNamestring (NextOp->Common.Value.Name);
821                 AcpiOsPrintf (", ");
822                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
823                 break;
824 
825             default:
826 
827                 break;
828             }
829 
830             AcpiDmFieldFlags (NextOp);
831             break;
832 
833         case AML_BUFFER_OP:
834 
835             /* The next op is the size parameter */
836 
837             NextOp = AcpiPsGetDepthNext (NULL, Op);
838             if (!NextOp)
839             {
840                 /* Single-step support */
841 
842                 return (AE_OK);
843             }
844 
845             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
846             {
847                 /*
848                  * We have a resource list. Don't need to output
849                  * the buffer size Op. Open up a new block
850                  */
851                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
852                 ASL_CV_CLOSE_PAREN (Op, Level);
853 
854                 if (Op->Asl.Parent->Common.AmlOpcode == AML_NAME_OP)
855                 {
856                     /*
857                      * Emit description comment showing the full ACPI name
858                      * of the ResourceTemplate only if it was defined using a
859                      * Name statement.
860                      */
861                      AcpiDmPredefinedDescription (Op->Asl.Parent);
862                 }
863 
864                 AcpiDmPredefinedDescription (Op->Asl.Parent);
865 
866                 AcpiOsPrintf ("\n");
867                 AcpiDmIndent (Info->Level);
868                 AcpiOsPrintf ("{\n");
869                 return (AE_OK);
870             }
871 
872             /* Normal Buffer, mark size as in the parameter list */
873 
874             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
875             return (AE_OK);
876 
877         case AML_IF_OP:
878         case AML_VARIABLE_PACKAGE_OP:
879         case AML_WHILE_OP:
880 
881             /* The next op is the size or predicate parameter */
882 
883             NextOp = AcpiPsGetDepthNext (NULL, Op);
884             if (NextOp)
885             {
886                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
887             }
888             return (AE_OK);
889 
890         case AML_PACKAGE_OP:
891 
892             /* The next op is the size parameter */
893 
894             NextOp = AcpiPsGetDepthNext (NULL, Op);
895             if (NextOp)
896             {
897                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
898             }
899             return (AE_OK);
900 
901         case AML_MATCH_OP:
902 
903             AcpiDmMatchOp (Op);
904             break;
905 
906         default:
907 
908             break;
909         }
910 
911         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
912         {
913             AcpiOsPrintf ("\n");
914             AcpiDmIndent (Level);
915             AcpiOsPrintf ("{\n");
916         }
917     }
918 
919     return (AE_OK);
920 }
921 
922 
923 /*******************************************************************************
924  *
925  * FUNCTION:    AcpiDmAscendingOp
926  *
927  * PARAMETERS:  ASL_WALK_CALLBACK
928  *
929  * RETURN:      Status
930  *
931  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
932  *              tree. Close out any parameter lists and complete the opcode.
933  *
934  ******************************************************************************/
935 
936 static ACPI_STATUS
AcpiDmAscendingOp(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)937 AcpiDmAscendingOp (
938     ACPI_PARSE_OBJECT       *Op,
939     UINT32                  Level,
940     void                    *Context)
941 {
942     ACPI_OP_WALK_INFO       *Info = Context;
943     ACPI_PARSE_OBJECT       *ParentOp;
944 
945 
946     /* Point the Op's filename pointer to the proper file */
947 
948     if (AcpiGbl_CaptureComments)
949     {
950         ASL_CV_LABEL_FILENODE (Op);
951 
952         /* Switch the output of these files if necessary */
953 
954         if (ASL_CV_FILE_HAS_SWITCHED (Op))
955         {
956             ASL_CV_SWITCH_FILES (Level, Op);
957         }
958     }
959 
960     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE ||
961         Op->Common.DisasmOpcode == ACPI_DASM_IGNORE_SINGLE)
962     {
963         /* Ignore this op -- it was handled elsewhere */
964 
965         return (AE_OK);
966     }
967 
968     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
969     {
970         /* Indicates the end of the current descriptor block (table) */
971 
972         ASL_CV_CLOSE_BRACE (Op, Level);
973 
974         /* Print any comments that are at the end of the file here */
975 
976         if (AcpiGbl_CaptureComments && AcpiGbl_LastListHead)
977         {
978             AcpiOsPrintf ("\n");
979             ASL_CV_PRINT_ONE_COMMENT_LIST (AcpiGbl_LastListHead, 0);
980         }
981         AcpiOsPrintf ("\n\n");
982 
983         return (AE_OK);
984     }
985 
986     switch (AcpiDmBlockType (Op))
987     {
988     case BLOCK_PAREN:
989 
990         /* Completed an op that has arguments, add closing paren if needed */
991 
992         AcpiDmCloseOperator (Op);
993 
994         if (Op->Common.AmlOpcode == AML_NAME_OP)
995         {
996             /* Emit description comment for Name() with a predefined ACPI name */
997 
998             AcpiDmPredefinedDescription (Op);
999         }
1000         else
1001         {
1002             /* For Create* operators, attempt to emit resource tag description */
1003 
1004             AcpiDmFieldPredefinedDescription (Op);
1005         }
1006 
1007         /* Decode Notify() values */
1008 
1009         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
1010         {
1011             AcpiDmNotifyDescription (Op);
1012         }
1013 
1014         AcpiDmDisplayTargetPathname (Op);
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                 if (!(Info->Flags & ACPI_PARSEOP_PARAMETER_LIST))
1029                 {
1030                     AcpiOsPrintf ("\n");
1031                 }
1032             }
1033         }
1034         break;
1035 
1036     case BLOCK_BRACE:
1037     case (BLOCK_BRACE | BLOCK_PAREN):
1038 
1039         /* Completed an op that has a term list, add closing brace */
1040 
1041         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
1042         {
1043             ASL_CV_CLOSE_BRACE (Op, Level);
1044         }
1045         else
1046         {
1047             AcpiDmIndent (Level);
1048             ASL_CV_CLOSE_BRACE (Op, Level);
1049         }
1050 
1051         AcpiDmCommaIfListMember (Op);
1052 
1053         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
1054         {
1055             AcpiOsPrintf ("\n");
1056             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
1057             {
1058                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
1059                     (Op->Common.Next) &&
1060                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
1061                 {
1062                     break;
1063                 }
1064 
1065                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1066                     (!Op->Common.Next))
1067                 {
1068                     break;
1069                 }
1070                 AcpiOsPrintf ("\n");
1071             }
1072         }
1073         break;
1074 
1075     case BLOCK_NONE:
1076     default:
1077 
1078         /* Could be a nested operator, check if comma required */
1079 
1080         if (!AcpiDmCommaIfListMember (Op))
1081         {
1082             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
1083                  (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)) &&
1084                  (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
1085             {
1086                 /*
1087                  * This is a first-level element of a term list
1088                  * start a new line
1089                  */
1090                 AcpiOsPrintf ("\n");
1091             }
1092         }
1093         else if (Op->Common.Parent)
1094         {
1095             switch (Op->Common.Parent->Common.AmlOpcode)
1096             {
1097             case AML_PACKAGE_OP:
1098             case AML_VARIABLE_PACKAGE_OP:
1099 
1100                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1101                 {
1102                     AcpiOsPrintf ("\n");
1103                 }
1104                 break;
1105 
1106             default:
1107 
1108                 break;
1109             }
1110         }
1111         break;
1112     }
1113 
1114     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST)
1115     {
1116         if ((Op->Common.Next) &&
1117             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMETER_LIST))
1118         {
1119             return (AE_OK);
1120         }
1121 
1122         /*
1123          * The parent Op is guaranteed to be valid because of the flag
1124          * ACPI_PARSEOP_PARAMETER_LIST -- which means that this op is part of
1125          * a parameter list and thus has a valid parent.
1126          */
1127         ParentOp = Op->Common.Parent;
1128 
1129         /*
1130          * Just completed a parameter node for something like "Buffer (param)".
1131          * Close the paren and open up the term list block with a brace.
1132          *
1133          * Switch predicates don't have a Next node but require a closing paren
1134          * and opening brace.
1135          */
1136         if (Op->Common.Next || Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1137         {
1138             ASL_CV_CLOSE_PAREN (Op, Level);
1139 
1140             /*
1141              * Emit a description comment for a Name() operator that is a
1142              * predefined ACPI name. Must check the grandparent.
1143              */
1144             ParentOp = ParentOp->Common.Parent;
1145             if (ParentOp &&
1146                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
1147             {
1148                 AcpiDmPredefinedDescription (ParentOp);
1149             }
1150 
1151             /* Correct the indentation level for Switch and Case predicates */
1152 
1153             if (Op->Common.DisasmOpcode == ACPI_DASM_SWITCH_PREDICATE)
1154             {
1155                 --Level;
1156             }
1157 
1158             AcpiOsPrintf ("\n");
1159             AcpiDmIndent (Level - 1);
1160             AcpiOsPrintf ("{\n");
1161         }
1162         else
1163         {
1164             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
1165             ASL_CV_CLOSE_PAREN (Op, Level);
1166             AcpiOsPrintf ("{");
1167         }
1168     }
1169 
1170     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
1171         (Op->Common.AmlOpcode == AML_RETURN_OP))
1172     {
1173         Info->Level++;
1174     }
1175 
1176     /*
1177      * For ASL+, check for and emit a C-style symbol. If valid, the
1178      * symbol string has been deferred until after the first operand
1179      */
1180     if (AcpiGbl_CstyleDisassembly)
1181     {
1182         if (Op->Asl.OperatorSymbol)
1183         {
1184             AcpiOsPrintf ("%s", Op->Asl.OperatorSymbol);
1185             Op->Asl.OperatorSymbol = NULL;
1186         }
1187     }
1188 
1189     return (AE_OK);
1190 }
1191