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