adwalk.c revision 1.1.1.13 1 /******************************************************************************
2 *
3 * Module Name: adwalk - Application-level disassembler parse tree walk routines
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2019, 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 ACPI_STATUS Status;
376
377
378 if (!Op)
379 {
380 return (AE_OK);
381 }
382
383 /* Most of the information (count, level, name) here */
384
385 Info->Count++;
386 AcpiOsPrintf ("% 5d [%2.2d] ", Info->Count, Level);
387 AcpiDmIndent (Level);
388 AcpiOsPrintf ("%-28s", AcpiPsGetOpcodeName (Op->Common.AmlOpcode));
389
390 /* Extra info is helpful */
391
392 switch (Op->Common.AmlOpcode)
393 {
394 case AML_BYTE_OP:
395
396 AcpiOsPrintf ("%2.2X", (UINT32) Op->Common.Value.Integer);
397 break;
398
399 case AML_WORD_OP:
400
401 AcpiOsPrintf ("%4.4X", (UINT32) Op->Common.Value.Integer);
402 break;
403
404 case AML_DWORD_OP:
405
406 AcpiOsPrintf ("%8.8X", (UINT32) Op->Common.Value.Integer);
407 break;
408
409 case AML_QWORD_OP:
410
411 AcpiOsPrintf ("%8.8X%8.8X", ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
412 break;
413
414 case AML_INT_NAMEPATH_OP:
415
416 if (Op->Common.Value.String)
417 {
418 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Op->Common.Value.String,
419 NULL, &Path);
420 if (ACPI_SUCCESS (Status))
421 {
422 AcpiOsPrintf ("%s %p", Path, Op->Common.Node);
423 ACPI_FREE (Path);
424 }
425 else
426 {
427 AcpiOsPrintf ("Could not externalize pathname for node [%4.4s]",
428 Op->Common.Node->Name.Ascii);
429 }
430 }
431 else
432 {
433 AcpiOsPrintf ("[NULL]");
434 }
435 break;
436
437 case AML_NAME_OP:
438 case AML_METHOD_OP:
439 case AML_DEVICE_OP:
440
441 AcpiOsPrintf ("%4.4s",
442 ACPI_CAST_PTR (char, &Op->Named.Name));
443 break;
444
445 case AML_INT_NAMEDFIELD_OP:
446
447 AcpiOsPrintf ("%4.4s Length: (bits) %8.8X%8.8X (bytes) %8.8X%8.8X",
448 ACPI_CAST_PTR (char, &Op->Named.Name),
449 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer),
450 ACPI_FORMAT_UINT64 (Op->Common.Value.Integer / 8));
451 break;
452
453
454 default:
455
456 break;
457 }
458
459 AcpiOsPrintf ("\n");
460 return (AE_OK);
461 }
462
463
464 /*******************************************************************************
465 *
466 * FUNCTION: AcpiDmFindOrphanDescending
467 *
468 * PARAMETERS: ASL_WALK_CALLBACK
469 *
470 * RETURN: Status
471 *
472 * DESCRIPTION: Check namepath Ops for orphaned method invocations
473 *
474 * Note: Parts of this are experimental, under possible further development.
475 *
476 ******************************************************************************/
477
478 static ACPI_STATUS
479 AcpiDmFindOrphanDescending (
480 ACPI_PARSE_OBJECT *Op,
481 UINT32 Level,
482 void *Context)
483 {
484 const ACPI_OPCODE_INFO *OpInfo;
485 ACPI_PARSE_OBJECT *ChildOp;
486 ACPI_PARSE_OBJECT *NextOp;
487 ACPI_PARSE_OBJECT *ParentOp;
488 UINT32 ArgCount;
489
490
491 if (!Op)
492 {
493 return (AE_OK);
494 }
495
496 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
497
498 switch (Op->Common.AmlOpcode)
499 {
500 #ifdef ACPI_UNDER_DEVELOPMENT
501 case AML_ADD_OP:
502
503 ChildOp = Op->Common.Value.Arg;
504 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
505 !ChildOp->Common.Node)
506 {
507 AcpiNsExternalizeName (ACPI_UINT32_MAX, ChildOp->Common.Value.String,
508 NULL, &Path);
509 AcpiOsPrintf ("/* %-16s A-NAMEPATH: %s */\n",
510 Op->Common.AmlOpName, Path);
511 ACPI_FREE (Path);
512
513 NextOp = Op->Common.Next;
514 if (!NextOp)
515 {
516 /* This NamePath has no args, assume it is an integer */
517
518 AcpiDmAddOpToExternalList (ChildOp,
519 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
520 return (AE_OK);
521 }
522
523 ArgCount = AcpiDmInspectPossibleArgs (3, 1, NextOp);
524 AcpiOsPrintf ("/* A-CHILDREN: %u Actual %u */\n",
525 ArgCount, AcpiDmCountChildren (Op));
526
527 if (ArgCount < 1)
528 {
529 /* One Arg means this is just a Store(Name,Target) */
530
531 AcpiDmAddOpToExternalList (ChildOp,
532 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
533 return (AE_OK);
534 }
535
536 AcpiDmAddOpToExternalList (ChildOp,
537 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
538 }
539 break;
540
541 #endif
542
543 case AML_STORE_OP:
544
545 ChildOp = Op->Common.Value.Arg;
546 if ((ChildOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
547 !ChildOp->Common.Node)
548 {
549 NextOp = Op->Common.Next;
550 if (!NextOp)
551 {
552 /* This NamePath has no args, assume it is an integer */
553
554 AcpiDmAddOpToExternalList (ChildOp,
555 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
556 return (AE_OK);
557 }
558
559 ArgCount = AcpiDmInspectPossibleArgs (2, 1, NextOp);
560 if (ArgCount <= 1)
561 {
562 /* One Arg means this is just a Store(Name,Target) */
563
564 AcpiDmAddOpToExternalList (ChildOp,
565 ChildOp->Common.Value.String, ACPI_TYPE_INTEGER, ArgCount, 0);
566 return (AE_OK);
567 }
568
569 AcpiDmAddOpToExternalList (ChildOp,
570 ChildOp->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
571 }
572 break;
573
574 case AML_INT_NAMEPATH_OP:
575
576 /* Must examine parent to see if this namepath is an argument */
577
578 ParentOp = Op->Common.Parent;
579 OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode);
580
581 if ((OpInfo->Class != AML_CLASS_EXECUTE) &&
582 (OpInfo->Class != AML_CLASS_CREATE) &&
583 (OpInfo->ObjectType != ACPI_TYPE_LOCAL_ALIAS) &&
584 (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) &&
585 !Op->Common.Node)
586 {
587 ArgCount = AcpiDmInspectPossibleArgs (0, 0, Op);
588
589 /*
590 * Check if namepath is a predicate for if/while or lone parameter to
591 * a return.
592 */
593 if (ArgCount == 0)
594 {
595 if (((ParentOp->Common.AmlOpcode == AML_IF_OP) ||
596 (ParentOp->Common.AmlOpcode == AML_WHILE_OP) ||
597 (ParentOp->Common.AmlOpcode == AML_RETURN_OP)) &&
598
599 /* And namepath is the first argument */
600 (ParentOp->Common.Value.Arg == Op))
601 {
602 AcpiDmAddOpToExternalList (Op,
603 Op->Common.Value.String, ACPI_TYPE_INTEGER, 0, 0);
604 break;
605 }
606 }
607
608 /*
609 * This is a standalone namestring (not a parameter to another
610 * operator) - it *must* be a method invocation, nothing else is
611 * grammatically possible.
612 */
613 AcpiDmAddOpToExternalList (Op,
614 Op->Common.Value.String, ACPI_TYPE_METHOD, ArgCount, 0);
615 }
616 break;
617
618 default:
619
620 break;
621 }
622
623 return (AE_OK);
624 }
625
626
627 /*******************************************************************************
628 *
629 * FUNCTION: AcpiDmLoadDescendingOp
630 *
631 * PARAMETERS: ASL_WALK_CALLBACK
632 *
633 * RETURN: Status
634 *
635 * DESCRIPTION: Descending handler for namespace control method object load
636 *
637 ******************************************************************************/
638
639 static ACPI_STATUS
640 AcpiDmLoadDescendingOp (
641 ACPI_PARSE_OBJECT *Op,
642 UINT32 Level,
643 void *Context)
644 {
645 ACPI_OP_WALK_INFO *Info = Context;
646 const ACPI_OPCODE_INFO *OpInfo;
647 ACPI_WALK_STATE *WalkState;
648 ACPI_OBJECT_TYPE ObjectType;
649 ACPI_STATUS Status;
650 char *Path = NULL;
651 ACPI_PARSE_OBJECT *NextOp;
652 ACPI_NAMESPACE_NODE *Node;
653 char FieldPath[5];
654 BOOLEAN PreDefined = FALSE;
655 UINT8 PreDefineIndex = 0;
656
657
658 WalkState = Info->WalkState;
659 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
660 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
661
662 /* Only interested in operators that create new names */
663
664 if (!(OpInfo->Flags & AML_NAMED) &&
665 !(OpInfo->Flags & AML_CREATE))
666 {
667 goto Exit;
668 }
669
670 /* Get the NamePath from the appropriate place */
671
672 if (OpInfo->Flags & AML_NAMED)
673 {
674 /* For all named operators, get the new name */
675
676 Path = Op->Named.Path;
677
678 if (!Path && Op->Common.AmlOpcode == AML_INT_NAMEDFIELD_OP)
679 {
680 *ACPI_CAST_PTR (UINT32, &FieldPath[0]) = Op->Named.Name;
681 FieldPath[4] = 0;
682 Path = FieldPath;
683 }
684 }
685 else if (OpInfo->Flags & AML_CREATE)
686 {
687 /* New name is the last child */
688
689 NextOp = Op->Common.Value.Arg;
690
691 while (NextOp->Common.Next)
692 {
693 NextOp = NextOp->Common.Next;
694 }
695
696 Path = NextOp->Common.Value.String;
697 }
698
699 if (!Path)
700 {
701 goto Exit;
702 }
703
704 /* Insert the name into the namespace */
705
706 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType,
707 ACPI_IMODE_LOAD_PASS2, ACPI_NS_DONT_OPEN_SCOPE,
708 WalkState, &Node);
709
710 Op->Common.Node = Node;
711
712 if (ACPI_SUCCESS (Status))
713 {
714 /* Check if it's a predefined node */
715
716 while (AcpiGbl_PreDefinedNames[PreDefineIndex].Name)
717 {
718 if (ACPI_COMPARE_NAMESEG (Node->Name.Ascii,
719 AcpiGbl_PreDefinedNames[PreDefineIndex].Name))
720 {
721 PreDefined = TRUE;
722 break;
723 }
724
725 PreDefineIndex++;
726 }
727
728 /*
729 * Set node owner id if it satisfies all the following conditions:
730 * 1) Not a predefined node, _SB_ etc
731 * 2) Not the root node
732 * 3) Not a node created by Scope
733 */
734 if (!PreDefined &&
735 (Node != AcpiGbl_RootNode) &&
736 (Op->Common.AmlOpcode != AML_SCOPE_OP))
737 {
738 Node->OwnerId = WalkState->OwnerId;
739 }
740 }
741
742
743 Exit:
744
745 if (AcpiNsOpensScope (ObjectType))
746 {
747 if (Op->Common.Node)
748 {
749 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
750 WalkState);
751 if (ACPI_FAILURE (Status))
752 {
753 return (Status);
754 }
755 }
756 }
757
758 return (AE_OK);
759 }
760
761
762 /*******************************************************************************
763 *
764 * FUNCTION: AcpiDmXrefDescendingOp
765 *
766 * PARAMETERS: ASL_WALK_CALLBACK
767 *
768 * RETURN: Status
769 *
770 * DESCRIPTION: Descending handler for namespace cross reference
771 *
772 ******************************************************************************/
773
774 static ACPI_STATUS
775 AcpiDmXrefDescendingOp (
776 ACPI_PARSE_OBJECT *Op,
777 UINT32 Level,
778 void *Context)
779 {
780 ACPI_OP_WALK_INFO *Info = Context;
781 const ACPI_OPCODE_INFO *OpInfo;
782 ACPI_WALK_STATE *WalkState;
783 ACPI_OBJECT_TYPE ObjectType;
784 ACPI_OBJECT_TYPE ObjectType2;
785 ACPI_STATUS Status;
786 char *Path = NULL;
787 ACPI_PARSE_OBJECT *NextOp;
788 ACPI_NAMESPACE_NODE *Node;
789 ACPI_OPERAND_OBJECT *Object;
790 UINT32 ParamCount = 0;
791 char *Pathname;
792 UINT16 Flags = 0;
793
794
795 WalkState = Info->WalkState;
796 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
797 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
798
799 if ((!(OpInfo->Flags & AML_NAMED)) &&
800 (!(OpInfo->Flags & AML_CREATE)) &&
801 (Op->Common.AmlOpcode != AML_INT_NAMEPATH_OP) &&
802 (Op->Common.AmlOpcode != AML_NOTIFY_OP))
803 {
804 goto Exit;
805 }
806
807 /* Get the NamePath from the appropriate place */
808
809 if (OpInfo->Flags & AML_NAMED)
810 {
811 /*
812 * Only these two operators (Alias, Scope) refer to an existing
813 * name, it is the first argument
814 */
815 if (Op->Common.AmlOpcode == AML_ALIAS_OP)
816 {
817 ObjectType = ACPI_TYPE_ANY;
818
819 NextOp = Op->Common.Value.Arg;
820 NextOp = NextOp->Common.Value.Arg;
821 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
822 {
823 Path = NextOp->Common.Value.String;
824 }
825 }
826 else if (Op->Common.AmlOpcode == AML_SCOPE_OP ||
827 Op->Common.AmlOpcode == AML_EXTERNAL_OP)
828 {
829 Path = Op->Named.Path;
830 }
831 }
832 else if (OpInfo->Flags & AML_CREATE)
833 {
834 /* Referenced Buffer Name is the first child */
835
836 ObjectType = ACPI_TYPE_BUFFER; /* Change from TYPE_BUFFER_FIELD */
837
838 NextOp = Op->Common.Value.Arg;
839 if (NextOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
840 {
841 Path = NextOp->Common.Value.String;
842 }
843 }
844 else if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
845 {
846 Path = Op->Common.Value.Arg->Asl.Value.String;
847 }
848 else
849 {
850 Path = Op->Common.Value.String;
851 }
852
853 if (!Path)
854 {
855 goto Exit;
856 }
857
858 /*
859 * Lookup the name in the namespace. Name must exist at this point, or it
860 * is an invalid reference.
861 *
862 * The namespace is also used as a lookup table for references to resource
863 * descriptors and the fields within them.
864 */
865 Node = NULL;
866 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ACPI_TYPE_ANY,
867 ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
868 WalkState, &Node);
869
870 if (ACPI_SUCCESS (Status) && (Node->Flags & ANOBJ_IS_EXTERNAL))
871 {
872 /* Node was created by an External() statement */
873
874 Status = AE_NOT_FOUND;
875 }
876
877 if (ACPI_FAILURE (Status))
878 {
879 if (Status == AE_NOT_FOUND)
880 {
881 /*
882 * Add this symbol as an external declaration, except if the
883 * parent is a CondRefOf operator. For this operator, we do not
884 * need an external, nor do we want one, since this can cause
885 * disassembly problems if the symbol is actually a control
886 * method.
887 */
888 if (!(Op->Asl.Parent &&
889 (Op->Asl.Parent->Asl.AmlOpcode == AML_CONDITIONAL_REF_OF_OP)))
890 {
891 if (Node)
892 {
893 AcpiDmAddNodeToExternalList (Node,
894 (UINT8) ObjectType, 7, Flags);
895 }
896 else
897 {
898 AcpiDmAddOpToExternalList (Op, Path,
899 (UINT8) ObjectType, 7, Flags);
900 }
901 }
902 }
903 }
904
905 /*
906 * Found the node, but check if it came from an external table.
907 * Add it to external list. Note: Node->OwnerId == 0 indicates
908 * one of the built-in ACPI Names (_OS_ etc.) which can safely
909 * be ignored.
910 */
911 else if (Node->OwnerId &&
912 (WalkState->OwnerId != Node->OwnerId))
913 {
914 ObjectType2 = ObjectType;
915
916 Object = AcpiNsGetAttachedObject (Node);
917 if (Object)
918 {
919 ObjectType2 = Object->Common.Type;
920 if (ObjectType2 == ACPI_TYPE_METHOD)
921 {
922 ParamCount = Object->Method.ParamCount;
923 }
924 }
925
926 Pathname = AcpiNsGetExternalPathname (Node);
927 if (!Pathname)
928 {
929 return (AE_NO_MEMORY);
930 }
931
932 AcpiDmAddNodeToExternalList (Node, (UINT8) ObjectType2,
933 ParamCount, ACPI_EXT_RESOLVED_REFERENCE);
934
935 ACPI_FREE (Pathname);
936 Op->Common.Node = Node;
937 }
938 else
939 {
940 Op->Common.Node = Node;
941 }
942
943
944 Exit:
945 /* Open new scope if necessary */
946
947 if (AcpiNsOpensScope (ObjectType))
948 {
949 if (Op->Common.Node)
950 {
951 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
952 WalkState);
953 if (ACPI_FAILURE (Status))
954 {
955 return (Status);
956 }
957 }
958 }
959
960 return (AE_OK);
961 }
962
963 /*******************************************************************************
964 *
965 * FUNCTION: AcpiDmCommonDescendingOp
966 *
967 * PARAMETERS: ASL_WALK_CALLBACK
968 *
969 * RETURN: ACPI_STATUS
970 *
971 * DESCRIPTION: Perform parse tree preprocessing before main disassembly walk.
972 *
973 ******************************************************************************/
974
975 static ACPI_STATUS
976 AcpiDmCommonDescendingOp (
977 ACPI_PARSE_OBJECT *Op,
978 UINT32 Level,
979 void *Context)
980 {
981 ACPI_STATUS Status;
982
983
984 /* Resource descriptor conversion */
985
986 Status = AcpiDmProcessResourceDescriptors (Op, Level, Context);
987 if (ACPI_FAILURE (Status))
988 {
989 return (Status);
990 }
991
992 /* Switch/Case conversion */
993
994 Status = AcpiDmProcessSwitch (Op);
995 return (AE_OK);
996 }
997
998
999 /*******************************************************************************
1000 *
1001 * FUNCTION: AcpiDmProcessResourceDescriptors
1002 *
1003 * PARAMETERS: ASL_WALK_CALLBACK
1004 *
1005 * RETURN: ACPI_STATUS
1006 *
1007 * DESCRIPTION: Convert fixed-offset references to resource descriptors to
1008 * symbolic references. Should only be called after namespace has
1009 * been cross referenced.
1010 *
1011 ******************************************************************************/
1012
1013 static ACPI_STATUS
1014 AcpiDmProcessResourceDescriptors (
1015 ACPI_PARSE_OBJECT *Op,
1016 UINT32 Level,
1017 void *Context)
1018 {
1019 ACPI_OP_WALK_INFO *Info = Context;
1020 const ACPI_OPCODE_INFO *OpInfo;
1021 ACPI_WALK_STATE *WalkState;
1022 ACPI_OBJECT_TYPE ObjectType;
1023 ACPI_STATUS Status;
1024
1025
1026 WalkState = Info->WalkState;
1027 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
1028
1029 /* Open new scope if necessary */
1030
1031 ObjectType = OpInfo->ObjectType;
1032 if (AcpiNsOpensScope (ObjectType))
1033 {
1034 if (Op->Common.Node)
1035 {
1036
1037 Status = AcpiDsScopeStackPush (Op->Common.Node, ObjectType,
1038 WalkState);
1039 if (ACPI_FAILURE (Status))
1040 {
1041 return (Status);
1042 }
1043 }
1044 }
1045
1046 /*
1047 * Check if this operator contains a reference to a resource descriptor.
1048 * If so, convert the reference into a symbolic reference.
1049 */
1050 AcpiDmCheckResourceReference (Op, WalkState);
1051 return (AE_OK);
1052 }
1053
1054 /*******************************************************************************
1055 *
1056 * FUNCTION: AcpiDmCommonAscendingOp
1057 *
1058 * PARAMETERS: ASL_WALK_CALLBACK
1059 *
1060 * RETURN: None
1061 *
1062 * DESCRIPTION: Ascending handler for combined parse/namespace walks. Closes
1063 * scope if necessary.
1064 *
1065 ******************************************************************************/
1066
1067 static ACPI_STATUS
1068 AcpiDmCommonAscendingOp (
1069 ACPI_PARSE_OBJECT *Op,
1070 UINT32 Level,
1071 void *Context)
1072 {
1073 ACPI_OP_WALK_INFO *Info = Context;
1074 ACPI_OBJECT_TYPE ObjectType;
1075
1076
1077 /* Close scope if necessary */
1078
1079 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
1080
1081 if (AcpiNsOpensScope (ObjectType))
1082 {
1083 (void) AcpiDsScopeStackPop (Info->WalkState);
1084 }
1085
1086 return (AE_OK);
1087 }
1088
1089 /*******************************************************************************
1090 *
1091 * FUNCTION: AcpiDmInspectPossibleArgs
1092 *
1093 * PARAMETERS: CurrentOpArgCount - Which arg of the current op was the
1094 * possible method invocation found
1095 * TargetCount - Number of targets (0,1,2) for this op
1096 * Op - Parse op
1097 *
1098 * RETURN: Status
1099 *
1100 * DESCRIPTION: Examine following args and next ops for possible arguments
1101 * for an unrecognized method invocation.
1102 *
1103 ******************************************************************************/
1104
1105 static UINT32
1106 AcpiDmInspectPossibleArgs (
1107 UINT32 CurrentOpArgCount,
1108 UINT32 TargetCount,
1109 ACPI_PARSE_OBJECT *Op)
1110 {
1111 const ACPI_OPCODE_INFO *OpInfo;
1112 UINT32 i;
1113 UINT32 ArgumentCount = 0;
1114 ACPI_PARSE_OBJECT *NextOp;
1115 ACPI_PARSE_OBJECT *ExecuteOp;
1116
1117
1118 if (!Op)
1119 {
1120 return (0);
1121 }
1122
1123 /* Lookahead for the maximum number of possible arguments */
1124
1125 NextOp = Op->Common.Next;
1126
1127 for (i = 0; (i < ACPI_METHOD_NUM_ARGS) && NextOp; i++)
1128 {
1129 OpInfo = AcpiPsGetOpcodeInfo (NextOp->Common.AmlOpcode);
1130
1131 /* Any one of these operators is "very probably" not a method arg */
1132
1133 if ((NextOp->Common.AmlOpcode == AML_STORE_OP) ||
1134 (NextOp->Common.AmlOpcode == AML_NOTIFY_OP) ||
1135 (OpInfo->Class == AML_CLASS_CONTROL) ||
1136 (OpInfo->Class == AML_CLASS_CREATE) ||
1137 (OpInfo->Class == AML_CLASS_NAMED_OBJECT))
1138 {
1139 break;
1140 }
1141
1142 if (OpInfo->Class == AML_CLASS_EXECUTE)
1143 {
1144 /* Probable that this is method arg if there is no target */
1145
1146 ExecuteOp = NextOp->Common.Value.Arg;
1147 while (ExecuteOp)
1148 {
1149 if ((ExecuteOp->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
1150 (ExecuteOp->Common.Value.Arg == NULL))
1151 {
1152 /* No target, could be a method arg */
1153
1154 break;
1155 }
1156
1157 if (NextOp->Common.AmlOpcode == AML_REF_OF_OP)
1158 {
1159 break;
1160 }
1161
1162 ExecuteOp = ExecuteOp->Common.Next;
1163 }
1164
1165 if (!ExecuteOp)
1166 {
1167 /* Has a target, not method arg */
1168
1169 return (ArgumentCount);
1170 }
1171 }
1172
1173 ArgumentCount++;
1174 NextOp = NextOp->Common.Next;
1175 }
1176
1177 return (ArgumentCount);
1178 }
1179