1 | /****************************************************************************** |
2 | * |
3 | * Module Name: psparse - Parser top level AML parse routines |
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, |
46 | * like Perl, do. Parsing is done by hand rather than with a YACC |
47 | * generated parser to tightly constrain stack and dynamic memory |
48 | * usage. At the same time, parsing is kept flexible and the code |
49 | * fairly compact by parsing based on a list of AML opcode |
50 | * templates in AmlOpInfo[] |
51 | */ |
52 | |
53 | #include "acpi.h" |
54 | #include "accommon.h" |
55 | #include "acparser.h" |
56 | #include "acdispat.h" |
57 | #include "amlcode.h" |
58 | #include "acinterp.h" |
59 | |
60 | #define _COMPONENT ACPI_PARSER |
61 | ACPI_MODULE_NAME ("psparse" ) |
62 | |
63 | |
64 | /******************************************************************************* |
65 | * |
66 | * FUNCTION: AcpiPsGetOpcodeSize |
67 | * |
68 | * PARAMETERS: Opcode - An AML opcode |
69 | * |
70 | * RETURN: Size of the opcode, in bytes (1 or 2) |
71 | * |
72 | * DESCRIPTION: Get the size of the current opcode. |
73 | * |
74 | ******************************************************************************/ |
75 | |
76 | UINT32 |
77 | AcpiPsGetOpcodeSize ( |
78 | UINT32 Opcode) |
79 | { |
80 | |
81 | /* Extended (2-byte) opcode if > 255 */ |
82 | |
83 | if (Opcode > 0x00FF) |
84 | { |
85 | return (2); |
86 | } |
87 | |
88 | /* Otherwise, just a single byte opcode */ |
89 | |
90 | return (1); |
91 | } |
92 | |
93 | |
94 | /******************************************************************************* |
95 | * |
96 | * FUNCTION: AcpiPsPeekOpcode |
97 | * |
98 | * PARAMETERS: ParserState - A parser state object |
99 | * |
100 | * RETURN: Next AML opcode |
101 | * |
102 | * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) |
103 | * |
104 | ******************************************************************************/ |
105 | |
106 | UINT16 |
107 | AcpiPsPeekOpcode ( |
108 | ACPI_PARSE_STATE *ParserState) |
109 | { |
110 | UINT8 *Aml; |
111 | UINT16 Opcode; |
112 | |
113 | |
114 | Aml = ParserState->Aml; |
115 | Opcode = (UINT16) ACPI_GET8 (Aml); |
116 | |
117 | if (Opcode == AML_EXTENDED_OP_PREFIX) |
118 | { |
119 | /* Extended opcode, get the second opcode byte */ |
120 | |
121 | Aml++; |
122 | Opcode = (UINT16) ((Opcode << 8) | ACPI_GET8 (Aml)); |
123 | } |
124 | |
125 | return (Opcode); |
126 | } |
127 | |
128 | |
129 | /******************************************************************************* |
130 | * |
131 | * FUNCTION: AcpiPsCompleteThisOp |
132 | * |
133 | * PARAMETERS: WalkState - Current State |
134 | * Op - Op to complete |
135 | * |
136 | * RETURN: Status |
137 | * |
138 | * DESCRIPTION: Perform any cleanup at the completion of an Op. |
139 | * |
140 | ******************************************************************************/ |
141 | |
142 | ACPI_STATUS |
143 | AcpiPsCompleteThisOp ( |
144 | ACPI_WALK_STATE *WalkState, |
145 | ACPI_PARSE_OBJECT *Op) |
146 | { |
147 | ACPI_PARSE_OBJECT *Prev; |
148 | ACPI_PARSE_OBJECT *Next; |
149 | const ACPI_OPCODE_INFO *ParentInfo; |
150 | ACPI_PARSE_OBJECT *ReplacementOp = NULL; |
151 | ACPI_STATUS Status = AE_OK; |
152 | |
153 | |
154 | ACPI_FUNCTION_TRACE_PTR (PsCompleteThisOp, Op); |
155 | |
156 | |
157 | /* Check for null Op, can happen if AML code is corrupt */ |
158 | |
159 | if (!Op) |
160 | { |
161 | return_ACPI_STATUS (AE_OK); /* OK for now */ |
162 | } |
163 | |
164 | AcpiExStopTraceOpcode (Op, WalkState); |
165 | |
166 | /* Delete this op and the subtree below it if asked to */ |
167 | |
168 | if (((WalkState->ParseFlags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) || |
169 | (WalkState->OpInfo->Class == AML_CLASS_ARGUMENT)) |
170 | { |
171 | return_ACPI_STATUS (AE_OK); |
172 | } |
173 | |
174 | /* Make sure that we only delete this subtree */ |
175 | |
176 | if (Op->Common.Parent) |
177 | { |
178 | Prev = Op->Common.Parent->Common.Value.Arg; |
179 | if (!Prev) |
180 | { |
181 | /* Nothing more to do */ |
182 | |
183 | goto Cleanup; |
184 | } |
185 | |
186 | /* |
187 | * Check if we need to replace the operator and its subtree |
188 | * with a return value op (placeholder op) |
189 | */ |
190 | ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); |
191 | |
192 | switch (ParentInfo->Class) |
193 | { |
194 | case AML_CLASS_CONTROL: |
195 | |
196 | break; |
197 | |
198 | case AML_CLASS_CREATE: |
199 | /* |
200 | * These opcodes contain TermArg operands. The current |
201 | * op must be replaced by a placeholder return op |
202 | */ |
203 | ReplacementOp = AcpiPsAllocOp ( |
204 | AML_INT_RETURN_VALUE_OP, Op->Common.Aml); |
205 | if (!ReplacementOp) |
206 | { |
207 | Status = AE_NO_MEMORY; |
208 | } |
209 | break; |
210 | |
211 | case AML_CLASS_NAMED_OBJECT: |
212 | /* |
213 | * These opcodes contain TermArg operands. The current |
214 | * op must be replaced by a placeholder return op |
215 | */ |
216 | if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || |
217 | (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || |
218 | (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || |
219 | (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || |
220 | (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP) || |
221 | (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) |
222 | { |
223 | ReplacementOp = AcpiPsAllocOp ( |
224 | AML_INT_RETURN_VALUE_OP, Op->Common.Aml); |
225 | if (!ReplacementOp) |
226 | { |
227 | Status = AE_NO_MEMORY; |
228 | } |
229 | } |
230 | else if ((Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && |
231 | (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) |
232 | { |
233 | if ((Op->Common.AmlOpcode == AML_BUFFER_OP) || |
234 | (Op->Common.AmlOpcode == AML_PACKAGE_OP) || |
235 | (Op->Common.AmlOpcode == AML_VAR_PACKAGE_OP)) |
236 | { |
237 | ReplacementOp = AcpiPsAllocOp (Op->Common.AmlOpcode, |
238 | Op->Common.Aml); |
239 | if (!ReplacementOp) |
240 | { |
241 | Status = AE_NO_MEMORY; |
242 | } |
243 | else |
244 | { |
245 | ReplacementOp->Named.Data = Op->Named.Data; |
246 | ReplacementOp->Named.Length = Op->Named.Length; |
247 | } |
248 | } |
249 | } |
250 | break; |
251 | |
252 | default: |
253 | |
254 | ReplacementOp = AcpiPsAllocOp ( |
255 | AML_INT_RETURN_VALUE_OP, Op->Common.Aml); |
256 | if (!ReplacementOp) |
257 | { |
258 | Status = AE_NO_MEMORY; |
259 | } |
260 | } |
261 | |
262 | /* We must unlink this op from the parent tree */ |
263 | |
264 | if (Prev == Op) |
265 | { |
266 | /* This op is the first in the list */ |
267 | |
268 | if (ReplacementOp) |
269 | { |
270 | ReplacementOp->Common.Parent = Op->Common.Parent; |
271 | ReplacementOp->Common.Value.Arg = NULL; |
272 | ReplacementOp->Common.Node = Op->Common.Node; |
273 | Op->Common.Parent->Common.Value.Arg = ReplacementOp; |
274 | ReplacementOp->Common.Next = Op->Common.Next; |
275 | } |
276 | else |
277 | { |
278 | Op->Common.Parent->Common.Value.Arg = Op->Common.Next; |
279 | } |
280 | } |
281 | |
282 | /* Search the parent list */ |
283 | |
284 | else while (Prev) |
285 | { |
286 | /* Traverse all siblings in the parent's argument list */ |
287 | |
288 | Next = Prev->Common.Next; |
289 | if (Next == Op) |
290 | { |
291 | if (ReplacementOp) |
292 | { |
293 | ReplacementOp->Common.Parent = Op->Common.Parent; |
294 | ReplacementOp->Common.Value.Arg = NULL; |
295 | ReplacementOp->Common.Node = Op->Common.Node; |
296 | Prev->Common.Next = ReplacementOp; |
297 | ReplacementOp->Common.Next = Op->Common.Next; |
298 | Next = NULL; |
299 | } |
300 | else |
301 | { |
302 | Prev->Common.Next = Op->Common.Next; |
303 | Next = NULL; |
304 | } |
305 | } |
306 | Prev = Next; |
307 | } |
308 | } |
309 | |
310 | |
311 | Cleanup: |
312 | |
313 | /* Now we can actually delete the subtree rooted at Op */ |
314 | |
315 | AcpiPsDeleteParseTree (Op); |
316 | return_ACPI_STATUS (Status); |
317 | } |
318 | |
319 | |
320 | /******************************************************************************* |
321 | * |
322 | * FUNCTION: AcpiPsNextParseState |
323 | * |
324 | * PARAMETERS: WalkState - Current state |
325 | * Op - Current parse op |
326 | * CallbackStatus - Status from previous operation |
327 | * |
328 | * RETURN: Status |
329 | * |
330 | * DESCRIPTION: Update the parser state based upon the return exception from |
331 | * the parser callback. |
332 | * |
333 | ******************************************************************************/ |
334 | |
335 | ACPI_STATUS |
336 | AcpiPsNextParseState ( |
337 | ACPI_WALK_STATE *WalkState, |
338 | ACPI_PARSE_OBJECT *Op, |
339 | ACPI_STATUS CallbackStatus) |
340 | { |
341 | ACPI_PARSE_STATE *ParserState = &WalkState->ParserState; |
342 | ACPI_STATUS Status = AE_CTRL_PENDING; |
343 | |
344 | |
345 | ACPI_FUNCTION_TRACE_PTR (PsNextParseState, Op); |
346 | |
347 | |
348 | switch (CallbackStatus) |
349 | { |
350 | case AE_CTRL_TERMINATE: |
351 | /* |
352 | * A control method was terminated via a RETURN statement. |
353 | * The walk of this method is complete. |
354 | */ |
355 | ParserState->Aml = ParserState->AmlEnd; |
356 | Status = AE_CTRL_TERMINATE; |
357 | break; |
358 | |
359 | case AE_CTRL_BREAK: |
360 | |
361 | ParserState->Aml = WalkState->AmlLastWhile; |
362 | WalkState->ControlState->Common.Value = FALSE; |
363 | Status = AE_CTRL_BREAK; |
364 | break; |
365 | |
366 | case AE_CTRL_CONTINUE: |
367 | |
368 | ParserState->Aml = WalkState->AmlLastWhile; |
369 | Status = AE_CTRL_CONTINUE; |
370 | break; |
371 | |
372 | case AE_CTRL_PENDING: |
373 | |
374 | ParserState->Aml = WalkState->AmlLastWhile; |
375 | break; |
376 | |
377 | #if 0 |
378 | case AE_CTRL_SKIP: |
379 | |
380 | ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; |
381 | Status = AE_OK; |
382 | break; |
383 | #endif |
384 | |
385 | case AE_CTRL_TRUE: |
386 | /* |
387 | * Predicate of an IF was true, and we are at the matching ELSE. |
388 | * Just close out this package |
389 | */ |
390 | ParserState->Aml = AcpiPsGetNextPackageEnd (ParserState); |
391 | Status = AE_CTRL_PENDING; |
392 | break; |
393 | |
394 | case AE_CTRL_FALSE: |
395 | /* |
396 | * Either an IF/WHILE Predicate was false or we encountered a BREAK |
397 | * opcode. In both cases, we do not execute the rest of the |
398 | * package; We simply close out the parent (finishing the walk of |
399 | * this branch of the tree) and continue execution at the parent |
400 | * level. |
401 | */ |
402 | ParserState->Aml = ParserState->Scope->ParseScope.PkgEnd; |
403 | |
404 | /* In the case of a BREAK, just force a predicate (if any) to FALSE */ |
405 | |
406 | WalkState->ControlState->Common.Value = FALSE; |
407 | Status = AE_CTRL_END; |
408 | break; |
409 | |
410 | case AE_CTRL_TRANSFER: |
411 | |
412 | /* A method call (invocation) -- transfer control */ |
413 | |
414 | Status = AE_CTRL_TRANSFER; |
415 | WalkState->PrevOp = Op; |
416 | WalkState->MethodCallOp = Op; |
417 | WalkState->MethodCallNode = (Op->Common.Value.Arg)->Common.Node; |
418 | |
419 | /* Will return value (if any) be used by the caller? */ |
420 | |
421 | WalkState->ReturnUsed = AcpiDsIsResultUsed (Op, WalkState); |
422 | break; |
423 | |
424 | default: |
425 | |
426 | Status = CallbackStatus; |
427 | if ((CallbackStatus & AE_CODE_MASK) == AE_CODE_CONTROL) |
428 | { |
429 | Status = AE_OK; |
430 | } |
431 | break; |
432 | } |
433 | |
434 | return_ACPI_STATUS (Status); |
435 | } |
436 | |
437 | |
438 | /******************************************************************************* |
439 | * |
440 | * FUNCTION: AcpiPsParseAml |
441 | * |
442 | * PARAMETERS: WalkState - Current state |
443 | * |
444 | * |
445 | * RETURN: Status |
446 | * |
447 | * DESCRIPTION: Parse raw AML and return a tree of ops |
448 | * |
449 | ******************************************************************************/ |
450 | |
451 | ACPI_STATUS |
452 | AcpiPsParseAml ( |
453 | ACPI_WALK_STATE *WalkState) |
454 | { |
455 | ACPI_STATUS Status; |
456 | ACPI_THREAD_STATE *Thread; |
457 | ACPI_THREAD_STATE *PrevWalkList = AcpiGbl_CurrentWalkList; |
458 | ACPI_WALK_STATE *PreviousWalkState; |
459 | |
460 | |
461 | ACPI_FUNCTION_TRACE (PsParseAml); |
462 | |
463 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
464 | "Entered with WalkState=%p Aml=%p size=%X\n" , |
465 | WalkState, WalkState->ParserState.Aml, |
466 | WalkState->ParserState.AmlSize)); |
467 | |
468 | if (!WalkState->ParserState.Aml) |
469 | { |
470 | return_ACPI_STATUS (AE_NULL_OBJECT); |
471 | } |
472 | |
473 | /* Create and initialize a new thread state */ |
474 | |
475 | Thread = AcpiUtCreateThreadState (); |
476 | if (!Thread) |
477 | { |
478 | if (WalkState->MethodDesc) |
479 | { |
480 | /* Executing a control method - additional cleanup */ |
481 | |
482 | AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); |
483 | } |
484 | |
485 | AcpiDsDeleteWalkState (WalkState); |
486 | return_ACPI_STATUS (AE_NO_MEMORY); |
487 | } |
488 | |
489 | WalkState->Thread = Thread; |
490 | |
491 | /* |
492 | * If executing a method, the starting SyncLevel is this method's |
493 | * SyncLevel |
494 | */ |
495 | if (WalkState->MethodDesc) |
496 | { |
497 | WalkState->Thread->CurrentSyncLevel = |
498 | WalkState->MethodDesc->Method.SyncLevel; |
499 | } |
500 | |
501 | AcpiDsPushWalkState (WalkState, Thread); |
502 | |
503 | /* |
504 | * This global allows the AML debugger to get a handle to the currently |
505 | * executing control method. |
506 | */ |
507 | AcpiGbl_CurrentWalkList = Thread; |
508 | |
509 | /* |
510 | * Execute the walk loop as long as there is a valid Walk State. This |
511 | * handles nested control method invocations without recursion. |
512 | */ |
513 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n" , WalkState)); |
514 | |
515 | Status = AE_OK; |
516 | while (WalkState) |
517 | { |
518 | if (ACPI_SUCCESS (Status)) |
519 | { |
520 | /* |
521 | * The ParseLoop executes AML until the method terminates |
522 | * or calls another method. |
523 | */ |
524 | Status = AcpiPsParseLoop (WalkState); |
525 | } |
526 | |
527 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
528 | "Completed one call to walk loop, %s State=%p\n" , |
529 | AcpiFormatException (Status), WalkState)); |
530 | |
531 | if (Status == AE_CTRL_TRANSFER) |
532 | { |
533 | /* |
534 | * A method call was detected. |
535 | * Transfer control to the called control method |
536 | */ |
537 | Status = AcpiDsCallControlMethod (Thread, WalkState, NULL); |
538 | if (ACPI_FAILURE (Status)) |
539 | { |
540 | Status = AcpiDsMethodError (Status, WalkState); |
541 | } |
542 | |
543 | /* |
544 | * If the transfer to the new method method call worked |
545 | *, a new walk state was created -- get it |
546 | */ |
547 | WalkState = AcpiDsGetCurrentWalkState (Thread); |
548 | continue; |
549 | } |
550 | else if (Status == AE_CTRL_TERMINATE) |
551 | { |
552 | Status = AE_OK; |
553 | } |
554 | else if ((Status != AE_OK) && (WalkState->MethodDesc)) |
555 | { |
556 | /* Either the method parse or actual execution failed */ |
557 | |
558 | AcpiExExitInterpreter (); |
559 | ACPI_ERROR_METHOD ("Method parse/execution failed" , |
560 | WalkState->MethodNode, NULL, Status); |
561 | AcpiExEnterInterpreter (); |
562 | |
563 | /* Check for possible multi-thread reentrancy problem */ |
564 | |
565 | if ((Status == AE_ALREADY_EXISTS) && |
566 | (!(WalkState->MethodDesc->Method.InfoFlags & |
567 | ACPI_METHOD_SERIALIZED))) |
568 | { |
569 | /* |
570 | * Method is not serialized and tried to create an object |
571 | * twice. The probable cause is that the method cannot |
572 | * handle reentrancy. Mark as "pending serialized" now, and |
573 | * then mark "serialized" when the last thread exits. |
574 | */ |
575 | WalkState->MethodDesc->Method.InfoFlags |= |
576 | ACPI_METHOD_SERIALIZED_PENDING; |
577 | } |
578 | } |
579 | |
580 | /* We are done with this walk, move on to the parent if any */ |
581 | |
582 | WalkState = AcpiDsPopWalkState (Thread); |
583 | |
584 | /* Reset the current scope to the beginning of scope stack */ |
585 | |
586 | AcpiDsScopeStackClear (WalkState); |
587 | |
588 | /* |
589 | * If we just returned from the execution of a control method or if we |
590 | * encountered an error during the method parse phase, there's lots of |
591 | * cleanup to do |
592 | */ |
593 | if (((WalkState->ParseFlags & ACPI_PARSE_MODE_MASK) == |
594 | ACPI_PARSE_EXECUTE && |
595 | !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) || |
596 | (ACPI_FAILURE (Status))) |
597 | { |
598 | AcpiDsTerminateControlMethod (WalkState->MethodDesc, WalkState); |
599 | } |
600 | |
601 | /* Delete this walk state and all linked control states */ |
602 | |
603 | AcpiPsCleanupScope (&WalkState->ParserState); |
604 | PreviousWalkState = WalkState; |
605 | |
606 | ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
607 | "ReturnValue=%p, ImplicitValue=%p State=%p\n" , |
608 | WalkState->ReturnDesc, WalkState->ImplicitReturnObj, WalkState)); |
609 | |
610 | /* Check if we have restarted a preempted walk */ |
611 | |
612 | WalkState = AcpiDsGetCurrentWalkState (Thread); |
613 | if (WalkState) |
614 | { |
615 | if (ACPI_SUCCESS (Status)) |
616 | { |
617 | /* |
618 | * There is another walk state, restart it. |
619 | * If the method return value is not used by the parent, |
620 | * The object is deleted |
621 | */ |
622 | if (!PreviousWalkState->ReturnDesc) |
623 | { |
624 | /* |
625 | * In slack mode execution, if there is no return value |
626 | * we should implicitly return zero (0) as a default value. |
627 | */ |
628 | if (AcpiGbl_EnableInterpreterSlack && |
629 | !PreviousWalkState->ImplicitReturnObj) |
630 | { |
631 | PreviousWalkState->ImplicitReturnObj = |
632 | AcpiUtCreateIntegerObject ((UINT64) 0); |
633 | if (!PreviousWalkState->ImplicitReturnObj) |
634 | { |
635 | return_ACPI_STATUS (AE_NO_MEMORY); |
636 | } |
637 | } |
638 | |
639 | /* Restart the calling control method */ |
640 | |
641 | Status = AcpiDsRestartControlMethod (WalkState, |
642 | PreviousWalkState->ImplicitReturnObj); |
643 | } |
644 | else |
645 | { |
646 | /* |
647 | * We have a valid return value, delete any implicit |
648 | * return value. |
649 | */ |
650 | AcpiDsClearImplicitReturn (PreviousWalkState); |
651 | |
652 | Status = AcpiDsRestartControlMethod (WalkState, |
653 | PreviousWalkState->ReturnDesc); |
654 | } |
655 | if (ACPI_SUCCESS (Status)) |
656 | { |
657 | WalkState->WalkType |= ACPI_WALK_METHOD_RESTART; |
658 | } |
659 | } |
660 | else |
661 | { |
662 | /* On error, delete any return object or implicit return */ |
663 | |
664 | AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); |
665 | AcpiDsClearImplicitReturn (PreviousWalkState); |
666 | } |
667 | } |
668 | |
669 | /* |
670 | * Just completed a 1st-level method, save the final internal return |
671 | * value (if any) |
672 | */ |
673 | else if (PreviousWalkState->CallerReturnDesc) |
674 | { |
675 | if (PreviousWalkState->ImplicitReturnObj) |
676 | { |
677 | *(PreviousWalkState->CallerReturnDesc) = |
678 | PreviousWalkState->ImplicitReturnObj; |
679 | } |
680 | else |
681 | { |
682 | /* NULL if no return value */ |
683 | |
684 | *(PreviousWalkState->CallerReturnDesc) = |
685 | PreviousWalkState->ReturnDesc; |
686 | } |
687 | } |
688 | else |
689 | { |
690 | if (PreviousWalkState->ReturnDesc) |
691 | { |
692 | /* Caller doesn't want it, must delete it */ |
693 | |
694 | AcpiUtRemoveReference (PreviousWalkState->ReturnDesc); |
695 | } |
696 | if (PreviousWalkState->ImplicitReturnObj) |
697 | { |
698 | /* Caller doesn't want it, must delete it */ |
699 | |
700 | AcpiUtRemoveReference (PreviousWalkState->ImplicitReturnObj); |
701 | } |
702 | } |
703 | |
704 | AcpiDsDeleteWalkState (PreviousWalkState); |
705 | } |
706 | |
707 | /* Normal exit */ |
708 | |
709 | AcpiExReleaseAllMutexes (Thread); |
710 | AcpiUtDeleteGenericState (ACPI_CAST_PTR (ACPI_GENERIC_STATE, Thread)); |
711 | AcpiGbl_CurrentWalkList = PrevWalkList; |
712 | return_ACPI_STATUS (Status); |
713 | } |
714 | |