psobject.c revision 244971
1/******************************************************************************
2 *
3 * Module Name: psobject - Support for parse objects
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2012, 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 "acpi.h"
46#include "accommon.h"
47#include "acparser.h"
48#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        break;
440
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
451    case AE_CTRL_END:
452
453        AcpiPsPopScope (&(WalkState->ParserState), Op,
454            &WalkState->ArgTypes, &WalkState->ArgCount);
455
456        if (*Op)
457        {
458            WalkState->Op = *Op;
459            WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode);
460            WalkState->Opcode = (*Op)->Common.AmlOpcode;
461
462            Status = WalkState->AscendingCallback (WalkState);
463            Status = AcpiPsNextParseState (WalkState, *Op, Status);
464
465            Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
466            if (ACPI_FAILURE (Status2))
467            {
468                return_ACPI_STATUS (Status2);
469            }
470        }
471
472        Status = AE_OK;
473        break;
474
475
476    case AE_CTRL_BREAK:
477    case AE_CTRL_CONTINUE:
478
479        /* Pop off scopes until we find the While */
480
481        while (!(*Op) || ((*Op)->Common.AmlOpcode != AML_WHILE_OP))
482        {
483            AcpiPsPopScope (&(WalkState->ParserState), Op,
484                &WalkState->ArgTypes, &WalkState->ArgCount);
485        }
486
487        /* Close this iteration of the While loop */
488
489        WalkState->Op = *Op;
490        WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode);
491        WalkState->Opcode = (*Op)->Common.AmlOpcode;
492
493        Status = WalkState->AscendingCallback (WalkState);
494        Status = AcpiPsNextParseState (WalkState, *Op, Status);
495
496        Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
497        if (ACPI_FAILURE (Status2))
498        {
499            return_ACPI_STATUS (Status2);
500        }
501
502        Status = AE_OK;
503        break;
504
505
506    case AE_CTRL_TERMINATE:
507
508        /* Clean up */
509        do
510        {
511            if (*Op)
512            {
513                Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
514                if (ACPI_FAILURE (Status2))
515                {
516                    return_ACPI_STATUS (Status2);
517                }
518
519                AcpiUtDeleteGenericState (
520                    AcpiUtPopGenericState (&WalkState->ControlState));
521            }
522
523            AcpiPsPopScope (&(WalkState->ParserState), Op,
524                &WalkState->ArgTypes, &WalkState->ArgCount);
525
526        } while (*Op);
527
528        return_ACPI_STATUS (AE_OK);
529
530
531    default:  /* All other non-AE_OK status */
532
533        do
534        {
535            if (*Op)
536            {
537                Status2 = AcpiPsCompleteThisOp (WalkState, *Op);
538                if (ACPI_FAILURE (Status2))
539                {
540                    return_ACPI_STATUS (Status2);
541                }
542            }
543
544            AcpiPsPopScope (&(WalkState->ParserState), Op,
545                &WalkState->ArgTypes, &WalkState->ArgCount);
546
547        } while (*Op);
548
549
550#if 0
551        /*
552         * TBD: Cleanup parse ops on error
553         */
554        if (*Op == NULL)
555        {
556            AcpiPsPopScope (ParserState, Op,
557                &WalkState->ArgTypes, &WalkState->ArgCount);
558        }
559#endif
560        WalkState->PrevOp = NULL;
561        WalkState->PrevArgTypes = WalkState->ArgTypes;
562        return_ACPI_STATUS (Status);
563    }
564
565    /* This scope complete? */
566
567    if (AcpiPsHasCompletedScope (&(WalkState->ParserState)))
568    {
569        AcpiPsPopScope (&(WalkState->ParserState), Op,
570            &WalkState->ArgTypes, &WalkState->ArgCount);
571        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *Op));
572    }
573    else
574    {
575        *Op = NULL;
576    }
577
578    return_ACPI_STATUS (AE_OK);
579}
580
581
582/*******************************************************************************
583 *
584 * FUNCTION:    AcpiPsCompleteFinalOp
585 *
586 * PARAMETERS:  WalkState           - Current state
587 *              Op                  - Current Op
588 *              Status              - Current parse status before complete last
589 *                                    Op
590 *
591 * RETURN:      Status
592 *
593 * DESCRIPTION: Complete last Op.
594 *
595 ******************************************************************************/
596
597ACPI_STATUS
598AcpiPsCompleteFinalOp (
599    ACPI_WALK_STATE         *WalkState,
600    ACPI_PARSE_OBJECT       *Op,
601    ACPI_STATUS             Status)
602{
603    ACPI_STATUS             Status2;
604
605
606    ACPI_FUNCTION_TRACE_PTR (PsCompleteFinalOp, WalkState);
607
608
609    /*
610     * Complete the last Op (if not completed), and clear the scope stack.
611     * It is easily possible to end an AML "package" with an unbounded number
612     * of open scopes (such as when several ASL blocks are closed with
613     * sequential closing braces). We want to terminate each one cleanly.
614     */
615    ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", Op));
616    do
617    {
618        if (Op)
619        {
620            if (WalkState->AscendingCallback != NULL)
621            {
622                WalkState->Op = Op;
623                WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
624                WalkState->Opcode = Op->Common.AmlOpcode;
625
626                Status = WalkState->AscendingCallback (WalkState);
627                Status = AcpiPsNextParseState (WalkState, Op, Status);
628                if (Status == AE_CTRL_PENDING)
629                {
630                    Status = AcpiPsCompleteOp (WalkState, &Op, AE_OK);
631                    if (ACPI_FAILURE (Status))
632                    {
633                        return_ACPI_STATUS (Status);
634                    }
635                }
636
637                if (Status == AE_CTRL_TERMINATE)
638                {
639                    Status = AE_OK;
640
641                    /* Clean up */
642                    do
643                    {
644                        if (Op)
645                        {
646                            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
647                            if (ACPI_FAILURE (Status2))
648                            {
649                                return_ACPI_STATUS (Status2);
650                            }
651                        }
652
653                        AcpiPsPopScope (&(WalkState->ParserState), &Op,
654                            &WalkState->ArgTypes, &WalkState->ArgCount);
655
656                    } while (Op);
657
658                    return_ACPI_STATUS (Status);
659                }
660
661                else if (ACPI_FAILURE (Status))
662                {
663                    /* First error is most important */
664
665                    (void) AcpiPsCompleteThisOp (WalkState, Op);
666                    return_ACPI_STATUS (Status);
667                }
668            }
669
670            Status2 = AcpiPsCompleteThisOp (WalkState, Op);
671            if (ACPI_FAILURE (Status2))
672            {
673                return_ACPI_STATUS (Status2);
674            }
675        }
676
677        AcpiPsPopScope (&(WalkState->ParserState), &Op, &WalkState->ArgTypes,
678            &WalkState->ArgCount);
679
680    } while (Op);
681
682    return_ACPI_STATUS (Status);
683}
684