1 | /******************************************************************************* |
2 | * |
3 | * Module Name: dsutils - Dispatcher utilities |
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 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | #include "acparser.h" |
47 | #include "amlcode.h" |
48 | #include "acdispat.h" |
49 | #include "acinterp.h" |
50 | #include "acnamesp.h" |
51 | #include "acdebug.h" |
52 | |
53 | #define _COMPONENT ACPI_DISPATCHER |
54 | ACPI_MODULE_NAME ("dsutils" ) |
55 | |
56 | |
57 | /******************************************************************************* |
58 | * |
59 | * FUNCTION: AcpiDsClearImplicitReturn |
60 | * |
61 | * PARAMETERS: WalkState - Current State |
62 | * |
63 | * RETURN: None. |
64 | * |
65 | * DESCRIPTION: Clear and remove a reference on an implicit return value. Used |
66 | * to delete "stale" return values (if enabled, the return value |
67 | * from every operator is saved at least momentarily, in case the |
68 | * parent method exits.) |
69 | * |
70 | ******************************************************************************/ |
71 | |
72 | void |
73 | AcpiDsClearImplicitReturn ( |
74 | ACPI_WALK_STATE *WalkState) |
75 | { |
76 | ACPI_FUNCTION_NAME (DsClearImplicitReturn); |
77 | |
78 | |
79 | /* |
80 | * Slack must be enabled for this feature |
81 | */ |
82 | if (!AcpiGbl_EnableInterpreterSlack) |
83 | { |
84 | return; |
85 | } |
86 | |
87 | if (WalkState->ImplicitReturnObj) |
88 | { |
89 | /* |
90 | * Delete any "stale" implicit return. However, in |
91 | * complex statements, the implicit return value can be |
92 | * bubbled up several levels. |
93 | */ |
94 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
95 | "Removing reference on stale implicit return obj %p\n" , |
96 | WalkState->ImplicitReturnObj)); |
97 | |
98 | AcpiUtRemoveReference (WalkState->ImplicitReturnObj); |
99 | WalkState->ImplicitReturnObj = NULL; |
100 | } |
101 | } |
102 | |
103 | |
104 | #ifndef ACPI_NO_METHOD_EXECUTION |
105 | /******************************************************************************* |
106 | * |
107 | * FUNCTION: AcpiDsDoImplicitReturn |
108 | * |
109 | * PARAMETERS: ReturnDesc - The return value |
110 | * WalkState - Current State |
111 | * AddReference - True if a reference should be added to the |
112 | * return object |
113 | * |
114 | * RETURN: TRUE if implicit return enabled, FALSE otherwise |
115 | * |
116 | * DESCRIPTION: Implements the optional "implicit return". We save the result |
117 | * of every ASL operator and control method invocation in case the |
118 | * parent method exit. Before storing a new return value, we |
119 | * delete the previous return value. |
120 | * |
121 | ******************************************************************************/ |
122 | |
123 | BOOLEAN |
124 | AcpiDsDoImplicitReturn ( |
125 | ACPI_OPERAND_OBJECT *ReturnDesc, |
126 | ACPI_WALK_STATE *WalkState, |
127 | BOOLEAN AddReference) |
128 | { |
129 | ACPI_FUNCTION_NAME (DsDoImplicitReturn); |
130 | |
131 | |
132 | /* |
133 | * Slack must be enabled for this feature, and we must |
134 | * have a valid return object |
135 | */ |
136 | if ((!AcpiGbl_EnableInterpreterSlack) || |
137 | (!ReturnDesc)) |
138 | { |
139 | return (FALSE); |
140 | } |
141 | |
142 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
143 | "Result %p will be implicitly returned; Prev=%p\n" , |
144 | ReturnDesc, |
145 | WalkState->ImplicitReturnObj)); |
146 | |
147 | /* |
148 | * Delete any "stale" implicit return value first. However, in |
149 | * complex statements, the implicit return value can be |
150 | * bubbled up several levels, so we don't clear the value if it |
151 | * is the same as the ReturnDesc. |
152 | */ |
153 | if (WalkState->ImplicitReturnObj) |
154 | { |
155 | if (WalkState->ImplicitReturnObj == ReturnDesc) |
156 | { |
157 | return (TRUE); |
158 | } |
159 | AcpiDsClearImplicitReturn (WalkState); |
160 | } |
161 | |
162 | /* Save the implicit return value, add a reference if requested */ |
163 | |
164 | WalkState->ImplicitReturnObj = ReturnDesc; |
165 | if (AddReference) |
166 | { |
167 | AcpiUtAddReference (ReturnDesc); |
168 | } |
169 | |
170 | return (TRUE); |
171 | } |
172 | |
173 | |
174 | /******************************************************************************* |
175 | * |
176 | * FUNCTION: AcpiDsIsResultUsed |
177 | * |
178 | * PARAMETERS: Op - Current Op |
179 | * WalkState - Current State |
180 | * |
181 | * RETURN: TRUE if result is used, FALSE otherwise |
182 | * |
183 | * DESCRIPTION: Check if a result object will be used by the parent |
184 | * |
185 | ******************************************************************************/ |
186 | |
187 | BOOLEAN |
188 | AcpiDsIsResultUsed ( |
189 | ACPI_PARSE_OBJECT *Op, |
190 | ACPI_WALK_STATE *WalkState) |
191 | { |
192 | const ACPI_OPCODE_INFO *ParentInfo; |
193 | |
194 | ACPI_FUNCTION_TRACE_PTR (DsIsResultUsed, Op); |
195 | |
196 | |
197 | /* Must have both an Op and a Result Object */ |
198 | |
199 | if (!Op) |
200 | { |
201 | ACPI_ERROR ((AE_INFO, "Null Op" )); |
202 | return_UINT8 (TRUE); |
203 | } |
204 | |
205 | /* |
206 | * We know that this operator is not a |
207 | * Return() operator (would not come here.) The following code is the |
208 | * optional support for a so-called "implicit return". Some AML code |
209 | * assumes that the last value of the method is "implicitly" returned |
210 | * to the caller. Just save the last result as the return value. |
211 | * NOTE: this is optional because the ASL language does not actually |
212 | * support this behavior. |
213 | */ |
214 | (void) AcpiDsDoImplicitReturn (WalkState->ResultObj, WalkState, TRUE); |
215 | |
216 | /* |
217 | * Now determine if the parent will use the result |
218 | * |
219 | * If there is no parent, or the parent is a ScopeOp, we are executing |
220 | * at the method level. An executing method typically has no parent, |
221 | * since each method is parsed separately. A method invoked externally |
222 | * via ExecuteControlMethod has a ScopeOp as the parent. |
223 | */ |
224 | if ((!Op->Common.Parent) || |
225 | (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) |
226 | { |
227 | /* No parent, the return value cannot possibly be used */ |
228 | |
229 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
230 | "At Method level, result of [%s] not used\n" , |
231 | AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); |
232 | return_UINT8 (FALSE); |
233 | } |
234 | |
235 | /* Get info on the parent. The RootOp is AML_SCOPE */ |
236 | |
237 | ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); |
238 | if (ParentInfo->Class == AML_CLASS_UNKNOWN) |
239 | { |
240 | ACPI_ERROR ((AE_INFO, |
241 | "Unknown parent opcode Op=%p" , Op)); |
242 | return_UINT8 (FALSE); |
243 | } |
244 | |
245 | /* |
246 | * Decide what to do with the result based on the parent. If |
247 | * the parent opcode will not use the result, delete the object. |
248 | * Otherwise leave it as is, it will be deleted when it is used |
249 | * as an operand later. |
250 | */ |
251 | switch (ParentInfo->Class) |
252 | { |
253 | case AML_CLASS_CONTROL: |
254 | |
255 | switch (Op->Common.Parent->Common.AmlOpcode) |
256 | { |
257 | case AML_RETURN_OP: |
258 | |
259 | /* Never delete the return value associated with a return opcode */ |
260 | |
261 | goto ResultUsed; |
262 | |
263 | case AML_IF_OP: |
264 | case AML_WHILE_OP: |
265 | /* |
266 | * If we are executing the predicate AND this is the predicate op, |
267 | * we will use the return value |
268 | */ |
269 | if ((WalkState->ControlState->Common.State == |
270 | ACPI_CONTROL_PREDICATE_EXECUTING) && |
271 | (WalkState->ControlState->Control.PredicateOp == Op)) |
272 | { |
273 | goto ResultUsed; |
274 | } |
275 | break; |
276 | |
277 | default: |
278 | |
279 | /* Ignore other control opcodes */ |
280 | |
281 | break; |
282 | } |
283 | |
284 | /* The general control opcode returns no result */ |
285 | |
286 | goto ResultNotUsed; |
287 | |
288 | case AML_CLASS_CREATE: |
289 | /* |
290 | * These opcodes allow TermArg(s) as operands and therefore |
291 | * the operands can be method calls. The result is used. |
292 | */ |
293 | goto ResultUsed; |
294 | |
295 | case AML_CLASS_NAMED_OBJECT: |
296 | |
297 | if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || |
298 | (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || |
299 | (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || |
300 | (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) || |
301 | (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || |
302 | (Op->Common.Parent->Common.AmlOpcode == AML_INT_EVAL_SUBTREE_OP) || |
303 | (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)) |
304 | { |
305 | /* |
306 | * These opcodes allow TermArg(s) as operands and therefore |
307 | * the operands can be method calls. The result is used. |
308 | */ |
309 | goto ResultUsed; |
310 | } |
311 | |
312 | goto ResultNotUsed; |
313 | |
314 | default: |
315 | /* |
316 | * In all other cases. the parent will actually use the return |
317 | * object, so keep it. |
318 | */ |
319 | goto ResultUsed; |
320 | } |
321 | |
322 | |
323 | ResultUsed: |
324 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
325 | "Result of [%s] used by Parent [%s] Op=%p\n" , |
326 | AcpiPsGetOpcodeName (Op->Common.AmlOpcode), |
327 | AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); |
328 | |
329 | return_UINT8 (TRUE); |
330 | |
331 | |
332 | ResultNotUsed: |
333 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
334 | "Result of [%s] not used by Parent [%s] Op=%p\n" , |
335 | AcpiPsGetOpcodeName (Op->Common.AmlOpcode), |
336 | AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); |
337 | |
338 | return_UINT8 (FALSE); |
339 | } |
340 | |
341 | |
342 | /******************************************************************************* |
343 | * |
344 | * FUNCTION: AcpiDsDeleteResultIfNotUsed |
345 | * |
346 | * PARAMETERS: Op - Current parse Op |
347 | * ResultObj - Result of the operation |
348 | * WalkState - Current state |
349 | * |
350 | * RETURN: Status |
351 | * |
352 | * DESCRIPTION: Used after interpretation of an opcode. If there is an internal |
353 | * result descriptor, check if the parent opcode will actually use |
354 | * this result. If not, delete the result now so that it will |
355 | * not become orphaned. |
356 | * |
357 | ******************************************************************************/ |
358 | |
359 | void |
360 | AcpiDsDeleteResultIfNotUsed ( |
361 | ACPI_PARSE_OBJECT *Op, |
362 | ACPI_OPERAND_OBJECT *ResultObj, |
363 | ACPI_WALK_STATE *WalkState) |
364 | { |
365 | ACPI_OPERAND_OBJECT *ObjDesc; |
366 | ACPI_STATUS Status; |
367 | |
368 | |
369 | ACPI_FUNCTION_TRACE_PTR (DsDeleteResultIfNotUsed, ResultObj); |
370 | |
371 | |
372 | if (!Op) |
373 | { |
374 | ACPI_ERROR ((AE_INFO, "Null Op" )); |
375 | return_VOID; |
376 | } |
377 | |
378 | if (!ResultObj) |
379 | { |
380 | return_VOID; |
381 | } |
382 | |
383 | if (!AcpiDsIsResultUsed (Op, WalkState)) |
384 | { |
385 | /* Must pop the result stack (ObjDesc should be equal to ResultObj) */ |
386 | |
387 | Status = AcpiDsResultPop (&ObjDesc, WalkState); |
388 | if (ACPI_SUCCESS (Status)) |
389 | { |
390 | AcpiUtRemoveReference (ResultObj); |
391 | } |
392 | } |
393 | |
394 | return_VOID; |
395 | } |
396 | |
397 | |
398 | /******************************************************************************* |
399 | * |
400 | * FUNCTION: AcpiDsResolveOperands |
401 | * |
402 | * PARAMETERS: WalkState - Current walk state with operands on stack |
403 | * |
404 | * RETURN: Status |
405 | * |
406 | * DESCRIPTION: Resolve all operands to their values. Used to prepare |
407 | * arguments to a control method invocation (a call from one |
408 | * method to another.) |
409 | * |
410 | ******************************************************************************/ |
411 | |
412 | ACPI_STATUS |
413 | AcpiDsResolveOperands ( |
414 | ACPI_WALK_STATE *WalkState) |
415 | { |
416 | UINT32 i; |
417 | ACPI_STATUS Status = AE_OK; |
418 | |
419 | |
420 | ACPI_FUNCTION_TRACE_PTR (DsResolveOperands, WalkState); |
421 | |
422 | |
423 | /* |
424 | * Attempt to resolve each of the valid operands |
425 | * Method arguments are passed by reference, not by value. This means |
426 | * that the actual objects are passed, not copies of the objects. |
427 | */ |
428 | for (i = 0; i < WalkState->NumOperands; i++) |
429 | { |
430 | Status = AcpiExResolveToValue (&WalkState->Operands[i], WalkState); |
431 | if (ACPI_FAILURE (Status)) |
432 | { |
433 | break; |
434 | } |
435 | } |
436 | |
437 | return_ACPI_STATUS (Status); |
438 | } |
439 | |
440 | |
441 | /******************************************************************************* |
442 | * |
443 | * FUNCTION: AcpiDsClearOperands |
444 | * |
445 | * PARAMETERS: WalkState - Current walk state with operands on stack |
446 | * |
447 | * RETURN: None |
448 | * |
449 | * DESCRIPTION: Clear all operands on the current walk state operand stack. |
450 | * |
451 | ******************************************************************************/ |
452 | |
453 | void |
454 | AcpiDsClearOperands ( |
455 | ACPI_WALK_STATE *WalkState) |
456 | { |
457 | UINT32 i; |
458 | |
459 | |
460 | ACPI_FUNCTION_TRACE_PTR (DsClearOperands, WalkState); |
461 | |
462 | |
463 | /* Remove a reference on each operand on the stack */ |
464 | |
465 | for (i = 0; i < WalkState->NumOperands; i++) |
466 | { |
467 | /* |
468 | * Remove a reference to all operands, including both |
469 | * "Arguments" and "Targets". |
470 | */ |
471 | AcpiUtRemoveReference (WalkState->Operands[i]); |
472 | WalkState->Operands[i] = NULL; |
473 | } |
474 | |
475 | WalkState->NumOperands = 0; |
476 | return_VOID; |
477 | } |
478 | #endif |
479 | |
480 | |
481 | /******************************************************************************* |
482 | * |
483 | * FUNCTION: AcpiDsCreateOperand |
484 | * |
485 | * PARAMETERS: WalkState - Current walk state |
486 | * Arg - Parse object for the argument |
487 | * ArgIndex - Which argument (zero based) |
488 | * |
489 | * RETURN: Status |
490 | * |
491 | * DESCRIPTION: Translate a parse tree object that is an argument to an AML |
492 | * opcode to the equivalent interpreter object. This may include |
493 | * looking up a name or entering a new name into the internal |
494 | * namespace. |
495 | * |
496 | ******************************************************************************/ |
497 | |
498 | ACPI_STATUS |
499 | AcpiDsCreateOperand ( |
500 | ACPI_WALK_STATE *WalkState, |
501 | ACPI_PARSE_OBJECT *Arg, |
502 | UINT32 ArgIndex) |
503 | { |
504 | ACPI_STATUS Status = AE_OK; |
505 | char *NameString; |
506 | UINT32 NameLength; |
507 | ACPI_OPERAND_OBJECT *ObjDesc; |
508 | ACPI_PARSE_OBJECT *ParentOp; |
509 | UINT16 Opcode; |
510 | ACPI_INTERPRETER_MODE InterpreterMode; |
511 | const ACPI_OPCODE_INFO *OpInfo; |
512 | |
513 | |
514 | ACPI_FUNCTION_TRACE_PTR (DsCreateOperand, Arg); |
515 | |
516 | |
517 | /* A valid name must be looked up in the namespace */ |
518 | |
519 | if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && |
520 | (Arg->Common.Value.String) && |
521 | !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) |
522 | { |
523 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n" , Arg)); |
524 | |
525 | /* Get the entire name string from the AML stream */ |
526 | |
527 | Status = AcpiExGetNameString (ACPI_TYPE_ANY, |
528 | Arg->Common.Value.Buffer, &NameString, &NameLength); |
529 | |
530 | if (ACPI_FAILURE (Status)) |
531 | { |
532 | return_ACPI_STATUS (Status); |
533 | } |
534 | |
535 | /* All prefixes have been handled, and the name is in NameString */ |
536 | |
537 | /* |
538 | * Special handling for BufferField declarations. This is a deferred |
539 | * opcode that unfortunately defines the field name as the last |
540 | * parameter instead of the first. We get here when we are performing |
541 | * the deferred execution, so the actual name of the field is already |
542 | * in the namespace. We don't want to attempt to look it up again |
543 | * because we may be executing in a different scope than where the |
544 | * actual opcode exists. |
545 | */ |
546 | if ((WalkState->DeferredNode) && |
547 | (WalkState->DeferredNode->Type == ACPI_TYPE_BUFFER_FIELD) && |
548 | (ArgIndex == (UINT32) |
549 | ((WalkState->Opcode == AML_CREATE_FIELD_OP) ? 3 : 2))) |
550 | { |
551 | ObjDesc = ACPI_CAST_PTR ( |
552 | ACPI_OPERAND_OBJECT, WalkState->DeferredNode); |
553 | Status = AE_OK; |
554 | } |
555 | else /* All other opcodes */ |
556 | { |
557 | /* |
558 | * Differentiate between a namespace "create" operation |
559 | * versus a "lookup" operation (IMODE_LOAD_PASS2 vs. |
560 | * IMODE_EXECUTE) in order to support the creation of |
561 | * namespace objects during the execution of control methods. |
562 | */ |
563 | ParentOp = Arg->Common.Parent; |
564 | OpInfo = AcpiPsGetOpcodeInfo (ParentOp->Common.AmlOpcode); |
565 | |
566 | if ((OpInfo->Flags & AML_NSNODE) && |
567 | (ParentOp->Common.AmlOpcode != AML_INT_METHODCALL_OP) && |
568 | (ParentOp->Common.AmlOpcode != AML_REGION_OP) && |
569 | (ParentOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP)) |
570 | { |
571 | /* Enter name into namespace if not found */ |
572 | |
573 | InterpreterMode = ACPI_IMODE_LOAD_PASS2; |
574 | } |
575 | else |
576 | { |
577 | /* Return a failure if name not found */ |
578 | |
579 | InterpreterMode = ACPI_IMODE_EXECUTE; |
580 | } |
581 | |
582 | Status = AcpiNsLookup (WalkState->ScopeInfo, NameString, |
583 | ACPI_TYPE_ANY, InterpreterMode, |
584 | ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, WalkState, |
585 | ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE, &ObjDesc)); |
586 | /* |
587 | * The only case where we pass through (ignore) a NOT_FOUND |
588 | * error is for the CondRefOf opcode. |
589 | */ |
590 | if (Status == AE_NOT_FOUND) |
591 | { |
592 | if (ParentOp->Common.AmlOpcode == AML_COND_REF_OF_OP) |
593 | { |
594 | /* |
595 | * For the Conditional Reference op, it's OK if |
596 | * the name is not found; We just need a way to |
597 | * indicate this to the interpreter, set the |
598 | * object to the root |
599 | */ |
600 | ObjDesc = ACPI_CAST_PTR ( |
601 | ACPI_OPERAND_OBJECT, AcpiGbl_RootNode); |
602 | Status = AE_OK; |
603 | } |
604 | else if (ParentOp->Common.AmlOpcode == AML_EXTERNAL_OP) |
605 | { |
606 | /* |
607 | * This opcode should never appear here. It is used only |
608 | * by AML disassemblers and is surrounded by an If(0) |
609 | * by the ASL compiler. |
610 | * |
611 | * Therefore, if we see it here, it is a serious error. |
612 | */ |
613 | Status = AE_AML_BAD_OPCODE; |
614 | } |
615 | else |
616 | { |
617 | /* |
618 | * We just plain didn't find it -- which is a |
619 | * very serious error at this point |
620 | */ |
621 | Status = AE_AML_NAME_NOT_FOUND; |
622 | } |
623 | } |
624 | |
625 | if (ACPI_FAILURE (Status)) |
626 | { |
627 | ACPI_ERROR_NAMESPACE (NameString, Status); |
628 | } |
629 | } |
630 | |
631 | /* Free the namestring created above */ |
632 | |
633 | ACPI_FREE (NameString); |
634 | |
635 | /* Check status from the lookup */ |
636 | |
637 | if (ACPI_FAILURE (Status)) |
638 | { |
639 | return_ACPI_STATUS (Status); |
640 | } |
641 | |
642 | /* Put the resulting object onto the current object stack */ |
643 | |
644 | Status = AcpiDsObjStackPush (ObjDesc, WalkState); |
645 | if (ACPI_FAILURE (Status)) |
646 | { |
647 | return_ACPI_STATUS (Status); |
648 | } |
649 | |
650 | AcpiDbDisplayArgumentObject (ObjDesc, WalkState); |
651 | } |
652 | else |
653 | { |
654 | /* Check for null name case */ |
655 | |
656 | if ((Arg->Common.AmlOpcode == AML_INT_NAMEPATH_OP) && |
657 | !(Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) |
658 | { |
659 | /* |
660 | * If the name is null, this means that this is an |
661 | * optional result parameter that was not specified |
662 | * in the original ASL. Create a Zero Constant for a |
663 | * placeholder. (Store to a constant is a Noop.) |
664 | */ |
665 | Opcode = AML_ZERO_OP; /* Has no arguments! */ |
666 | |
667 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
668 | "Null namepath: Arg=%p\n" , Arg)); |
669 | } |
670 | else |
671 | { |
672 | Opcode = Arg->Common.AmlOpcode; |
673 | } |
674 | |
675 | /* Get the object type of the argument */ |
676 | |
677 | OpInfo = AcpiPsGetOpcodeInfo (Opcode); |
678 | if (OpInfo->ObjectType == ACPI_TYPE_INVALID) |
679 | { |
680 | return_ACPI_STATUS (AE_NOT_IMPLEMENTED); |
681 | } |
682 | |
683 | if ((OpInfo->Flags & AML_HAS_RETVAL) || |
684 | (Arg->Common.Flags & ACPI_PARSEOP_IN_STACK)) |
685 | { |
686 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
687 | "Argument previously created, already stacked\n" )); |
688 | |
689 | AcpiDbDisplayArgumentObject ( |
690 | WalkState->Operands [WalkState->NumOperands - 1], WalkState); |
691 | |
692 | /* |
693 | * Use value that was already previously returned |
694 | * by the evaluation of this argument |
695 | */ |
696 | Status = AcpiDsResultPop (&ObjDesc, WalkState); |
697 | if (ACPI_FAILURE (Status)) |
698 | { |
699 | /* |
700 | * Only error is underflow, and this indicates |
701 | * a missing or null operand! |
702 | */ |
703 | ACPI_EXCEPTION ((AE_INFO, Status, |
704 | "Missing or null operand" )); |
705 | return_ACPI_STATUS (Status); |
706 | } |
707 | } |
708 | else |
709 | { |
710 | /* Create an ACPI_INTERNAL_OBJECT for the argument */ |
711 | |
712 | ObjDesc = AcpiUtCreateInternalObject (OpInfo->ObjectType); |
713 | if (!ObjDesc) |
714 | { |
715 | return_ACPI_STATUS (AE_NO_MEMORY); |
716 | } |
717 | |
718 | /* Initialize the new object */ |
719 | |
720 | Status = AcpiDsInitObjectFromOp ( |
721 | WalkState, Arg, Opcode, &ObjDesc); |
722 | if (ACPI_FAILURE (Status)) |
723 | { |
724 | AcpiUtDeleteObjectDesc (ObjDesc); |
725 | return_ACPI_STATUS (Status); |
726 | } |
727 | } |
728 | |
729 | /* Put the operand object on the object stack */ |
730 | |
731 | Status = AcpiDsObjStackPush (ObjDesc, WalkState); |
732 | if (ACPI_FAILURE (Status)) |
733 | { |
734 | return_ACPI_STATUS (Status); |
735 | } |
736 | |
737 | AcpiDbDisplayArgumentObject (ObjDesc, WalkState); |
738 | } |
739 | |
740 | return_ACPI_STATUS (AE_OK); |
741 | } |
742 | |
743 | |
744 | /******************************************************************************* |
745 | * |
746 | * FUNCTION: AcpiDsCreateOperands |
747 | * |
748 | * PARAMETERS: WalkState - Current state |
749 | * FirstArg - First argument of a parser argument tree |
750 | * |
751 | * RETURN: Status |
752 | * |
753 | * DESCRIPTION: Convert an operator's arguments from a parse tree format to |
754 | * namespace objects and place those argument object on the object |
755 | * stack in preparation for evaluation by the interpreter. |
756 | * |
757 | ******************************************************************************/ |
758 | |
759 | ACPI_STATUS |
760 | AcpiDsCreateOperands ( |
761 | ACPI_WALK_STATE *WalkState, |
762 | ACPI_PARSE_OBJECT *FirstArg) |
763 | { |
764 | ACPI_STATUS Status = AE_OK; |
765 | ACPI_PARSE_OBJECT *Arg; |
766 | ACPI_PARSE_OBJECT *Arguments[ACPI_OBJ_NUM_OPERANDS]; |
767 | UINT32 ArgCount = 0; |
768 | UINT32 Index = WalkState->NumOperands; |
769 | UINT32 i; |
770 | |
771 | |
772 | ACPI_FUNCTION_TRACE_PTR (DsCreateOperands, FirstArg); |
773 | |
774 | |
775 | /* Get all arguments in the list */ |
776 | |
777 | Arg = FirstArg; |
778 | while (Arg) |
779 | { |
780 | if (Index >= ACPI_OBJ_NUM_OPERANDS) |
781 | { |
782 | return_ACPI_STATUS (AE_BAD_DATA); |
783 | } |
784 | |
785 | Arguments[Index] = Arg; |
786 | WalkState->Operands [Index] = NULL; |
787 | |
788 | /* Move on to next argument, if any */ |
789 | |
790 | Arg = Arg->Common.Next; |
791 | ArgCount++; |
792 | Index++; |
793 | } |
794 | |
795 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
796 | "NumOperands %d, ArgCount %d, Index %d\n" , |
797 | WalkState->NumOperands, ArgCount, Index)); |
798 | |
799 | /* Create the interpreter arguments, in reverse order */ |
800 | |
801 | Index--; |
802 | for (i = 0; i < ArgCount; i++) |
803 | { |
804 | Arg = Arguments[Index]; |
805 | WalkState->OperandIndex = (UINT8) Index; |
806 | |
807 | Status = AcpiDsCreateOperand (WalkState, Arg, Index); |
808 | if (ACPI_FAILURE (Status)) |
809 | { |
810 | goto Cleanup; |
811 | } |
812 | |
813 | ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
814 | "Created Arg #%u (%p) %u args total\n" , |
815 | Index, Arg, ArgCount)); |
816 | Index--; |
817 | } |
818 | |
819 | return_ACPI_STATUS (Status); |
820 | |
821 | |
822 | Cleanup: |
823 | /* |
824 | * We must undo everything done above; meaning that we must |
825 | * pop everything off of the operand stack and delete those |
826 | * objects |
827 | */ |
828 | AcpiDsObjStackPopAndDelete (ArgCount, WalkState); |
829 | |
830 | ACPI_EXCEPTION ((AE_INFO, Status, "While creating Arg %u" , Index)); |
831 | return_ACPI_STATUS (Status); |
832 | } |
833 | |
834 | |
835 | /***************************************************************************** |
836 | * |
837 | * FUNCTION: AcpiDsEvaluateNamePath |
838 | * |
839 | * PARAMETERS: WalkState - Current state of the parse tree walk, |
840 | * the opcode of current operation should be |
841 | * AML_INT_NAMEPATH_OP |
842 | * |
843 | * RETURN: Status |
844 | * |
845 | * DESCRIPTION: Translate the -NamePath- parse tree object to the equivalent |
846 | * interpreter object, convert it to value, if needed, duplicate |
847 | * it, if needed, and push it onto the current result stack. |
848 | * |
849 | ****************************************************************************/ |
850 | |
851 | ACPI_STATUS |
852 | AcpiDsEvaluateNamePath ( |
853 | ACPI_WALK_STATE *WalkState) |
854 | { |
855 | ACPI_STATUS Status = AE_OK; |
856 | ACPI_PARSE_OBJECT *Op = WalkState->Op; |
857 | ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; |
858 | ACPI_OPERAND_OBJECT *NewObjDesc; |
859 | UINT8 Type; |
860 | |
861 | |
862 | ACPI_FUNCTION_TRACE_PTR (DsEvaluateNamePath, WalkState); |
863 | |
864 | |
865 | if (!Op->Common.Parent) |
866 | { |
867 | /* This happens after certain exception processing */ |
868 | |
869 | goto Exit; |
870 | } |
871 | |
872 | if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || |
873 | (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) || |
874 | (Op->Common.Parent->Common.AmlOpcode == AML_REF_OF_OP)) |
875 | { |
876 | /* TBD: Should we specify this feature as a bit of OpInfo->Flags of these opcodes? */ |
877 | |
878 | goto Exit; |
879 | } |
880 | |
881 | Status = AcpiDsCreateOperand (WalkState, Op, 0); |
882 | if (ACPI_FAILURE (Status)) |
883 | { |
884 | goto Exit; |
885 | } |
886 | |
887 | if (Op->Common.Flags & ACPI_PARSEOP_TARGET) |
888 | { |
889 | NewObjDesc = *Operand; |
890 | goto PushResult; |
891 | } |
892 | |
893 | Type = (*Operand)->Common.Type; |
894 | |
895 | Status = AcpiExResolveToValue (Operand, WalkState); |
896 | if (ACPI_FAILURE (Status)) |
897 | { |
898 | goto Exit; |
899 | } |
900 | |
901 | if (Type == ACPI_TYPE_INTEGER) |
902 | { |
903 | /* It was incremented by AcpiExResolveToValue */ |
904 | |
905 | AcpiUtRemoveReference (*Operand); |
906 | |
907 | Status = AcpiUtCopyIobjectToIobject ( |
908 | *Operand, &NewObjDesc, WalkState); |
909 | if (ACPI_FAILURE (Status)) |
910 | { |
911 | goto Exit; |
912 | } |
913 | } |
914 | else |
915 | { |
916 | /* |
917 | * The object either was anew created or is |
918 | * a Namespace node - don't decrement it. |
919 | */ |
920 | NewObjDesc = *Operand; |
921 | } |
922 | |
923 | /* Cleanup for name-path operand */ |
924 | |
925 | Status = AcpiDsObjStackPop (1, WalkState); |
926 | if (ACPI_FAILURE (Status)) |
927 | { |
928 | WalkState->ResultObj = NewObjDesc; |
929 | goto Exit; |
930 | } |
931 | |
932 | PushResult: |
933 | |
934 | WalkState->ResultObj = NewObjDesc; |
935 | |
936 | Status = AcpiDsResultPush (WalkState->ResultObj, WalkState); |
937 | if (ACPI_SUCCESS (Status)) |
938 | { |
939 | /* Force to take it from stack */ |
940 | |
941 | Op->Common.Flags |= ACPI_PARSEOP_IN_STACK; |
942 | } |
943 | |
944 | Exit: |
945 | |
946 | return_ACPI_STATUS (Status); |
947 | } |
948 | |