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