ACPI_STATUS AcpiDsRestartControlMethod ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT *ReturnDesc) { ACPI_STATUS Status; int SameAsImplicitReturn; ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", AcpiUtGetNodeName (WalkState->MethodNode), WalkState->MethodCallOp, ReturnDesc)); ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", WalkState->ReturnUsed, WalkState->Results, WalkState)); /* Did the called method return a value? */ if (ReturnDesc) { /* Is the implicit return object the same as the return desc? */ SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); /* Are we actually going to use the return value? */ if (WalkState->ReturnUsed) { /* Save the return value from the previous method */ Status = AcpiDsResultPush (ReturnDesc, WalkState); if (ACPI_FAILURE (Status)) { AcpiUtRemoveReference (ReturnDesc); return_ACPI_STATUS (Status); } /* * Save as THIS method's return value in case it is returned * immediately to yet another method */ WalkState->ReturnDesc = ReturnDesc; } /* * The following code is the optional support for the so-called * "implicit return". Some AML code assumes that the last value of the * method is "implicitly" returned to the caller, in the absence of an * explicit return value. * * Just save the last result of the method as the return value. * * NOTE: this is optional because the ASL language does not actually * support this behavior. */ else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || SameAsImplicitReturn) { /* * Delete the return value if it will not be used by the * calling method or remove one reference if the explicit return * is the same as the implicit return value. */ AcpiUtRemoveReference (ReturnDesc); } } return_ACPI_STATUS (AE_OK); }
BOOLEAN AcpiDsIsResultUsed ( ACPI_PARSE_OBJECT *Op, ACPI_WALK_STATE *WalkState) { const ACPI_OPCODE_INFO *ParentInfo; ACPI_FUNCTION_TRACE_PTR (DsIsResultUsed, Op); /* Must have both an Op and a Result Object */ if (!Op) { ACPI_ERROR ((AE_INFO, "Null Op")); return_UINT8 (TRUE); } /* * We know that this operator is not a * Return() operator (would not come here.) The following code is the * optional support for a so-called "implicit return". Some AML code * assumes that the last value of the method is "implicitly" returned * to the caller. Just save the last result as the return value. * NOTE: this is optional because the ASL language does not actually * support this behavior. */ (void) AcpiDsDoImplicitReturn (WalkState->ResultObj, WalkState, TRUE); /* * Now determine if the parent will use the result * * If there is no parent, or the parent is a ScopeOp, we are executing * at the method level. An executing method typically has no parent, * since each method is parsed separately. A method invoked externally * via ExecuteControlMethod has a ScopeOp as the parent. */ if ((!Op->Common.Parent) || (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) { /* No parent, the return value cannot possibly be used */ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n", AcpiPsGetOpcodeName (Op->Common.AmlOpcode))); return_UINT8 (FALSE); } /* Get info on the parent. The RootOp is AML_SCOPE */ ParentInfo = AcpiPsGetOpcodeInfo (Op->Common.Parent->Common.AmlOpcode); if (ParentInfo->Class == AML_CLASS_UNKNOWN) { ACPI_ERROR ((AE_INFO, "Unknown parent opcode Op=%p", Op)); return_UINT8 (FALSE); } /* * Decide what to do with the result based on the parent. If * the parent opcode will not use the result, delete the object. * Otherwise leave it as is, it will be deleted when it is used * as an operand later. */ switch (ParentInfo->Class) { case AML_CLASS_CONTROL: switch (Op->Common.Parent->Common.AmlOpcode) { case AML_RETURN_OP: /* Never delete the return value associated with a return opcode */ goto ResultUsed; case AML_IF_OP: case AML_WHILE_OP: /* * If we are executing the predicate AND this is the predicate op, * we will use the return value */ if ((WalkState->ControlState->Common.State == ACPI_CONTROL_PREDICATE_EXECUTING) && (WalkState->ControlState->Control.PredicateOp == Op)) { goto ResultUsed; } break; default: /* Ignore other control opcodes */ break; } /* The general control opcode returns no result */ goto ResultNotUsed; case AML_CLASS_CREATE: /* * These opcodes allow TermArg(s) as operands and therefore * the operands can be method calls. The result is used. */ goto ResultUsed; case AML_CLASS_NAMED_OBJECT: if ((Op->Common.Parent->Common.AmlOpcode == AML_REGION_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_DATA_REGION_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_VAR_PACKAGE_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_BUFFER_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_INT_EVAL_SUBTREE_OP) || (Op->Common.Parent->Common.AmlOpcode == AML_BANK_FIELD_OP)) { /* * These opcodes allow TermArg(s) as operands and therefore * the operands can be method calls. The result is used. */ goto ResultUsed; } goto ResultNotUsed; default: /* * In all other cases. the parent will actually use the return * object, so keep it. */ goto ResultUsed; } ResultUsed: ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n", AcpiPsGetOpcodeName (Op->Common.AmlOpcode), AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); return_UINT8 (TRUE); ResultNotUsed: ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n", AcpiPsGetOpcodeName (Op->Common.AmlOpcode), AcpiPsGetOpcodeName (Op->Common.Parent->Common.AmlOpcode), Op)); return_UINT8 (FALSE); }
ACPI_STATUS AcpiDsGetPredicateValue ( ACPI_WALK_STATE *WalkState, ACPI_OPERAND_OBJECT *ResultObj) { ACPI_STATUS Status = AE_OK; ACPI_OPERAND_OBJECT *ObjDesc; ACPI_OPERAND_OBJECT *LocalObjDesc = NULL; ACPI_FUNCTION_TRACE_PTR (DsGetPredicateValue, WalkState); WalkState->ControlState->Common.State = 0; if (ResultObj) { Status = AcpiDsResultPop (&ObjDesc, WalkState); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Could not get result from predicate evaluation")); return_ACPI_STATUS (Status); } } else { Status = AcpiDsCreateOperand (WalkState, WalkState->Op, 0); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } Status = AcpiExResolveToValue (&WalkState->Operands [0], WalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } ObjDesc = WalkState->Operands [0]; } if (!ObjDesc) { ACPI_ERROR ((AE_INFO, "No predicate ObjDesc=%p State=%p", ObjDesc, WalkState)); return_ACPI_STATUS (AE_AML_NO_OPERAND); } /* * Result of predicate evaluation must be an Integer * object. Implicitly convert the argument if necessary. */ Status = AcpiExConvertToInteger (ObjDesc, &LocalObjDesc, 16); if (ACPI_FAILURE (Status)) { goto Cleanup; } if (LocalObjDesc->Common.Type != ACPI_TYPE_INTEGER) { ACPI_ERROR ((AE_INFO, "Bad predicate (not an integer) ObjDesc=%p State=%p Type=0x%X", ObjDesc, WalkState, ObjDesc->Common.Type)); Status = AE_AML_OPERAND_TYPE; goto Cleanup; } /* Truncate the predicate to 32-bits if necessary */ (void) AcpiExTruncateFor32bitTable (LocalObjDesc); /* * Save the result of the predicate evaluation on * the control stack */ if (LocalObjDesc->Integer.Value) { WalkState->ControlState->Common.Value = TRUE; } else { /* * Predicate is FALSE, we will just toss the * rest of the package */ WalkState->ControlState->Common.Value = FALSE; Status = AE_CTRL_FALSE; } /* Predicate can be used for an implicit return value */ (void) AcpiDsDoImplicitReturn (LocalObjDesc, WalkState, TRUE); Cleanup: ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n", WalkState->ControlState->Common.Value, WalkState->Op)); /* Break to debugger to display result */ AcpiDbDisplayResultObject (LocalObjDesc, WalkState); /* * Delete the predicate result object (we know that * we don't need it anymore) */ if (LocalObjDesc != ObjDesc) { AcpiUtRemoveReference (LocalObjDesc); } AcpiUtRemoveReference (ObjDesc); WalkState->ControlState->Common.State = ACPI_CONTROL_NORMAL; return_ACPI_STATUS (Status); }