psobject.c revision 250838
1/******************************************************************************
2 *
3 * Module Name: psobject - Support for parse objects
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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#include <contrib/dev/acpica/include/acpi.h>
46#include <contrib/dev/acpica/include/accommon.h>
47#include <contrib/dev/acpica/include/acparser.h>
48#include <contrib/dev/acpica/include/amlcode.h>
49
50#define _COMPONENT          ACPI_PARSER
51        ACPI_MODULE_NAME    ("psobject")
52
53
54/* Local prototypes */
55
56static ACPI_STATUS
57AcpiPsGetAmlOpcode (
58    ACPI_WALK_STATE         *WalkState);
59
60
61/*******************************************************************************
62 *
63 * FUNCTION:    AcpiPsGetAmlOpcode
64 *
65 * PARAMETERS:  WalkState           - Current state
66 *
67 * RETURN:      Status
68 *
69 * DESCRIPTION: Extract the next AML opcode from the input stream.
70 *
71 ******************************************************************************/
72
73static ACPI_STATUS
74AcpiPsGetAmlOpcode (
75    ACPI_WALK_STATE         *WalkState)
76{
77
78    ACPI_FUNCTION_TRACE_PTR (PsGetAmlOpcode, WalkState);
79
80
81    WalkState->AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->ParserState.Aml,
82                                WalkState->ParserState.AmlStart);
83    WalkState->Opcode = AcpiPsPeekOpcode (&(WalkState->ParserState));
84
85    /*
86     * First cut to determine what we have found:
87     * 1) A valid AML opcode
88     * 2) A name string
89     * 3) An unknown/invalid opcode
90     */
91    WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode);
92
93    switch (WalkState->OpInfo->Class)
94    {
95    case AML_CLASS_ASCII:
96    case AML_CLASS_PREFIX:
97        /*
98         * Starts with a valid prefix or ASCII char, this is a name
99         * string. Convert the bare name string to a namepath.
100         */
101        WalkState->Opcode = AML_INT_NAMEPATH_OP;
102        WalkState->ArgTypes = ARGP_NAMESTRING;
103        break;
104
105    case AML_CLASS_UNKNOWN:
106
107        /* The opcode is unrecognized. Complain and skip unknown opcodes */
108
109        if (WalkState->PassNumber == 2)
110        {
111            ACPI_ERROR ((AE_INFO,
112                "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring",
113                WalkState->Opcode,
114                (UINT32) (WalkState->AmlOffset + sizeof (ACPI_TABLE_HEADER))));
115
116            ACPI_DUMP_BUFFER ((WalkState->ParserState.Aml - 16), 48);
117
118#ifdef ACPI_ASL_COMPILER
119            /*
120             * This is executed for the disassembler only. Output goes
121             * to the disassembled ASL output file.
122             */
123            AcpiOsPrintf (
124                "/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n",
125                WalkState->Opcode,
126                (UINT32) (WalkState->AmlOffset + sizeof (ACPI_TABLE_HEADER)));
127
128            /* Dump the context surrounding the invalid opcode */
129
130            AcpiUtDumpBuffer (((UINT8 *) WalkState->ParserState.Aml - 16),
131                48, DB_BYTE_DISPLAY,
132                (WalkState->AmlOffset + sizeof (ACPI_TABLE_HEADER) - 16));
133            AcpiOsPrintf (" */\n");
134#endif
135        }
136
137        /* Increment past one-byte or two-byte opcode */
138
139        WalkState->ParserState.Aml++;
140        if (WalkState->Opcode > 0xFF) /* Can only happen if first byte is 0x5B */
141        {
142            WalkState->ParserState.Aml++;
143        }
144
145        return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE);
146
147    default:
148
149        /* Found opcode info, this is a normal opcode */
150
151        WalkState->ParserState.Aml += AcpiPsGetOpcodeSize (WalkState->Opcode);
152        WalkState->ArgTypes = WalkState->OpInfo->ParseArgs;
153        break;
154    }
155
156    return_ACPI_STATUS (AE_OK);
157}
158
159
160/*******************************************************************************
161 *
162 * FUNCTION:    AcpiPsBuildNamedOp
163 *
164 * PARAMETERS:  WalkState           - Current state
165 *              AmlOpStart          - Begin of named Op in AML
166 *              UnnamedOp           - Early Op (not a named Op)
167 *              Op                  - Returned Op
168 *
169 * RETURN:      Status
170 *
171 * DESCRIPTION: Parse a named Op
172 *
173 ******************************************************************************/
174
175ACPI_STATUS
176AcpiPsBuildNamedOp (
177    ACPI_WALK_STATE         *WalkState,
178    UINT8                   *AmlOpStart,
179    ACPI_PARSE_OBJECT       *UnnamedOp,
180    ACPI_PARSE_OBJECT       **Op)
181{
182    ACPI_STATUS             Status = AE_OK;
183    ACPI_PARSE_OBJECT       *Arg = NULL;
184
185
186    ACPI_FUNCTION_TRACE_PTR (PsBuildNamedOp, WalkState);
187
188
189    UnnamedOp->Common.Value.Arg = NULL;
190    UnnamedOp->Common.ArgListLength = 0;
191    UnnamedOp->Common.AmlOpcode = WalkState->Opcode;
192
193    /*
194     * Get and append arguments until we find the node that contains
195     * the name (the type ARGP_NAME).
196     */
197    while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
198          (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) != ARGP_NAME))
199    {
200        Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
201                    GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
202        if (ACPI_FAILURE (Status))
203        {
204            return_ACPI_STATUS (Status);
205        }
206
207        AcpiPsAppendArg (UnnamedOp, Arg);
208        INCREMENT_ARG_LIST (WalkState->ArgTypes);
209    }
210
211    /*
212     * Make sure that we found a NAME and didn't run out of arguments
213     */
214    if (!GET_CURRENT_ARG_TYPE (WalkState->ArgTypes))
215    {
216        return_ACPI_STATUS (AE_AML_NO_OPERAND);
217    }
218
219    /* We know that this arg is a name, move to next arg */
220
221    INCREMENT_ARG_LIST (WalkState->ArgTypes);
222
223    /*
224     * Find the object. This will either insert the object into
225     * the namespace or simply look it up
226     */
227    WalkState->Op = NULL;
228
229    Status = WalkState->DescendingCallback (WalkState, Op);
230    if (ACPI_FAILURE (Status))
231    {
232        ACPI_EXCEPTION ((AE_INFO, Status, "During name lookup/catalog"));
233        return_ACPI_STATUS (Status);
234    }
235
236    if (!*Op)
237    {
238        return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE);
239    }
240
241    Status = AcpiPsNextParseState (WalkState, *Op, Status);
242    if (ACPI_FAILURE (Status))
243    {
244        if (Status == AE_CTRL_PENDING)
245        {
246            return_ACPI_STATUS (AE_CTRL_PARSE_PENDING);
247        }
248        return_ACPI_STATUS (Status);
249    }
250
251    AcpiPsAppendArg (*Op, UnnamedOp->Common.Value.Arg);
252
253    if ((*Op)->Common.AmlOpcode == AML_REGION_OP ||
254        (*Op)->Common.AmlOpcode == AML_DATA_REGION_OP)
255    {
256        /*
257         * Defer final parsing of an OperationRegion body, because we don't
258         * have enough info in the first pass to parse it correctly (i.e.,
259         * there may be method calls within the TermArg elements of the body.)
260         *
261         * However, we must continue parsing because the opregion is not a
262         * standalone package -- we don't know where the end is at this point.
263         *
264         * (Length is unknown until parse of the body complete)
265         */
266        (*Op)->Named.Data = AmlOpStart;
267        (*Op)->Named.Length = 0;
268    }
269
270    return_ACPI_STATUS (AE_OK);
271}
272
273
274/*******************************************************************************
275 *
276 * FUNCTION:    AcpiPsCreateOp
277 *
278 * PARAMETERS:  WalkState           - Current state
279 *              AmlOpStart          - Op start in AML
280 *              NewOp               - Returned Op
281 *
282 * RETURN:      Status
283 *
284 * DESCRIPTION: Get Op from AML
285 *
286 ******************************************************************************/
287
288ACPI_STATUS
289AcpiPsCreateOp (
290    ACPI_WALK_STATE         *WalkState,
291    UINT8                   *AmlOpStart,
292    ACPI_PARSE_OBJECT       **NewOp)
293{
294    ACPI_STATUS             Status = AE_OK;
295    ACPI_PARSE_OBJECT       *Op;
296    ACPI_PARSE_OBJECT       *NamedOp = NULL;
297    ACPI_PARSE_OBJECT       *ParentScope;
298    UINT8                   ArgumentCount;
299    const ACPI_OPCODE_INFO  *OpInfo;
300
301
302    ACPI_FUNCTION_TRACE_PTR (PsCreateOp, WalkState);
303
304
305    Status = AcpiPsGetAmlOpcode (WalkState);
306    if (Status == AE_CTRL_PARSE_CONTINUE)
307    {
308        return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE);
309    }
310
311    /* Create Op structure and append to parent's argument list */
312
313    WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode);
314    Op = AcpiPsAllocOp (WalkState->Opcode);
315    if (!Op)
316    {
317        return_ACPI_STATUS (AE_NO_MEMORY);
318    }
319
320    if (WalkState->OpInfo->Flags & AML_NAMED)
321    {
322        Status = AcpiPsBuildNamedOp (WalkState, AmlOpStart, Op, &NamedOp);
323        AcpiPsFreeOp (Op);
324        if (ACPI_FAILURE (Status))
325        {
326            return_ACPI_STATUS (Status);
327        }
328
329        *NewOp = NamedOp;
330        return_ACPI_STATUS (AE_OK);
331    }
332
333    /* Not a named opcode, just allocate Op and append to parent */
334
335    if (WalkState->OpInfo->Flags & AML_CREATE)
336    {
337        /*
338         * Backup to beginning of CreateXXXfield declaration
339         * BodyLength is unknown until we parse the body
340         */
341        Op->Named.Data = AmlOpStart;
342        Op->Named.Length = 0;
343    }
344
345    if (WalkState->Opcode == AML_BANK_FIELD_OP)
346    {
347        /*
348         * Backup to beginning of BankField declaration
349         * BodyLength is unknown until we parse the body
350         */
351        Op->Named.Data = AmlOpStart;
352        Op->Named.Length = 0;
353    }
354
355    ParentScope = AcpiPsGetParentScope (&(WalkState->ParserState));
356    AcpiPsAppendArg (ParentScope, Op);
357
358    if (ParentScope)
359    {
360        OpInfo = AcpiPsGetOpcodeInfo (ParentScope->Common.AmlOpcode);
361        if (OpInfo->Flags & AML_HAS_TARGET)
362        {
363            ArgumentCount = AcpiPsGetArgumentCount (OpInfo->Type);
364            if (ParentScope->Common.ArgListLength > ArgumentCount)
365            {
366                Op->Common.Flags |= ACPI_PARSEOP_TARGET;
367            }
368        }
369        else if (ParentScope->Common.AmlOpcode == AML_INCREMENT_OP)
370        {
371            Op->Common.Flags |= ACPI_PARSEOP_TARGET;
372        }
373    }
374
375    if (WalkState->DescendingCallback != NULL)
376    {
377        /*
378         * Find the object. This will either insert the object into
379         * the namespace or simply look it up
380         */
381        WalkState->Op = *NewOp = Op;
382
383        Status = WalkState->DescendingCallback (WalkState, &Op);
384        Status = AcpiPsNextParseState (WalkState, Op, Status);
385        if (Status == AE_CTRL_PENDING)
386        {
387            Status = AE_CTRL_PARSE_PENDING;
388        }
389    }
390
391    return_ACPI_STATUS (Status);
392}
393
394
395/*******************************************************************************
396 *
397 * FUNCTION:    AcpiPsCompleteOp
398 *
399 * PARAMETERS:  WalkState           - Current state
400 *              Op                  - Returned Op
401 *              Status              - Parse status before complete Op
402 *
403 * RETURN:      Status
404 *
405 * DESCRIPTION: Complete Op
406 *
407 ******************************************************************************/
408
409ACPI_STATUS
410AcpiPsCompleteOp (
411    ACPI_WALK_STATE         *WalkState,
412    ACPI_PARSE_OBJECT       **Op,
413    ACPI_STATUS             Status)
414{
415    ACPI_STATUS             Status2;
416
417
418    ACPI_FUNCTION_TRACE_PTR (PsCompleteOp, WalkState);
419
420
421    /*
422     * Finished one argument of the containing scope
423     */
424    WalkState->ParserState.Scope->ParseScope.ArgCount--;
425
426    /* Close this Op (will result in parse subtree deletion) */
427
428    Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
429    if (ACPI_FAILURE (Status2))
430    {
431        return_ACPI_STATUS (Status2);
432    }
433
434    *Op = NULL;
435
436    switch (Status)
437    {
438    case AE_OK:
439
440        break;
441
442    case AE_CTRL_TRANSFER:
443
444        /* We are about to transfer to a called method */
445
446        WalkState->PrevOp = NULL;
447        WalkState->PrevArgTypes = WalkState->ArgTypes;
448        return_ACPI_STATUS (Status);
449
450    case AE_CTRL_END:
451
452        AcpiPsPopScope (&(WalkState->ParserState), Op,
453            &WalkState->ArgTypes, &WalkState->ArgCount);
454
455        if (*Op)
456        {
457            WalkState->Op = *Op;
458            WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode);
459            WalkState->Opcode = (*Op)->Common.AmlOpcode;
460
461            Status = WalkState->AscendingCallback (WalkState);
462            Status = AcpiPsNextParseState (WalkState, *Op, Status);
463
464            Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
465            if (ACPI_FAILURE (Status2))
466            {
467                return_ACPI_STATUS (Status2);
468            }
469        }
470
471        Status = AE_OK;
472        break;
473
474    case AE_CTRL_BREAK:
475    case AE_CTRL_CONTINUE:
476
477        /* Pop off scopes until we find the While */
478
479        while (!(*Op) || ((*Op)->Common.AmlOpcode != AML_WHILE_OP))
480        {
481            AcpiPsPopScope (&(WalkState->ParserState), Op,
482                &WalkState->ArgTypes, &WalkState->ArgCount);
483        }
484
485        /* Close this iteration of the While loop */
486
487        WalkState->Op = *Op;
488        WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode);
489        WalkState->Opcode = (*Op)->Common.AmlOpcode;
490
491        Status = WalkState->AscendingCallback (WalkState);
492        Status = AcpiPsNextParseState (WalkState, *Op, Status);
493
494        Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
495        if (ACPI_FAILURE (Status2))
496        {
497            return_ACPI_STATUS (Status2);
498        }
499
500        Status = AE_OK;
501        break;
502
503    case AE_CTRL_TERMINATE:
504
505        /* Clean up */
506        do
507        {
508            if (*Op)
509            {
510                Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
511                if (ACPI_FAILURE (Status2))
512                {
513                    return_ACPI_STATUS (Status2);
514                }
515
516                AcpiUtDeleteGenericState (
517                    AcpiUtPopGenericState (&WalkState->ControlState));
518            }
519
520            AcpiPsPopScope (&(WalkState->ParserState), Op,
521                &WalkState->ArgTypes, &WalkState->ArgCount);
522
523        } while (*Op);
524
525        return_ACPI_STATUS (AE_OK);
526
527    default:  /* All other non-AE_OK status */
528
529        do
530        {
531            if (*Op)
532            {
533                Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
534                if (ACPI_FAILURE (Status2))
535                {
536                    return_ACPI_STATUS (Status2);
537                }
538            }
539
540            AcpiPsPopScope (&(WalkState->ParserState), Op,
541                &WalkState->ArgTypes, &WalkState->ArgCount);
542
543        } while (*Op);
544
545
546#if 0
547        /*
548         * TBD: Cleanup parse ops on error
549         */
550        if (*Op == NULL)
551        {
552            AcpiPsPopScope (ParserState, Op,
553                &WalkState->ArgTypes, &WalkState->ArgCount);
554        }
555#endif
556        WalkState->PrevOp = NULL;
557        WalkState->PrevArgTypes = WalkState->ArgTypes;
558        return_ACPI_STATUS (Status);
559    }
560
561    /* This scope complete? */
562
563    if (AcpiPsHasCompletedScope (&(WalkState->ParserState)))
564    {
565        AcpiPsPopScope (&(WalkState->ParserState), Op,
566            &WalkState->ArgTypes, &WalkState->ArgCount);
567        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *Op));
568    }
569    else
570    {
571        *Op = NULL;
572    }
573
574    return_ACPI_STATUS (AE_OK);
575}
576
577
578/*******************************************************************************
579 *
580 * FUNCTION:    AcpiPsCompleteFinalOp
581 *
582 * PARAMETERS:  WalkState           - Current state
583 *              Op                  - Current Op
584 *              Status              - Current parse status before complete last
585 *                                    Op
586 *
587 * RETURN:      Status
588 *
589 * DESCRIPTION: Complete last Op.
590 *
591 ******************************************************************************/
592
593ACPI_STATUS
594AcpiPsCompleteFinalOp (
595    ACPI_WALK_STATE         *WalkState,
596    ACPI_PARSE_OBJECT       *Op,
597    ACPI_STATUS             Status)
598{
599    ACPI_STATUS             Status2;
600
601
602    ACPI_FUNCTION_TRACE_PTR (PsCompleteFinalOp, WalkState);
603
604
605    /*
606     * Complete the last Op (if not completed), and clear the scope stack.
607     * It is easily possible to end an AML "package" with an unbounded number
608     * of open scopes (such as when several ASL blocks are closed with
609     * sequential closing braces). We want to terminate each one cleanly.
610     */
611    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", Op));
612    do
613    {
614        if (Op)
615        {
616            if (WalkState->AscendingCallback != NULL)
617            {
618                WalkState->Op = Op;
619                WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
620                WalkState->Opcode = Op->Common.AmlOpcode;
621
622                Status = WalkState->AscendingCallback (WalkState);
623                Status = AcpiPsNextParseState (WalkState, Op, Status);
624                if (Status == AE_CTRL_PENDING)
625                {
626                    Status = AcpiPsCompleteOp (WalkState, &Op, AE_OK);
627                    if (ACPI_FAILURE (Status))
628                    {
629                        return_ACPI_STATUS (Status);
630                    }
631                }
632
633                if (Status == AE_CTRL_TERMINATE)
634                {
635                    Status = AE_OK;
636
637                    /* Clean up */
638                    do
639                    {
640                        if (Op)
641                        {
642                            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
643                            if (ACPI_FAILURE (Status2))
644                            {
645                                return_ACPI_STATUS (Status2);
646                            }
647                        }
648
649                        AcpiPsPopScope (&(WalkState->ParserState), &Op,
650                            &WalkState->ArgTypes, &WalkState->ArgCount);
651
652                    } while (Op);
653
654                    return_ACPI_STATUS (Status);
655                }
656
657                else if (ACPI_FAILURE (Status))
658                {
659                    /* First error is most important */
660
661                    (void) AcpiPsCompleteThisOp (WalkState, Op);
662                    return_ACPI_STATUS (Status);
663                }
664            }
665
666            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
667            if (ACPI_FAILURE (Status2))
668            {
669                return_ACPI_STATUS (Status2);
670            }
671        }
672
673        AcpiPsPopScope (&(WalkState->ParserState), &Op, &WalkState->ArgTypes,
674            &WalkState->ArgCount);
675
676    } while (Op);
677
678    return_ACPI_STATUS (Status);
679}
680