psloop.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: psloop - Main AML parse loop
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions, and the following disclaimer,
16 *    without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 *    substantially similar to the "NO WARRANTY" disclaimer below
19 *    ("Disclaimer") and any redistribution must be conditioned upon
20 *    including a substantially similar Disclaimer requirement for further
21 *    binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 *    of any contributors may be used to endorse or promote products derived
24 *    from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44/*
45 * Parse the AML and build an operation tree as most interpreters, (such as
46 * Perl) do. Parsing is done by hand rather than with a YACC generated parser
47 * to tightly constrain stack and dynamic memory usage. Parsing is kept
48 * flexible and the code fairly compact by parsing based on a list of AML
49 * opcode templates in AmlOpInfo[].
50 */
51
52#include <contrib/dev/acpica/include/acpi.h>
53#include <contrib/dev/acpica/include/accommon.h>
54#include <contrib/dev/acpica/include/acinterp.h>
55#include <contrib/dev/acpica/include/acparser.h>
56#include <contrib/dev/acpica/include/acdispat.h>
57#include <contrib/dev/acpica/include/amlcode.h>
58
59#define _COMPONENT          ACPI_PARSER
60        ACPI_MODULE_NAME    ("psloop")
61
62
63/* Local prototypes */
64
65static ACPI_STATUS
66AcpiPsGetArguments (
67    ACPI_WALK_STATE         *WalkState,
68    UINT8                   *AmlOpStart,
69    ACPI_PARSE_OBJECT       *Op);
70
71static void
72AcpiPsLinkModuleCode (
73    ACPI_PARSE_OBJECT       *ParentOp,
74    UINT8                   *AmlStart,
75    UINT32                  AmlLength,
76    ACPI_OWNER_ID           OwnerId);
77
78
79/*******************************************************************************
80 *
81 * FUNCTION:    AcpiPsGetArguments
82 *
83 * PARAMETERS:  WalkState           - Current state
84 *              AmlOpStart          - Op start in AML
85 *              Op                  - Current Op
86 *
87 * RETURN:      Status
88 *
89 * DESCRIPTION: Get arguments for passed Op.
90 *
91 ******************************************************************************/
92
93static ACPI_STATUS
94AcpiPsGetArguments (
95    ACPI_WALK_STATE         *WalkState,
96    UINT8                   *AmlOpStart,
97    ACPI_PARSE_OBJECT       *Op)
98{
99    ACPI_STATUS             Status = AE_OK;
100    ACPI_PARSE_OBJECT       *Arg = NULL;
101    const ACPI_OPCODE_INFO  *OpInfo;
102
103
104    ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);
105
106
107    switch (Op->Common.AmlOpcode)
108    {
109    case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
110    case AML_WORD_OP:       /* AML_WORDDATA_ARG */
111    case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
112    case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
113    case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
114
115        /* Fill in constant or string argument directly */
116
117        AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
118            GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
119        break;
120
121    case AML_INT_NAMEPATH_OP:   /* AML_NAMESTRING_ARG */
122
123        Status = AcpiPsGetNextNamepath (WalkState,
124            &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL);
125        if (ACPI_FAILURE (Status))
126        {
127            return_ACPI_STATUS (Status);
128        }
129
130        WalkState->ArgTypes = 0;
131        break;
132
133    default:
134        /*
135         * Op is not a constant or string, append each argument to the Op
136         */
137        while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
138            !WalkState->ArgCount)
139        {
140            WalkState->Aml = WalkState->ParserState.Aml;
141
142            Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
143                GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
144            if (ACPI_FAILURE (Status))
145            {
146                return_ACPI_STATUS (Status);
147            }
148
149            if (Arg)
150            {
151                AcpiPsAppendArg (Op, Arg);
152            }
153
154            INCREMENT_ARG_LIST (WalkState->ArgTypes);
155        }
156
157
158        /*
159         * Handle executable code at "module-level". This refers to
160         * executable opcodes that appear outside of any control method.
161         */
162        if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
163            ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
164        {
165            /*
166             * We want to skip If/Else/While constructs during Pass1 because we
167             * want to actually conditionally execute the code during Pass2.
168             *
169             * Except for disassembly, where we always want to walk the
170             * If/Else/While packages
171             */
172            switch (Op->Common.AmlOpcode)
173            {
174            case AML_IF_OP:
175            case AML_ELSE_OP:
176            case AML_WHILE_OP:
177                /*
178                 * Currently supported module-level opcodes are:
179                 * IF/ELSE/WHILE. These appear to be the most common,
180                 * and easiest to support since they open an AML
181                 * package.
182                 */
183                if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
184                {
185                    AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
186                        (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
187                        WalkState->OwnerId);
188                }
189
190                ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
191                    "Pass1: Skipping an If/Else/While body\n"));
192
193                /* Skip body of if/else/while in pass 1 */
194
195                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
196                WalkState->ArgCount = 0;
197                break;
198
199            default:
200                /*
201                 * Check for an unsupported executable opcode at module
202                 * level. We must be in PASS1, the parent must be a SCOPE,
203                 * The opcode class must be EXECUTE, and the opcode must
204                 * not be an argument to another opcode.
205                 */
206                if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
207                    (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
208                {
209                    OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
210                    if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
211                        (!Arg))
212                    {
213                        ACPI_WARNING ((AE_INFO,
214                            "Unsupported module-level executable opcode "
215                            "0x%.2X at table offset 0x%.4X",
216                            Op->Common.AmlOpcode,
217                            (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
218                                WalkState->ParserState.AmlStart) +
219                                sizeof (ACPI_TABLE_HEADER))));
220                    }
221                }
222                break;
223            }
224        }
225
226        /* Special processing for certain opcodes */
227
228        switch (Op->Common.AmlOpcode)
229        {
230        case AML_METHOD_OP:
231            /*
232             * Skip parsing of control method because we don't have enough
233             * info in the first pass to parse it correctly.
234             *
235             * Save the length and address of the body
236             */
237            Op->Named.Data = WalkState->ParserState.Aml;
238            Op->Named.Length = (UINT32)
239                (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);
240
241            /* Skip body of method */
242
243            WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
244            WalkState->ArgCount = 0;
245            break;
246
247        case AML_BUFFER_OP:
248        case AML_PACKAGE_OP:
249        case AML_VAR_PACKAGE_OP:
250
251            if ((Op->Common.Parent) &&
252                (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
253                (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
254            {
255                /*
256                 * Skip parsing of Buffers and Packages because we don't have
257                 * enough info in the first pass to parse them correctly.
258                 */
259                Op->Named.Data = AmlOpStart;
260                Op->Named.Length = (UINT32)
261                    (WalkState->ParserState.PkgEnd - AmlOpStart);
262
263                /* Skip body */
264
265                WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
266                WalkState->ArgCount = 0;
267            }
268            break;
269
270        case AML_WHILE_OP:
271
272            if (WalkState->ControlState)
273            {
274                WalkState->ControlState->Control.PackageEnd =
275                    WalkState->ParserState.PkgEnd;
276            }
277            break;
278
279        default:
280
281            /* No action for all other opcodes */
282
283            break;
284        }
285
286        break;
287    }
288
289    return_ACPI_STATUS (AE_OK);
290}
291
292
293/*******************************************************************************
294 *
295 * FUNCTION:    AcpiPsLinkModuleCode
296 *
297 * PARAMETERS:  ParentOp            - Parent parser op
298 *              AmlStart            - Pointer to the AML
299 *              AmlLength           - Length of executable AML
300 *              OwnerId             - OwnerId of module level code
301 *
302 * RETURN:      None.
303 *
304 * DESCRIPTION: Wrap the module-level code with a method object and link the
305 *              object to the global list. Note, the mutex field of the method
306 *              object is used to link multiple module-level code objects.
307 *
308 ******************************************************************************/
309
310static void
311AcpiPsLinkModuleCode (
312    ACPI_PARSE_OBJECT       *ParentOp,
313    UINT8                   *AmlStart,
314    UINT32                  AmlLength,
315    ACPI_OWNER_ID           OwnerId)
316{
317    ACPI_OPERAND_OBJECT     *Prev;
318    ACPI_OPERAND_OBJECT     *Next;
319    ACPI_OPERAND_OBJECT     *MethodObj;
320    ACPI_NAMESPACE_NODE     *ParentNode;
321
322
323    ACPI_FUNCTION_TRACE (PsLinkModuleCode);
324
325
326    /* Get the tail of the list */
327
328    Prev = Next = AcpiGbl_ModuleCodeList;
329    while (Next)
330    {
331        Prev = Next;
332        Next = Next->Method.Mutex;
333    }
334
335    /*
336     * Insert the module level code into the list. Merge it if it is
337     * adjacent to the previous element.
338     */
339    if (!Prev ||
340       ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
341    {
342        /* Create, initialize, and link a new temporary method object */
343
344        MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
345        if (!MethodObj)
346        {
347            return_VOID;
348        }
349
350        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
351            "Create/Link new code block: %p\n", MethodObj));
352
353        if (ParentOp->Common.Node)
354        {
355            ParentNode = ParentOp->Common.Node;
356        }
357        else
358        {
359            ParentNode = AcpiGbl_RootNode;
360        }
361
362        MethodObj->Method.AmlStart = AmlStart;
363        MethodObj->Method.AmlLength = AmlLength;
364        MethodObj->Method.OwnerId = OwnerId;
365        MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL;
366
367        /*
368         * Save the parent node in NextObject. This is cheating, but we
369         * don't want to expand the method object.
370         */
371        MethodObj->Method.NextObject =
372            ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode);
373
374        if (!Prev)
375        {
376            AcpiGbl_ModuleCodeList = MethodObj;
377        }
378        else
379        {
380            Prev->Method.Mutex = MethodObj;
381        }
382    }
383    else
384    {
385        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
386            "Appending to existing code block: %p\n", Prev));
387
388        Prev->Method.AmlLength += AmlLength;
389    }
390
391    return_VOID;
392}
393
394/*******************************************************************************
395 *
396 * FUNCTION:    AcpiPsParseLoop
397 *
398 * PARAMETERS:  WalkState           - Current state
399 *
400 * RETURN:      Status
401 *
402 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
403 *              a tree of ops.
404 *
405 ******************************************************************************/
406
407ACPI_STATUS
408AcpiPsParseLoop (
409    ACPI_WALK_STATE         *WalkState)
410{
411    ACPI_STATUS             Status = AE_OK;
412    ACPI_PARSE_OBJECT       *Op = NULL;     /* current op */
413    ACPI_PARSE_STATE        *ParserState;
414    UINT8                   *AmlOpStart = NULL;
415
416
417    ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);
418
419
420    if (WalkState->DescendingCallback == NULL)
421    {
422        return_ACPI_STATUS (AE_BAD_PARAMETER);
423    }
424
425    ParserState = &WalkState->ParserState;
426    WalkState->ArgTypes = 0;
427
428#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
429
430    if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)
431    {
432        /* We are restarting a preempted control method */
433
434        if (AcpiPsHasCompletedScope (ParserState))
435        {
436            /*
437             * We must check if a predicate to an IF or WHILE statement
438             * was just completed
439             */
440            if ((ParserState->Scope->ParseScope.Op) &&
441               ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||
442                (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&
443                (WalkState->ControlState) &&
444                (WalkState->ControlState->Common.State ==
445                    ACPI_CONTROL_PREDICATE_EXECUTING))
446            {
447                /*
448                 * A predicate was just completed, get the value of the
449                 * predicate and branch based on that value
450                 */
451                WalkState->Op = NULL;
452                Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));
453                if (ACPI_FAILURE (Status) &&
454                    ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
455                {
456                    if (Status == AE_AML_NO_RETURN_VALUE)
457                    {
458                        ACPI_EXCEPTION ((AE_INFO, Status,
459                            "Invoked method did not return a value"));
460                    }
461
462                    ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));
463                    return_ACPI_STATUS (Status);
464                }
465
466                Status = AcpiPsNextParseState (WalkState, Op, Status);
467            }
468
469            AcpiPsPopScope (ParserState, &Op,
470                &WalkState->ArgTypes, &WalkState->ArgCount);
471            ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
472        }
473        else if (WalkState->PrevOp)
474        {
475            /* We were in the middle of an op */
476
477            Op = WalkState->PrevOp;
478            WalkState->ArgTypes = WalkState->PrevArgTypes;
479        }
480    }
481#endif
482
483    /* Iterative parsing loop, while there is more AML to process: */
484
485    while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
486    {
487        AmlOpStart = ParserState->Aml;
488        if (!Op)
489        {
490            Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
491            if (ACPI_FAILURE (Status))
492            {
493                if (Status == AE_CTRL_PARSE_CONTINUE)
494                {
495                    continue;
496                }
497
498                if (Status == AE_CTRL_PARSE_PENDING)
499                {
500                    Status = AE_OK;
501                }
502
503                if (Status == AE_CTRL_TERMINATE)
504                {
505                    return_ACPI_STATUS (Status);
506                }
507
508                Status = AcpiPsCompleteOp (WalkState, &Op, Status);
509                if (ACPI_FAILURE (Status))
510                {
511                    return_ACPI_STATUS (Status);
512                }
513
514                continue;
515            }
516
517            AcpiExStartTraceOpcode (Op, WalkState);
518        }
519
520
521        /*
522         * Start ArgCount at zero because we don't know if there are
523         * any args yet
524         */
525        WalkState->ArgCount  = 0;
526
527        /* Are there any arguments that must be processed? */
528
529        if (WalkState->ArgTypes)
530        {
531            /* Get arguments */
532
533            Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);
534            if (ACPI_FAILURE (Status))
535            {
536                Status = AcpiPsCompleteOp (WalkState, &Op, Status);
537                if (ACPI_FAILURE (Status))
538                {
539                    return_ACPI_STATUS (Status);
540                }
541
542                continue;
543            }
544        }
545
546        /* Check for arguments that need to be processed */
547
548        if (WalkState->ArgCount)
549        {
550            /*
551             * There are arguments (complex ones), push Op and
552             * prepare for argument
553             */
554            Status = AcpiPsPushScope (ParserState, Op,
555                WalkState->ArgTypes, WalkState->ArgCount);
556            if (ACPI_FAILURE (Status))
557            {
558                Status = AcpiPsCompleteOp (WalkState, &Op, Status);
559                if (ACPI_FAILURE (Status))
560                {
561                    return_ACPI_STATUS (Status);
562                }
563
564                continue;
565            }
566
567            Op = NULL;
568            continue;
569        }
570
571        /*
572         * All arguments have been processed -- Op is complete,
573         * prepare for next
574         */
575        WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
576        if (WalkState->OpInfo->Flags & AML_NAMED)
577        {
578            if (Op->Common.AmlOpcode == AML_REGION_OP ||
579                Op->Common.AmlOpcode == AML_DATA_REGION_OP)
580            {
581                /*
582                 * Skip parsing of control method or opregion body,
583                 * because we don't have enough info in the first pass
584                 * to parse them correctly.
585                 *
586                 * Completed parsing an OpRegion declaration, we now
587                 * know the length.
588                 */
589                Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
590            }
591        }
592
593        if (WalkState->OpInfo->Flags & AML_CREATE)
594        {
595            /*
596             * Backup to beginning of CreateXXXfield declaration (1 for
597             * Opcode)
598             *
599             * BodyLength is unknown until we parse the body
600             */
601            Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
602        }
603
604        if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)
605        {
606            /*
607             * Backup to beginning of BankField declaration
608             *
609             * BodyLength is unknown until we parse the body
610             */
611            Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
612        }
613
614        /* This op complete, notify the dispatcher */
615
616        if (WalkState->AscendingCallback != NULL)
617        {
618            WalkState->Op = Op;
619            WalkState->Opcode = Op->Common.AmlOpcode;
620
621            Status = WalkState->AscendingCallback (WalkState);
622            Status = AcpiPsNextParseState (WalkState, Op, Status);
623            if (Status == AE_CTRL_PENDING)
624            {
625                Status = AE_OK;
626            }
627        }
628
629        Status = AcpiPsCompleteOp (WalkState, &Op, Status);
630        if (ACPI_FAILURE (Status))
631        {
632            return_ACPI_STATUS (Status);
633        }
634
635    } /* while ParserState->Aml */
636
637    Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);
638    return_ACPI_STATUS (Status);
639}
640