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