adwalk.c revision 1.1.1.11.2.2 1 /******************************************************************************
2 *
3 * Module Name: adwalk - Application-level disassembler parse tree walk routines
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2020, 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 "acdisasm.h"
49 #include "acdispat.h"
50 #include "acnamesp.h"
51 #include "acapps.h"
52
53
54 #define _COMPONENT ACPI_TOOLS
55 ACPI_MODULE_NAME ("adwalk")
56
57 /*
58 * aslmap - opcode mappings and reserved method names
59 */
60 ACPI_OBJECT_TYPE
61 AslMapNamedOpcodeToDataType (
62 UINT16 Opcode);
63
64 /* Local prototypes */
65
66 static ACPI_STATUS
67 AcpiDmFindOrphanDescending (
68 ACPI_PARSE_OBJECT *Op,
69 UINT32 Level,
70 void *Context);
71
72 static ACPI_STATUS
73 AcpiDmDumpDescending (
74 ACPI_PARSE_OBJECT *Op,
75 UINT32 Level,
76 void *Context);
77
78 static ACPI_STATUS
79 AcpiDmXrefDescendingOp (
80 ACPI_PARSE_OBJECT *Op,
81 UINT32 Level,
82 void *Context);
83
84 static ACPI_STATUS
85 AcpiDmCommonAscendingOp (
86 ACPI_PARSE_OBJECT *Op,
87 UINT32 Level,
88 void *Context);
89
90 static ACPI_STATUS
91 AcpiDmLoadDescendingOp (
92 ACPI_PARSE_OBJECT *Op,
93 UINT32 Level,
94 void *Context);
95
96 static UINT32
97 AcpiDmInspectPossibleArgs (
98 UINT32 CurrentOpArgCount,
99 UINT32 TargetCount,
100 ACPI_PARSE_OBJECT *Op);
101
102 static ACPI_STATUS
103 AcpiDmCommonDescendingOp (
104 ACPI_PARSE_OBJECT *Op,
105 UINT32 Level,
106 void *Context);
107
108 static ACPI_STATUS
109 AcpiDmProcessResourceDescriptors (
110 ACPI_PARSE_OBJECT *Op,
111 UINT32 Level,
112 void *Context);
113
114 /*******************************************************************************
115 *
116 * FUNCTION: AcpiDmDumpTree
117 *
118 * PARAMETERS: Origin - Starting object
119 *
120 * RETURN: None
121 *
122 * DESCRIPTION: Parse tree walk to format and output the nodes
123 *
124 ******************************************************************************/
125
126 void
127 AcpiDmDumpTree (
128 ACPI_PARSE_OBJECT *Origin)
129 {
130 ACPI_OP_WALK_INFO Info;
131
132
133 if (!Origin)
134 {
135 return;
136 }
137
138 AcpiOsPrintf ("/*\nAML Parse Tree\n\n");
139 Info.Flags = 0;
140 Info.Count = 0;
141 Info.Level = 0;
142 Info.WalkState = NULL;
143
144 AcpiDmWalkParseTree (Origin, AcpiDmDumpDescending, NULL, &Info);
145 AcpiOsPrintf ("*/\n\n");
146 }
147
148
149 /*******************************************************************************
150 *
151 * FUNCTION: AcpiDmFindOrphanMethods
152 *
153 * PARAMETERS: Origin - Starting object
154 *
155 * RETURN: None
156 *
157 * DESCRIPTION: Parse tree walk to find "orphaned" method invocations -- methods
158 * that are not resolved in the namespace
159 *
160 ******************************************************************************/
161
162 void
163 AcpiDmFindOrphanMethods (
164 ACPI_PARSE_OBJECT *Origin)
165 {
166 ACPI_OP_WALK_INFO Info;
167
168
169 if (!Origin)
170 {
171 return;
172 }
173
174 Info.Flags = 0;
175 Info.Level = 0;
176 Info.WalkState = NULL;
177
178 AcpiDmWalkParseTree (Origin, AcpiDmFindOrphanDescending, NULL, &Info);
179 }
180
181
182 /*******************************************************************************
183 *
184 * FUNCTION: AcpiDmFinishNamespaceLoad
185 *
186 * PARAMETERS: ParseTreeRoot - Root of the parse tree
187 * NamespaceRoot - Root of the internal namespace
188 * OwnerId - OwnerId of the table to be disassembled
189 *
190 * RETURN: None
191 *
192 * DESCRIPTION: Load all namespace items that are created within control
193 * methods. Used before namespace cross reference
194 *
195 ******************************************************************************/
196
197 void
198 AcpiDmFinishNamespaceLoad (
199 ACPI_PARSE_OBJECT *ParseTreeRoot,
200 ACPI_NAMESPACE_NODE *NamespaceRoot,
201 ACPI_OWNER_ID OwnerId)
202 {
203 ACPI_STATUS Status;
204 ACPI_OP_WALK_INFO Info;
205 ACPI_WALK_STATE *WalkState;
206
207
208 if (!ParseTreeRoot)
209 {
210 return;
211 }
212
213 /* Create and initialize a new walk state */
214
215 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL);
216 if (!WalkState)
217 {
218 return;
219 }
220
221 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type,
222 WalkState);
223 if (ACPI_FAILURE (Status))
224 {
225 return;
226 }
227
228 Info.Flags = 0;
229 Info.Level = 0;
230 Info.WalkState = WalkState;
231
232 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmLoadDescendingOp,
233 AcpiDmCommonAscendingOp, &Info);
234 ACPI_FREE (WalkState);
235 }
236
237
238 /*******************************************************************************
239 *
240 * FUNCTION: AcpiDmCrossReferenceNamespace
241 *
242 * PARAMETERS: ParseTreeRoot - Root of the parse tree
243 * NamespaceRoot - Root of the internal namespace
244 * OwnerId - OwnerId of the table to be disassembled
245 *
246 * RETURN: None
247 *
248 * DESCRIPTION: Cross reference the namespace to create externals
249 *
250 ******************************************************************************/
251
252 void
253 AcpiDmCrossReferenceNamespace (
254 ACPI_PARSE_OBJECT *ParseTreeRoot,
255 ACPI_NAMESPACE_NODE *NamespaceRoot,
256 ACPI_OWNER_ID OwnerId)
257 {
258 ACPI_STATUS Status;
259 ACPI_OP_WALK_INFO Info;
260 ACPI_WALK_STATE *WalkState;
261
262
263 if (!ParseTreeRoot)
264 {
265 return;
266 }
267
268 /* Create and initialize a new walk state */
269
270 WalkState = AcpiDsCreateWalkState (OwnerId, ParseTreeRoot, NULL, NULL);
271 if (!WalkState)
272 {
273 return;
274 }
275
276 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type,
277 WalkState);
278 if (ACPI_FAILURE (Status))
279 {
280 return;
281 }
282
283 Info.Flags = 0;
284 Info.Level = 0;
285 Info.WalkState = WalkState;
286
287 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmXrefDescendingOp,
288 AcpiDmCommonAscendingOp, &Info);
289 ACPI_FREE (WalkState);
290 }
291
292
293 /*******************************************************************************
294 *
295 * FUNCTION: AcpiDmConvertParseObjects
296 *
297 * PARAMETERS: ParseTreeRoot - Root of the parse tree
298 * NamespaceRoot - Root of the internal namespace
299 *
300 * RETURN: None
301 *
302 * DESCRIPTION: Begin parse tree walk to perform conversions needed for
303 * disassembly. These include resource descriptors and switch/case
304 * operations.
305 *
306 ******************************************************************************/
307
308 void
309 AcpiDmConvertParseObjects (
310 ACPI_PARSE_OBJECT *ParseTreeRoot,
311 ACPI_NAMESPACE_NODE *NamespaceRoot)
312 {
313 ACPI_STATUS Status;
314 ACPI_OP_WALK_INFO Info;
315 ACPI_WALK_STATE *WalkState;
316
317
318 if (!ParseTreeRoot)
319 {
320 return;
321 }
322
323 /* Create and initialize a new walk state */
324
325 WalkState = AcpiDsCreateWalkState (0, ParseTreeRoot, NULL, NULL);
326 if (!WalkState)
327 {
328 return;
329 }
330
331 Status = AcpiDsScopeStackPush (NamespaceRoot, NamespaceRoot->Type,
332 WalkState);
333 if (ACPI_FAILURE (Status))
334 {
335 ACPI_FREE (WalkState);
336 return;
337 }
338
339 Info.Flags = 0;
340 Info.Level = 0;
341 Info.WalkState = WalkState;
342
343 AcpiDmWalkParseTree (ParseTreeRoot, AcpiDmCommonDescendingOp,
344 AcpiDmCommonAscendingOp, &Info);
345 ACPI_FREE (WalkState);
346
347 if (AcpiGbl_TempListHead) {
348 AcpiDmClearTempList();
349 }
350
351 return;
352 }
353
354
355 /*******************************************************************************
356 *
357 * FUNCTION: AcpiDmDumpDescending
358 *
359 * PARAMETERS: ASL_WALK_CALLBACK
360 *
361 * RETURN: Status
362 *
363 * DESCRIPTION: Format and print contents of one parse Op.
364 *
365 ******************************************************************************/
366
367 static ACPI_STATUS
368 AcpiDmDumpDescending (
369 ACPI_PARSE_OBJECT *Op,
370 UINT32 Level,
371 void *Context)
372 {
373 ACPI_OP_WALK_INFO *Info = Context;
374 char *Path;
375
376
377 if (!Op)
378 {
379 return (AE_OK);
380 }
381
382 /* Most of the information (count, level, name) here */
383
384 Info->Count++;
385 AcpiOsPrintf ("% 5d [%2.2d] ", Info->Count, Level);
386 AcpiDmIndent (Level);
387 AcpiOsPrintf ("%-28s", AcpiPsGetOpcodeName (Op->Common.AmlOpcode));
388
389 /* Extra info is helpful */
390
391 switch (Op->Common.AmlOpcode)
392 {
393 case AML_BYTE_OP:
394
395 AcpiOsPrintf ("%2.2X", (UINT32) Op->Common.Value.Integer);
396 break;
397
398 case AML_WORD_OP:
399
400 AcpiOsPrintf ("%4.4X", (UINT32) Op->Common.Value.Integer);
401 break;
402
403 case AML_DWORD_OP:
404
405 AcpiOsPrintf ("%8.8X", (UINT32) Op->Common.Value.Integer);
406 break;
407
408 case AML_QWORD_OP:
409
410 AcpiOsPrintf ("%8.8X%8.8X", ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
411 break;
412
413 case AML_INT_NAMEPATH_OP:
414
415 if (Op->Common.Value.String)
416 {
417 AcpiNsExternalizeName (ACPI_UINT32_MAX, Op->Common.Value.String,
418 NULL, &Path);
419 AcpiOsPrintf ("%s %p", Path, Op->Common.Node);
420 ACPI_FREE (Path);
421 }
422 else
423 {
424 AcpiOsPrintf ("[NULL]");
425 }
426 break;
427
428 case AML_NAME_OP:
429 case AML_METHOD_OP:
430 case AML_DEVICE_OP:
431
432 AcpiOsPrintf ("%4.4s",
433 ACPI_CAST_PTR (char, &Op->Named.Name));
434 break;
435
436 case AML_INT_NAMEDFIELD_OP:
437
438 AcpiOsPrintf ("%4.4s Length: (bits) %8.8X%8.8X (bytes) %8.8X%8.8X",
439 ACPI_CAST_PTR (char, &Op->Named.Name),
440 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer),
441 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer / 8));
442 break;
443
444
445 default:
446
447 break;
448 }
449
450 AcpiOsPrintf ("\n");
451 return (AE_OK);
452 }
453
454
455 /*******************************************************************************
456 *
457 * FUNCTION: AcpiDmFindOrphanDescending
458 *
459 * PARAMETERS: ASL_WALK_CALLBACK
460 *
461 * RETURN: Status
462 *
463 * DESCRIPTION: Check namepath Ops for orphaned method invocations
464 *
465 * Note: Parts of this are experimental, under possible further development.
466 *
467 ******************************************************************************/
468
469 static ACPI_STATUS
470 AcpiDmFindOrphanDescending (
471 ACPI_PARSE_OBJECT *Op,
472 UINT32 Level,
473 void *Context)
474 {
475 const ACPI_OPCODE_INFO *OpInfo;
476 ACPI_PARSE_OBJECT *ChildOp;
477 ACPI_PARSE_OBJECT *NextOp;
478 ACPI_PARSE_OBJECT *ParentOp;
479 UINT32 ArgCount;
480
481
482 if (!Op)
483 {
484 return (AE_OK);
485 }
486
487 #ifdef ACPI_UNDER_DEVELOPMENT
488 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
489 #endif
490
491 switch (Op->Common.AmlOpcode)
492 {
493 #ifdef ACPI_UNDER_DEVELOPMENT
494 case AML_ADD_OP:
495
496 ChildOp = Op->Common.Value.Arg;
497 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
498 !ChildOp->Common.Node)
499 {
500 AcpiNsExternalizeName (ACPI_UINT32_MAX, ChildOp->Common.Value.String,
501 NULL, &Path);
502 AcpiOsPrintf ("/* %-16s A-NAMEPATH: %s */\n",
503 Op->Common.AmlOpName, Path);
504 ACPI_FREE (Path);
505
506 NextOp = Op->Common.Next;
507 if (!NextOp)
508 {
509 /* This NamePath has no args, assume it is an integer */
510
511 AcpiDmAddOpToExternalList (ChildOp,
512 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
513 return (AE_OK);
514 }
515
516 ArgCount = AcpiDmInspectPossibleArgs (3, 1, NextOp);
517 AcpiOsPrintf ("/* A-CHILDREN: %u Actual %u */\n",
518 ArgCount, AcpiDmCountChildren (Op));
519
520 if (ArgCount < 1)
521 {
522 /* One Arg means this is just a Store(Name,Target) */
523
524 AcpiDmAddOpToExternalList (ChildOp,
525 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
526 return (AE_OK);
527 }
528
529 AcpiDmAddOpToExternalList (ChildOp,
530 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
531 }
532 break;
533
534 #endif
535
536 case AML_STORE_OP:
537
538 ChildOp = Op->Common.Value.Arg;
539 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
540 !ChildOp->Common.Node)
541 {
542 NextOp = Op->Common.Next;
543 if (!NextOp)
544 {
545 /* This NamePath has no args, assume it is an integer */
546
547 AcpiDmAddOpToExternalList (ChildOp,
548 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
549 return (AE_OK);
550 }
551
552 ArgCount = AcpiDmInspectPossibleArgs (2, 1, NextOp);
553 if (ArgCount <= 1)
554 {
555 /* One Arg means this is just a Store(Name,Target) */
556
557 AcpiDmAddOpToExternalList (ChildOp,
558 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, ArgCount, 0);
559 return (AE_OK);
560 }
561
562 AcpiDmAddOpToExternalList (ChildOp,
563 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
564 }
565 break;
566
567 case AML_INT_NAMEPATH_OP:
568
569 /* Must examine parent to see if this namepath is an argument */
570
571 ParentOp = Op->Common.Parent;
572 OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode);
573
574 if ((OpInfo->Class != AML_CLASS_EXECUTE) &&
575 (OpInfo->Class != AML_CLASS_CREATE) &&
576 (OpInfo->ObjectType != ACPI_TYPE_LOCAL_ALIAS) &&
577 (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) &&
578 !Op->Common.Node)
579 {
580 ArgCount = AcpiDmInspectPossibleArgs (0, 0, Op);
581
582 /*
583 * Check if namepath is a predicate for if/while or lone parameter to
584 * a return.
585 */
586 if (ArgCount == 0)
587 {
588 if (((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
589 (ParentOp->Common.AmlOpcode == AML_WHILE_OP) ||
590 (ParentOp->Common.AmlOpcode == AML_RETURN_OP)) &&
591
592 /* And namepath is the first argument */
593 (ParentOp->Common.Value.Arg == Op))
594 {
595 AcpiDmAddOpToExternalList (Op,
596 Op->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
597 break;
598 }
599 }
600
601 /*
602 * This is a standalone namestring (not a parameter to another
603 * operator) - it *must* be a method invocation, nothing else is
604 * grammatically possible.
605 */
606 AcpiDmAddOpToExternalList (Op,
607 Op->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
608 }
609 break;
610
611 default:
612
613 break;
614 }
615
616 return (AE_OK);
617 }
618
619
620 /*******************************************************************************
621 *
622 * FUNCTION: AcpiDmLoadDescendingOp
623 *
624 * PARAMETERS: ASL_WALK_CALLBACK
625 *
626 * RETURN: Status
627 *
628 * DESCRIPTION: Descending handler for namespace control method object load
629 *
630 ******************************************************************************/
631
632 static ACPI_STATUS
633 AcpiDmLoadDescendingOp (
634 ACPI_PARSE_OBJECT *Op,
635 UINT32 Level,
636 void *Context)
637 {
638 ACPI_OP_WALK_INFO *Info = Context;
639 const ACPI_OPCODE_INFO *OpInfo;
640 ACPI_WALK_STATE *WalkState;
641 ACPI_OBJECT_TYPE ObjectType;
642 ACPI_STATUS Status;
643 char *Path = NULL;
644 ACPI_PARSE_OBJECT *NextOp;
645 ACPI_NAMESPACE_NODE *Node;
646 char FieldPath[5];
647 BOOLEAN PreDefined = FALSE;
648 UINT8 PreDefineIndex = 0;
649
650
651 WalkState = Info->WalkState;
652 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
653 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
654
655 /* Only interested in operators that create new names */
656
657 if (!(OpInfo->Flags & AML_NAMED) &&
658 !(OpInfo->Flags & AML_CREATE))
659 {
660 goto Exit;
661 }
662
663 /* Get the NamePath from the appropriate place */
664
665 if (OpInfo->Flags & AML_NAMED)
666 {
667 /* For all named operators, get the new name */
668
669 Path = Op->Named.Path;
670
671 if (!Path && Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP)
672 {
673 *ACPI_CAST_PTR (UINT32, &FieldPath[0]) = Op->Named.Name;
674 FieldPath[4] = 0;
675 Path = FieldPath;
676 }
677 }
678 else if (OpInfo->Flags & AML_CREATE)
679 {
680 /* New name is the last child */
681
682 NextOp = Op->Common.Value.Arg;
683
684 while (NextOp->Common.Next)
685 {
686 NextOp = NextOp->Common.Next;
687 }
688
689 Path = NextOp->Common.Value.String;
690 }
691
692 if (!Path)
693 {
694 goto Exit;
695 }
696
697 /* Insert the name into the namespace */
698
699 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType,
700 ACPI_IMODE_LOAD_PASS2, ACPI_NS_DONT_OPEN_SCOPE,
701 WalkState, &Node);
702
703 Op->Common.Node = Node;
704
705 if (ACPI_SUCCESS (Status))
706 {
707 /* Check if it's a predefined node */
708
709 while (AcpiGbl_PreDefinedNames[PreDefineIndex].Name)
710 {
711 if (ACPI_COMPARE_NAMESEG (Node->Name.Ascii,
712 AcpiGbl_PreDefinedNames[PreDefineIndex].Name))
713 {
714 PreDefined = TRUE;
715 break;
716 }
717
718 PreDefineIndex++;
719 }
720
721 /*
722 * Set node owner id if it satisfies all the following conditions:
723 * 1) Not a predefined node, _SB_ etc
724 * 2) Not the root node
725 * 3) Not a node created by Scope
726 */
727
728 if (!PreDefined && Node != AcpiGbl_RootNode &&
729 Op->Common.AmlOpcode != AML_SCOPE_OP)
730 {
731 Node->OwnerId = WalkState->OwnerId;
732 }
733 }
734
735
736 Exit:
737
738 if (AcpiNsOpensScope (ObjectType))
739 {
740 if (Op->Common.Node)
741 {
742 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
743 WalkState);
744 if (ACPI_FAILURE (Status))
745 {
746 return (Status);
747 }
748 }
749 }
750
751 return (AE_OK);
752 }
753
754
755 /*******************************************************************************
756 *
757 * FUNCTION: AcpiDmXrefDescendingOp
758 *
759 * PARAMETERS: ASL_WALK_CALLBACK
760 *
761 * RETURN: Status
762 *
763 * DESCRIPTION: Descending handler for namespace cross reference
764 *
765 ******************************************************************************/
766
767 static ACPI_STATUS
768 AcpiDmXrefDescendingOp (
769 ACPI_PARSE_OBJECT *Op,
770 UINT32 Level,
771 void *Context)
772 {
773 ACPI_OP_WALK_INFO *Info = Context;
774 const ACPI_OPCODE_INFO *OpInfo;
775 ACPI_WALK_STATE *WalkState;
776 ACPI_OBJECT_TYPE ObjectType;
777 ACPI_OBJECT_TYPE ObjectType2;
778 ACPI_STATUS Status;
779 char *Path = NULL;
780 ACPI_PARSE_OBJECT *NextOp;
781 ACPI_NAMESPACE_NODE *Node;
782 ACPI_OPERAND_OBJECT *Object;
783 UINT32 ParamCount = 0;
784 char *Pathname;
785 UINT16 Flags = 0;
786
787
788 WalkState = Info->WalkState;
789 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
790 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
791
792 if ((!(OpInfo->Flags & AML_NAMED)) &&
793 (!(OpInfo->Flags & AML_CREATE)) &&
794 (Op->Common.AmlOpcode != AML_INT_NAMEPATH_OP) &&
795 (Op->Common.AmlOpcode != AML_NOTIFY_OP))
796 {
797 goto Exit;
798 }
799
800 /* Get the NamePath from the appropriate place */
801
802 if (OpInfo->Flags & AML_NAMED)
803 {
804 /*
805 * Only these two operators (Alias, Scope) refer to an existing
806 * name, it is the first argument
807 */
808 if (Op->Common.AmlOpcode == AML_ALIAS_OP)
809 {
810 ObjectType = ACPI_TYPE_ANY;
811
812 NextOp = Op->Common.Value.Arg;
813 NextOp = NextOp->Common.Value.Arg;
814 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
815 {
816 Path = NextOp->Common.Value.String;
817 }
818 }
819 else if (Op->Common.AmlOpcode == AML_SCOPE_OP ||
820 Op->Common.AmlOpcode == AML_EXTERNAL_OP)
821 {
822 Path = Op->Named.Path;
823 }
824 }
825 else if (OpInfo->Flags & AML_CREATE)
826 {
827 /* Referenced Buffer Name is the first child */
828
829 ObjectType = ACPI_TYPE_BUFFER; /* Change from TYPE_BUFFER_FIELD */
830
831 NextOp = Op->Common.Value.Arg;
832 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
833 {
834 Path = NextOp->Common.Value.String;
835 }
836 }
837 else if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
838 {
839 Path = Op->Common.Value.Arg->Asl.Value.String;
840 }
841 else
842 {
843 Path = Op->Common.Value.String;
844 }
845
846 if (!Path)
847 {
848 goto Exit;
849 }
850
851 /*
852 * Lookup the name in the namespace. Name must exist at this point, or it
853 * is an invalid reference.
854 *
855 * The namespace is also used as a lookup table for references to resource
856 * descriptors and the fields within them.
857 */
858 Node = NULL;
859 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY,
860 ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
861 WalkState, &Node);
862
863 if (ACPI_SUCCESS (Status) && (Node->Flags & ANOBJ_IS_EXTERNAL))
864 {
865 /* Node was created by an External() statement */
866
867 Status = AE_NOT_FOUND;
868 }
869
870 if (ACPI_FAILURE (Status))
871 {
872 if (Status == AE_NOT_FOUND)
873 {
874 /*
875 * Add this symbol as an external declaration, except if the
876 * parent is a CondRefOf operator. For this operator, we do not
877 * need an external, nor do we want one, since this can cause
878 * disassembly problems if the symbol is actually a control
879 * method.
880 */
881 if (!(Op->Asl.Parent &&
882 (Op->Asl.Parent->Asl.AmlOpcode == AML_CONDITIONAL_REF_OF_OP)))
883 {
884 if (Node)
885 {
886 AcpiDmAddNodeToExternalList (Node,
887 (UINT8) ObjectType, 7, Flags);
888 }
889 else
890 {
891 AcpiDmAddOpToExternalList (Op, Path,
892 (UINT8) ObjectType, 7, Flags);
893 }
894 }
895 }
896 }
897
898 /*
899 * Found the node, but check if it came from an external table.
900 * Add it to external list. Note: Node->OwnerId == 0 indicates
901 * one of the built-in ACPI Names (_OS_ etc.) which can safely
902 * be ignored.
903 */
904 else if (Node->OwnerId &&
905 (WalkState->OwnerId != Node->OwnerId))
906 {
907 ObjectType2 = ObjectType;
908
909 Object = AcpiNsGetAttachedObject (Node);
910 if (Object)
911 {
912 ObjectType2 = Object->Common.Type;
913 if (ObjectType2 == ACPI_TYPE_METHOD)
914 {
915 ParamCount = Object->Method.ParamCount;
916 }
917 }
918
919 Pathname = AcpiNsGetExternalPathname (Node);
920 if (!Pathname)
921 {
922 return (AE_NO_MEMORY);
923 }
924
925 AcpiDmAddNodeToExternalList (Node, (UINT8) ObjectType2,
926 ParamCount, ACPI_EXT_RESOLVED_REFERENCE);
927
928 ACPI_FREE (Pathname);
929 Op->Common.Node = Node;
930 }
931 else
932 {
933 Op->Common.Node = Node;
934 }
935
936
937 Exit:
938 /* Open new scope if necessary */
939
940 if (AcpiNsOpensScope (ObjectType))
941 {
942 if (Op->Common.Node)
943 {
944 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
945 WalkState);
946 if (ACPI_FAILURE (Status))
947 {
948 return (Status);
949 }
950 }
951 }
952
953 return (AE_OK);
954 }
955
956 /*******************************************************************************
957 *
958 * FUNCTION: AcpiDmCommonDescendingOp
959 *
960 * PARAMETERS: ASL_WALK_CALLBACK
961 *
962 * RETURN: ACPI_STATUS
963 *
964 * DESCRIPTION: Perform parse tree preprocessing before main disassembly walk.
965 *
966 ******************************************************************************/
967
968 static ACPI_STATUS
969 AcpiDmCommonDescendingOp (
970 ACPI_PARSE_OBJECT *Op,
971 UINT32 Level,
972 void *Context)
973 {
974 ACPI_STATUS Status;
975
976
977 /* Resource descriptor conversion */
978
979 Status = AcpiDmProcessResourceDescriptors (Op, Level, Context);
980 if (ACPI_FAILURE (Status))
981 {
982 return (Status);
983 }
984
985 /* Switch/Case conversion */
986
987 Status = AcpiDmProcessSwitch (Op);
988 return (Status);
989 }
990
991
992 /*******************************************************************************
993 *
994 * FUNCTION: AcpiDmProcessResourceDescriptors
995 *
996 * PARAMETERS: ASL_WALK_CALLBACK
997 *
998 * RETURN: ACPI_STATUS
999 *
1000 * DESCRIPTION: Convert fixed-offset references to resource descriptors to
1001 * symbolic references. Should only be called after namespace has
1002 * been cross referenced.
1003 *
1004 ******************************************************************************/
1005
1006 static ACPI_STATUS
1007 AcpiDmProcessResourceDescriptors (
1008 ACPI_PARSE_OBJECT *Op,
1009 UINT32 Level,
1010 void *Context)
1011 {
1012 ACPI_OP_WALK_INFO *Info = Context;
1013 const ACPI_OPCODE_INFO *OpInfo;
1014 ACPI_WALK_STATE *WalkState;
1015 ACPI_OBJECT_TYPE ObjectType;
1016 ACPI_STATUS Status;
1017
1018
1019 WalkState = Info->WalkState;
1020 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
1021
1022 /* Open new scope if necessary */
1023
1024 ObjectType = OpInfo->ObjectType;
1025 if (AcpiNsOpensScope (ObjectType))
1026 {
1027 if (Op->Common.Node)
1028 {
1029
1030 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
1031 WalkState);
1032 if (ACPI_FAILURE (Status))
1033 {
1034 return (Status);
1035 }
1036 }
1037 }
1038
1039 /*
1040 * Check if this operator contains a reference to a resource descriptor.
1041 * If so, convert the reference into a symbolic reference.
1042 */
1043 AcpiDmCheckResourceReference (Op, WalkState);
1044 return (AE_OK);
1045 }
1046
1047 /*******************************************************************************
1048 *
1049 * FUNCTION: AcpiDmCommonAscendingOp
1050 *
1051 * PARAMETERS: ASL_WALK_CALLBACK
1052 *
1053 * RETURN: None
1054 *
1055 * DESCRIPTION: Ascending handler for combined parse/namespace walks. Closes
1056 * scope if necessary.
1057 *
1058 ******************************************************************************/
1059
1060 static ACPI_STATUS
1061 AcpiDmCommonAscendingOp (
1062 ACPI_PARSE_OBJECT *Op,
1063 UINT32 Level,
1064 void *Context)
1065 {
1066 ACPI_OP_WALK_INFO *Info = Context;
1067 ACPI_OBJECT_TYPE ObjectType;
1068
1069
1070 /* Close scope if necessary */
1071
1072 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
1073
1074 if (AcpiNsOpensScope (ObjectType))
1075 {
1076 (void) AcpiDsScopeStackPop (Info->WalkState);
1077 }
1078
1079 return (AE_OK);
1080 }
1081
1082 /*******************************************************************************
1083 *
1084 * FUNCTION: AcpiDmInspectPossibleArgs
1085 *
1086 * PARAMETERS: CurrentOpArgCount - Which arg of the current op was the
1087 * possible method invocation found
1088 * TargetCount - Number of targets (0,1,2) for this op
1089 * Op - Parse op
1090 *
1091 * RETURN: Status
1092 *
1093 * DESCRIPTION: Examine following args and next ops for possible arguments
1094 * for an unrecognized method invocation.
1095 *
1096 ******************************************************************************/
1097
1098 static UINT32
1099 AcpiDmInspectPossibleArgs (
1100 UINT32 CurrentOpArgCount,
1101 UINT32 TargetCount,
1102 ACPI_PARSE_OBJECT *Op)
1103 {
1104 const ACPI_OPCODE_INFO *OpInfo;
1105 UINT32 i;
1106 UINT32 ArgumentCount = 0;
1107 ACPI_PARSE_OBJECT *NextOp;
1108 ACPI_PARSE_OBJECT *ExecuteOp;
1109
1110
1111 if (!Op)
1112 {
1113 return (0);
1114 }
1115
1116 /* Lookahead for the maximum number of possible arguments */
1117
1118 NextOp = Op->Common.Next;
1119
1120 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && NextOp; i++)
1121 {
1122 OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode);
1123
1124 /* Any one of these operators is "very probably" not a method arg */
1125
1126 if ((NextOp->Common.AmlOpcode == AML_STORE_OP) ||
1127 (NextOp->Common.AmlOpcode == AML_NOTIFY_OP) ||
1128 (OpInfo->Class == AML_CLASS_CONTROL) ||
1129 (OpInfo->Class == AML_CLASS_CREATE) ||
1130 (OpInfo->Class == AML_CLASS_NAMED_OBJECT))
1131 {
1132 break;
1133 }
1134
1135 if (OpInfo->Class == AML_CLASS_EXECUTE)
1136 {
1137 /* Probable that this is method arg if there is no target */
1138
1139 ExecuteOp = NextOp->Common.Value.Arg;
1140 while (ExecuteOp)
1141 {
1142 if ((ExecuteOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
1143 (ExecuteOp->Common.Value.Arg == NULL))
1144 {
1145 /* No target, could be a method arg */
1146
1147 break;
1148 }
1149
1150 if (NextOp->Common.AmlOpcode == AML_REF_OF_OP)
1151 {
1152 break;
1153 }
1154
1155 ExecuteOp = ExecuteOp->Common.Next;
1156 }
1157
1158 if (!ExecuteOp)
1159 {
1160 /* Has a target, not method arg */
1161
1162 return (ArgumentCount);
1163 }
1164 }
1165
1166 ArgumentCount++;
1167 NextOp = NextOp->Common.Next;
1168 }
1169
1170 return (ArgumentCount);
1171 }
1172