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