xref: /netbsd-src/sys/external/bsd/acpica/dist/parser/psloop.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: psloop - Main AML parse loop
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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: %8.8X pass %u\n",
179             WalkState->ArgCount, WalkState->PassNumber));
180 
181         /*
182          * This case handles the legacy option that groups all module-level
183          * code blocks together and defers execution until all of the tables
184          * are loaded. Execute all of these blocks at this time.
185          * Execute any module-level code that was detected during the table
186          * load phase.
187          *
188          * Note: this option is deprecated and will be eliminated in the
189          * future. Use of this option can cause problems with AML code that
190          * depends upon in-order immediate execution of module-level code.
191          */
192         if (AcpiGbl_GroupModuleLevelCode &&
193             (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
194             ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
195         {
196             /*
197              * We want to skip If/Else/While constructs during Pass1 because we
198              * want to actually conditionally execute the code during Pass2.
199              *
200              * Except for disassembly, where we always want to walk the
201              * If/Else/While packages
202              */
203             switch (Op->Common.AmlOpcode)
204             {
205             case AML_IF_OP:
206             case AML_ELSE_OP:
207             case AML_WHILE_OP:
208                 /*
209                  * Currently supported module-level opcodes are:
210                  * IF/ELSE/WHILE. These appear to be the most common,
211                  * and easiest to support since they open an AML
212                  * package.
213                  */
214                 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
215                 {
216                     AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
217                         (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
218                         WalkState->OwnerId);
219                 }
220 
221                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
222                     "Pass1: Skipping an If/Else/While body\n"));
223 
224                 /* Skip body of if/else/while in pass 1 */
225 
226                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
227                 WalkState->ArgCount = 0;
228                 break;
229 
230             default:
231                 /*
232                  * Check for an unsupported executable opcode at module
233                  * level. We must be in PASS1, the parent must be a SCOPE,
234                  * The opcode class must be EXECUTE, and the opcode must
235                  * not be an argument to another opcode.
236                  */
237                 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
238                     (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
239                 {
240                     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
241                     if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
242                         (!Arg))
243                     {
244                         ACPI_WARNING ((AE_INFO,
245                             "Unsupported module-level executable opcode "
246                             "0x%.2X at table offset 0x%.4X",
247                             Op->Common.AmlOpcode,
248                             (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
249                                 WalkState->ParserState.AmlStart) +
250                                 sizeof (ACPI_TABLE_HEADER))));
251                     }
252                 }
253                 break;
254             }
255         }
256 
257         /* Special processing for certain opcodes */
258 
259         switch (Op->Common.AmlOpcode)
260         {
261         case AML_METHOD_OP:
262             /*
263              * Skip parsing of control method because we don't have enough
264              * info in the first pass to parse it correctly.
265              *
266              * Save the length and address of the body
267              */
268             Op->Named.Data = WalkState->ParserState.Aml;
269             Op->Named.Length = (UINT32)
270                 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);
271 
272             /* Skip body of method */
273 
274             WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
275             WalkState->ArgCount = 0;
276             break;
277 
278         case AML_BUFFER_OP:
279         case AML_PACKAGE_OP:
280         case AML_VARIABLE_PACKAGE_OP:
281 
282             if ((Op->Common.Parent) &&
283                 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
284                 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
285             {
286                 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
287                     "Setup Package/Buffer: Pass %u, AML Ptr: %p\n",
288                     WalkState->PassNumber, AmlOpStart));
289 
290                 /*
291                  * Skip parsing of Buffers and Packages because we don't have
292                  * enough info in the first pass to parse them correctly.
293                  */
294                 Op->Named.Data = AmlOpStart;
295                 Op->Named.Length = (UINT32)
296                     (WalkState->ParserState.PkgEnd - AmlOpStart);
297 
298                 /* Skip body */
299 
300                 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
301                 WalkState->ArgCount = 0;
302             }
303             break;
304 
305         case AML_WHILE_OP:
306 
307             if (WalkState->ControlState)
308             {
309                 WalkState->ControlState->Control.PackageEnd =
310                     WalkState->ParserState.PkgEnd;
311             }
312             break;
313 
314         default:
315 
316             /* No action for all other opcodes */
317 
318             break;
319         }
320 
321         break;
322     }
323 
324     return_ACPI_STATUS (AE_OK);
325 }
326 
327 
328 /*******************************************************************************
329  *
330  * FUNCTION:    AcpiPsLinkModuleCode
331  *
332  * PARAMETERS:  ParentOp            - Parent parser op
333  *              AmlStart            - Pointer to the AML
334  *              AmlLength           - Length of executable AML
335  *              OwnerId             - OwnerId of module level code
336  *
337  * RETURN:      None.
338  *
339  * DESCRIPTION: Wrap the module-level code with a method object and link the
340  *              object to the global list. Note, the mutex field of the method
341  *              object is used to link multiple module-level code objects.
342  *
343  * NOTE: In this legacy option, each block of detected executable AML
344  * code that is outside of any control method is wrapped with a temporary
345  * control method object and placed on a global list below.
346  *
347  * This function executes the module-level code for all tables only after
348  * all of the tables have been loaded. It is a legacy option and is
349  * not compatible with other ACPI implementations. See AcpiNsLoadTable.
350  *
351  * This function will be removed when the legacy option is removed.
352  *
353  ******************************************************************************/
354 
355 static void
356 AcpiPsLinkModuleCode (
357     ACPI_PARSE_OBJECT       *ParentOp,
358     UINT8                   *AmlStart,
359     UINT32                  AmlLength,
360     ACPI_OWNER_ID           OwnerId)
361 {
362     ACPI_OPERAND_OBJECT     *Prev;
363     ACPI_OPERAND_OBJECT     *Next;
364     ACPI_OPERAND_OBJECT     *MethodObj;
365     ACPI_NAMESPACE_NODE     *ParentNode;
366 
367 
368     ACPI_FUNCTION_TRACE (PsLinkModuleCode);
369 
370 
371     /* Get the tail of the list */
372 
373     Prev = Next = AcpiGbl_ModuleCodeList;
374     while (Next)
375     {
376         Prev = Next;
377         Next = Next->Method.Mutex;
378     }
379 
380     /*
381      * Insert the module level code into the list. Merge it if it is
382      * adjacent to the previous element.
383      */
384     if (!Prev ||
385        ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
386     {
387         /* Create, initialize, and link a new temporary method object */
388 
389         MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
390         if (!MethodObj)
391         {
392             return_VOID;
393         }
394 
395         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
396             "Create/Link new code block: %p\n", MethodObj));
397 
398         if (ParentOp->Common.Node)
399         {
400             ParentNode = ParentOp->Common.Node;
401         }
402         else
403         {
404             ParentNode = AcpiGbl_RootNode;
405         }
406 
407         MethodObj->Method.AmlStart = AmlStart;
408         MethodObj->Method.AmlLength = AmlLength;
409         MethodObj->Method.OwnerId = OwnerId;
410         MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL;
411 
412         /*
413          * Save the parent node in NextObject. This is cheating, but we
414          * don't want to expand the method object.
415          */
416         MethodObj->Method.NextObject =
417             ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode);
418 
419         if (!Prev)
420         {
421             AcpiGbl_ModuleCodeList = MethodObj;
422         }
423         else
424         {
425             Prev->Method.Mutex = MethodObj;
426         }
427     }
428     else
429     {
430         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
431             "Appending to existing code block: %p\n", Prev));
432 
433         Prev->Method.AmlLength += AmlLength;
434     }
435 
436     return_VOID;
437 }
438 
439 /*******************************************************************************
440  *
441  * FUNCTION:    AcpiPsParseLoop
442  *
443  * PARAMETERS:  WalkState           - Current state
444  *
445  * RETURN:      Status
446  *
447  * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
448  *              a tree of ops.
449  *
450  ******************************************************************************/
451 
452 ACPI_STATUS
453 AcpiPsParseLoop (
454     ACPI_WALK_STATE         *WalkState)
455 {
456     ACPI_STATUS             Status = AE_OK;
457     ACPI_PARSE_OBJECT       *Op = NULL;     /* current op */
458     ACPI_PARSE_STATE        *ParserState;
459     UINT8                   *AmlOpStart = NULL;
460 
461 
462     ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);
463 
464 
465     if (WalkState->DescendingCallback == NULL)
466     {
467         return_ACPI_STATUS (AE_BAD_PARAMETER);
468     }
469 
470     ParserState = &WalkState->ParserState;
471     WalkState->ArgTypes = 0;
472 
473 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
474 
475     if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)
476     {
477         /* We are restarting a preempted control method */
478 
479         if (AcpiPsHasCompletedScope (ParserState))
480         {
481             /*
482              * We must check if a predicate to an IF or WHILE statement
483              * was just completed
484              */
485             if ((ParserState->Scope->ParseScope.Op) &&
486                ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||
487                 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&
488                 (WalkState->ControlState) &&
489                 (WalkState->ControlState->Common.State ==
490                     ACPI_CONTROL_PREDICATE_EXECUTING))
491             {
492                 /*
493                  * A predicate was just completed, get the value of the
494                  * predicate and branch based on that value
495                  */
496                 WalkState->Op = NULL;
497                 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));
498                 if (ACPI_FAILURE (Status) &&
499                     ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
500                 {
501                     if (Status == AE_AML_NO_RETURN_VALUE)
502                     {
503                         ACPI_EXCEPTION ((AE_INFO, Status,
504                             "Invoked method did not return a value"));
505                     }
506 
507                     ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));
508                     return_ACPI_STATUS (Status);
509                 }
510 
511                 Status = AcpiPsNextParseState (WalkState, Op, Status);
512             }
513 
514             AcpiPsPopScope (ParserState, &Op,
515                 &WalkState->ArgTypes, &WalkState->ArgCount);
516             ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
517         }
518         else if (WalkState->PrevOp)
519         {
520             /* We were in the middle of an op */
521 
522             Op = WalkState->PrevOp;
523             WalkState->ArgTypes = WalkState->PrevArgTypes;
524         }
525     }
526 #endif
527 
528     /* Iterative parsing loop, while there is more AML to process: */
529 
530     while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
531     {
532         ASL_CV_CAPTURE_COMMENTS (WalkState);
533 
534         AmlOpStart = ParserState->Aml;
535         if (!Op)
536         {
537             Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
538             if (ACPI_FAILURE (Status))
539             {
540                 if (Status == AE_CTRL_PARSE_CONTINUE)
541                 {
542                     continue;
543                 }
544 
545                 if (Status == AE_CTRL_PARSE_PENDING)
546                 {
547                     Status = AE_OK;
548                 }
549 
550                 if (Status == AE_CTRL_TERMINATE)
551                 {
552                     return_ACPI_STATUS (Status);
553                 }
554 
555                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
556                 if (ACPI_FAILURE (Status))
557                 {
558                     return_ACPI_STATUS (Status);
559                 }
560 
561                 continue;
562             }
563 
564             AcpiExStartTraceOpcode (Op, WalkState);
565         }
566 
567         /*
568          * Start ArgCount at zero because we don't know if there are
569          * any args yet
570          */
571         WalkState->ArgCount = 0;
572 
573         switch (Op->Common.AmlOpcode)
574         {
575         case AML_BYTE_OP:
576         case AML_WORD_OP:
577         case AML_DWORD_OP:
578         case AML_QWORD_OP:
579 
580             break;
581 
582         default:
583 
584             ASL_CV_CAPTURE_COMMENTS (WalkState);
585             break;
586         }
587 
588         /* Are there any arguments that must be processed? */
589 
590         if (WalkState->ArgTypes)
591         {
592             /* Get arguments */
593 
594             Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);
595             if (ACPI_FAILURE (Status))
596             {
597                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
598                 if (ACPI_FAILURE (Status))
599                 {
600                     return_ACPI_STATUS (Status);
601                 }
602 
603                 continue;
604             }
605         }
606 
607         /* Check for arguments that need to be processed */
608 
609         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
610             "Parseloop: argument count: %8.8X\n", WalkState->ArgCount));
611 
612         if (WalkState->ArgCount)
613         {
614             /*
615              * There are arguments (complex ones), push Op and
616              * prepare for argument
617              */
618             Status = AcpiPsPushScope (ParserState, Op,
619                 WalkState->ArgTypes, WalkState->ArgCount);
620             if (ACPI_FAILURE (Status))
621             {
622                 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
623                 if (ACPI_FAILURE (Status))
624                 {
625                     return_ACPI_STATUS (Status);
626                 }
627 
628                 continue;
629             }
630 
631             Op = NULL;
632             continue;
633         }
634 
635         /*
636          * All arguments have been processed -- Op is complete,
637          * prepare for next
638          */
639         WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
640         if (WalkState->OpInfo->Flags & AML_NAMED)
641         {
642             if (Op->Common.AmlOpcode == AML_REGION_OP ||
643                 Op->Common.AmlOpcode == AML_DATA_REGION_OP)
644             {
645                 /*
646                  * Skip parsing of control method or opregion body,
647                  * because we don't have enough info in the first pass
648                  * to parse them correctly.
649                  *
650                  * Completed parsing an OpRegion declaration, we now
651                  * know the length.
652                  */
653                 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
654             }
655         }
656 
657         if (WalkState->OpInfo->Flags & AML_CREATE)
658         {
659             /*
660              * Backup to beginning of CreateXXXfield declaration (1 for
661              * Opcode)
662              *
663              * BodyLength is unknown until we parse the body
664              */
665             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
666         }
667 
668         if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)
669         {
670             /*
671              * Backup to beginning of BankField declaration
672              *
673              * BodyLength is unknown until we parse the body
674              */
675             Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
676         }
677 
678         /* This op complete, notify the dispatcher */
679 
680         if (WalkState->AscendingCallback != NULL)
681         {
682             WalkState->Op = Op;
683             WalkState->Opcode = Op->Common.AmlOpcode;
684 
685             Status = WalkState->AscendingCallback (WalkState);
686             Status = AcpiPsNextParseState (WalkState, Op, Status);
687             if (Status == AE_CTRL_PENDING)
688             {
689                 Status = AE_OK;
690             }
691         }
692 
693         Status = AcpiPsCompleteOp (WalkState, &Op, Status);
694         if (ACPI_FAILURE (Status))
695         {
696             return_ACPI_STATUS (Status);
697         }
698 
699     } /* while ParserState->Aml */
700 
701     Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);
702     return_ACPI_STATUS (Status);
703 }
704