BOOLEAN ApCheckForPredefinedMethod ( ACPI_PARSE_OBJECT *Op, ASL_METHOD_INFO *MethodInfo) { UINT32 Index; UINT32 RequiredArgCount; const ACPI_PREDEFINED_INFO *ThisName; /* Check for a match against the predefined name list */ Index = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); switch (Index) { case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Just return, nothing to do */ return (FALSE); case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ Gbl_ReservedMethods++; /* NumArguments must be zero for all _Lxx/_Exx/_Wxx/_Qxx methods */ if (MethodInfo->NumArguments != 0) { sprintf (MsgBuffer, "%s requires %u", Op->Asl.ExternalName, 0); AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, MsgBuffer); } break; default: /* * Matched a predefined method name - validate the ASL-defined * argument count against the ACPI specification. * * Some methods are allowed to have a "minimum" number of args * (_SCP) because their definition in ACPI has changed over time. */ Gbl_ReservedMethods++; ThisName = &AcpiGbl_PredefinedMethods[Index]; RequiredArgCount = METHOD_GET_ARG_COUNT (ThisName->Info.ArgumentList); if (MethodInfo->NumArguments != RequiredArgCount) { sprintf (MsgBuffer, "%4.4s requires %u", ThisName->Info.Name, RequiredArgCount); if (MethodInfo->NumArguments < RequiredArgCount) { AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_LO, Op, MsgBuffer); } else if ((MethodInfo->NumArguments > RequiredArgCount) && !(ThisName->Info.ArgumentList & ARG_COUNT_IS_MINIMUM)) { AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, MsgBuffer); } } /* * Check if method returns no value, but the predefined name is * required to return a value */ if (MethodInfo->NumReturnNoValue && ThisName->Info.ExpectedBtypes) { AcpiUtGetExpectedReturnTypes (StringBuffer, ThisName->Info.ExpectedBtypes); sprintf (MsgBuffer, "%s required for %4.4s", StringBuffer, ThisName->Info.Name); AslError (ASL_WARNING, ASL_MSG_RESERVED_RETURN_VALUE, Op, MsgBuffer); } break; } return (TRUE); }
void ApCheckPredefinedReturnValue ( ACPI_PARSE_OBJECT *Op, ASL_METHOD_INFO *MethodInfo) { UINT32 Index; ACPI_PARSE_OBJECT *ReturnValueOp; const ACPI_PREDEFINED_INFO *ThisName; /* * Check parent method for a match against the predefined name list. * * Note: Disable compiler errors/warnings because any errors will be * caught when analyzing the parent method. Eliminates duplicate errors. */ Gbl_AllExceptionsDisabled = TRUE; Index = ApCheckForPredefinedName (MethodInfo->Op, MethodInfo->Op->Asl.NameSeg); Gbl_AllExceptionsDisabled = FALSE; switch (Index) { case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ /* No return value expected, warn if there is one */ ApCheckForUnexpectedReturnValue (Op, MethodInfo); return; case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Just return, nothing to do */ return; default: /* A standard predefined ACPI name */ ThisName = &AcpiGbl_PredefinedMethods[Index]; if (!ThisName->Info.ExpectedBtypes) { /* No return value expected, warn if there is one */ ApCheckForUnexpectedReturnValue (Op, MethodInfo); return; } /* Get the object returned, it is the next argument */ ReturnValueOp = Op->Asl.Child; switch (ReturnValueOp->Asl.ParseOpcode) { case PARSEOP_ZERO: case PARSEOP_ONE: case PARSEOP_ONES: case PARSEOP_INTEGER: case PARSEOP_STRING_LITERAL: case PARSEOP_BUFFER: case PARSEOP_PACKAGE: /* Static data return object - check against expected type */ ApCheckObjectType (ThisName->Info.Name, ReturnValueOp, ThisName->Info.ExpectedBtypes, ACPI_NOT_PACKAGE_ELEMENT); /* For packages, check the individual package elements */ if (ReturnValueOp->Asl.ParseOpcode == PARSEOP_PACKAGE) { ApCheckPackage (ReturnValueOp, ThisName); } break; default: /* * All other ops are very difficult or impossible to typecheck at * compile time. These include all Localx, Argx, and method * invocations. Also, NAMESEG and NAMESTRING because the type of * any named object can be changed at runtime (for example, * CopyObject will change the type of the target object.) */ break; } } }
void ApCheckForPredefinedObject ( ACPI_PARSE_OBJECT *Op, char *Name) { UINT32 Index; ACPI_PARSE_OBJECT *ObjectOp; const ACPI_PREDEFINED_INFO *ThisName; /* * Check for a real predefined name -- not a resource descriptor name * or a predefined scope name */ Index = ApCheckForPredefinedName (Op, Name); switch (Index) { case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Nothing to do */ return; case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ /* * These names must be control methods, by definition in ACPI spec. * Also because they are defined to return no value. None of them * require any arguments. */ AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with zero arguments"); return; default: break; } /* A standard predefined ACPI name */ /* * If this predefined name requires input arguments, then * it must be implemented as a control method */ ThisName = &AcpiGbl_PredefinedMethods[Index]; if (METHOD_GET_ARG_COUNT (ThisName->Info.ArgumentList) > 0) { AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with arguments"); return; } /* * If no return value is expected from this predefined name, then * it follows that it must be implemented as a control method * (with zero args, because the args > 0 case was handled above) * Examples are: _DIS, _INI, _IRC, _OFF, _ON, _PSx */ if (!ThisName->Info.ExpectedBtypes) { AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with zero arguments"); return; } /* Typecheck the actual object, it is the next argument */ ObjectOp = Op->Asl.Child->Asl.Next; ApCheckObjectType (ThisName->Info.Name, Op->Asl.Child->Asl.Next, ThisName->Info.ExpectedBtypes, ACPI_NOT_PACKAGE_ELEMENT); /* For packages, check the individual package elements */ if (ObjectOp->Asl.ParseOpcode == PARSEOP_PACKAGE) { ApCheckPackage (ObjectOp, ThisName); } }
ACPI_STATUS MtMethodAnalysisWalkBegin ( ACPI_PARSE_OBJECT *Op, UINT32 Level, void *Context) { ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; ACPI_PARSE_OBJECT *Next; UINT32 RegisterNumber; UINT32 i; char LocalName[] = "Local0"; char ArgName[] = "Arg0"; ACPI_PARSE_OBJECT *ArgNode; ACPI_PARSE_OBJECT *NextType; ACPI_PARSE_OBJECT *NextParamType; UINT8 ActualArgs = 0; switch (Op->Asl.ParseOpcode) { case PARSEOP_METHOD: TotalMethods++; /* Create and init method info */ MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); MethodInfo->Next = WalkInfo->MethodStack; MethodInfo->Op = Op; WalkInfo->MethodStack = MethodInfo; /* * Special handling for _PSx methods. Dependency rules (same scope): * * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3 * 2) _PS1/_PS2/_PS3: A _PS0 must exist */ if (ACPI_COMPARE_NAME (METHOD_NAME__PS0, Op->Asl.NameSeg)) { /* For _PS0, one of _PS1/_PS2/_PS3 must exist */ if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) && (!ApFindNameInScope (METHOD_NAME__PS2, Op)) && (!ApFindNameInScope (METHOD_NAME__PS3, Op))) { AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, "_PS0 requires one of _PS1/_PS2/_PS3 in same scope"); } } else if ( ACPI_COMPARE_NAME (METHOD_NAME__PS1, Op->Asl.NameSeg) || ACPI_COMPARE_NAME (METHOD_NAME__PS2, Op->Asl.NameSeg) || ACPI_COMPARE_NAME (METHOD_NAME__PS3, Op->Asl.NameSeg)) { /* For _PS1/_PS2/_PS3, a _PS0 must exist */ if (!ApFindNameInScope (METHOD_NAME__PS0, Op)) { sprintf (MsgBuffer, "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg); AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, MsgBuffer); } } /* Get the name node */ Next = Op->Asl.Child; /* Get the NumArguments node */ Next = Next->Asl.Next; MethodInfo->NumArguments = (UINT8) (((UINT8) Next->Asl.Value.Integer) & 0x07); /* Get the SerializeRule and SyncLevel nodes, ignored here */ Next = Next->Asl.Next; MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer; Next = Next->Asl.Next; ArgNode = Next; /* Get the ReturnType node */ Next = Next->Asl.Next; NextType = Next->Asl.Child; while (NextType) { /* Get and map each of the ReturnTypes */ MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType); NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; NextType = NextType->Asl.Next; } /* Get the ParameterType node */ Next = Next->Asl.Next; NextType = Next->Asl.Child; while (NextType) { if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) { NextParamType = NextType->Asl.Child; while (NextParamType) { MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType); NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; NextParamType = NextParamType->Asl.Next; } } else { MethodInfo->ValidArgTypes[ActualArgs] = AnMapObjTypeToBtype (NextType); NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; ActualArgs++; } NextType = NextType->Asl.Next; } if ((MethodInfo->NumArguments) && (MethodInfo->NumArguments != ActualArgs)) { /* error: Param list did not match number of args */ } /* Allow numarguments == 0 for Function() */ if ((!MethodInfo->NumArguments) && (ActualArgs)) { MethodInfo->NumArguments = ActualArgs; ArgNode->Asl.Value.Integer |= ActualArgs; } /* * Actual arguments are initialized at method entry. * All other ArgX "registers" can be used as locals, so we * track their initialization. */ for (i = 0; i < MethodInfo->NumArguments; i++) { MethodInfo->ArgInitialized[i] = TRUE; } break; case PARSEOP_METHODCALL: if (MethodInfo && (Op->Asl.Node == MethodInfo->Op->Asl.Node)) { AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); } break; case PARSEOP_LOCAL0: case PARSEOP_LOCAL1: case PARSEOP_LOCAL2: case PARSEOP_LOCAL3: case PARSEOP_LOCAL4: case PARSEOP_LOCAL5: case PARSEOP_LOCAL6: case PARSEOP_LOCAL7: if (!MethodInfo) { /* * Local was used outside a control method, or there was an error * in the method declaration. */ AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); return (AE_ERROR); } RegisterNumber = (Op->Asl.AmlOpcode & 0x0007); /* * If the local is being used as a target, mark the local * initialized */ if (Op->Asl.CompileFlags & NODE_IS_TARGET) { MethodInfo->LocalInitialized[RegisterNumber] = TRUE; } /* * Otherwise, this is a reference, check if the local * has been previously initialized. * * The only operator that accepts an uninitialized value is ObjectType() */ else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) { LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); } break; case PARSEOP_ARG0: case PARSEOP_ARG1: case PARSEOP_ARG2: case PARSEOP_ARG3: case PARSEOP_ARG4: case PARSEOP_ARG5: case PARSEOP_ARG6: if (!MethodInfo) { /* * Arg was used outside a control method, or there was an error * in the method declaration. */ AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); return (AE_ERROR); } RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); /* * If the Arg is being used as a target, mark the local * initialized */ if (Op->Asl.CompileFlags & NODE_IS_TARGET) { MethodInfo->ArgInitialized[RegisterNumber] = TRUE; } /* * Otherwise, this is a reference, check if the Arg * has been previously initialized. * * The only operator that accepts an uninitialized value is ObjectType() */ else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) { AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); } /* Flag this arg if it is not a "real" argument to the method */ if (RegisterNumber >= MethodInfo->NumArguments) { AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); } break; case PARSEOP_RETURN: if (!MethodInfo) { /* * Probably was an error in the method declaration, * no additional error here */ ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); return (AE_ERROR); } /* * A child indicates a possible return value. A simple Return or * Return() is marked with NODE_IS_NULL_RETURN by the parser so * that it is not counted as a "real" return-with-value, although * the AML code that is actually emitted is Return(0). The AML * definition of Return has a required parameter, so we are * forced to convert a null return to Return(0). */ if ((Op->Asl.Child) && (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) && (!(Op->Asl.Child->Asl.CompileFlags & NODE_IS_NULL_RETURN))) { MethodInfo->NumReturnWithValue++; } else { MethodInfo->NumReturnNoValue++; } break; case PARSEOP_BREAK: case PARSEOP_CONTINUE: Next = Op->Asl.Parent; while (Next) { if (Next->Asl.ParseOpcode == PARSEOP_WHILE) { break; } Next = Next->Asl.Parent; } if (!Next) { AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); } break; case PARSEOP_STALL: /* We can range check if the argument is an integer */ if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) { AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); } break; case PARSEOP_DEVICE: Next = Op->Asl.Child; if (!ApFindNameInScope (METHOD_NAME__HID, Next) && !ApFindNameInScope (METHOD_NAME__ADR, Next)) { AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op, "Device object requires a _HID or _ADR in same scope"); } break; case PARSEOP_EVENT: case PARSEOP_MUTEX: case PARSEOP_OPERATIONREGION: case PARSEOP_POWERRESOURCE: case PARSEOP_PROCESSOR: case PARSEOP_THERMALZONE: /* * The first operand is a name to be created in the namespace. * Check against the reserved list. */ i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); if (i < ACPI_VALID_RESERVED_NAME_MAX) { AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName); } break; case PARSEOP_NAME: /* Typecheck any predefined names statically defined with Name() */ ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); /* Special typechecking for _HID */ if (!strcmp (METHOD_NAME__HID, Op->Asl.NameSeg)) { Next = Op->Asl.Child->Asl.Next; AnCheckId (Next, ASL_TYPE_HID); } /* Special typechecking for _CID */ else if (!strcmp (METHOD_NAME__CID, Op->Asl.NameSeg)) { Next = Op->Asl.Child->Asl.Next; if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) { Next = Next->Asl.Child; while (Next) { AnCheckId (Next, ASL_TYPE_CID); Next = Next->Asl.Next; } } else { AnCheckId (Next, ASL_TYPE_CID); } } break; default: break; } /* Check for named object creation within a non-serialized method */ MtCheckNamedObjectInMethod (Op, MethodInfo); return (AE_OK); }
void ApCheckForPredefinedObject ( ACPI_PARSE_OBJECT *Op, char *Name) { UINT32 Index; /* * Check for a real predefined name -- not a resource descriptor name * or a predefined scope name */ Index = ApCheckForPredefinedName (Op, Name); switch (Index) { case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Nothing to do */ return; case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ /* * These names must be control methods, by definition in ACPI spec. * Also because they are defined to return no value. None of them * require any arguments. */ AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with zero arguments"); return; default: /* A standard predefined ACPI name */ /* * If this predefined name requires input arguments, then * it must be implemented as a control method */ if (PredefinedNames[Index].Info.ParamCount > 0) { AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with arguments"); return; } /* * If no return value is expected from this predefined name, then * it follows that it must be implemented as a control method * (with zero args, because the args > 0 case was handled above) * Examples are: _DIS, _INI, _IRC, _OFF, _ON, _PSx */ if (!PredefinedNames[Index].Info.ExpectedBtypes) { AslError (ASL_ERROR, ASL_MSG_RESERVED_METHOD, Op, "with zero arguments"); return; } /* Typecheck the actual object, it is the next argument */ ApCheckObjectType (PredefinedNames[Index].Info.Name, Op->Asl.Child->Asl.Next, PredefinedNames[Index].Info.ExpectedBtypes); return; } }
void ApCheckPredefinedReturnValue ( ACPI_PARSE_OBJECT *Op, ASL_METHOD_INFO *MethodInfo) { UINT32 Index; ACPI_PARSE_OBJECT *ReturnValueOp; /* Check parent method for a match against the predefined name list */ Index = ApCheckForPredefinedName (MethodInfo->Op, MethodInfo->Op->Asl.NameSeg); switch (Index) { case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ /* No return value expected, warn if there is one */ ApCheckForUnexpectedReturnValue (Op, MethodInfo); return; case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Just return, nothing to do */ return; default: /* A standard predefined ACPI name */ if (!PredefinedNames[Index].Info.ExpectedBtypes) { /* No return value expected, warn if there is one */ ApCheckForUnexpectedReturnValue (Op, MethodInfo); return; } /* Get the object returned, it is the next argument */ ReturnValueOp = Op->Asl.Child; switch (ReturnValueOp->Asl.ParseOpcode) { case PARSEOP_ZERO: case PARSEOP_ONE: case PARSEOP_ONES: case PARSEOP_INTEGER: case PARSEOP_STRING_LITERAL: case PARSEOP_BUFFER: case PARSEOP_PACKAGE: /* Static data return object - check against expected type */ ApCheckObjectType (PredefinedNames[Index].Info.Name, ReturnValueOp, PredefinedNames[Index].Info.ExpectedBtypes); break; default: /* * All other ops are very difficult or impossible to typecheck at * compile time. These include all Localx, Argx, and method * invocations. Also, NAMESEG and NAMESTRING because the type of * any named object can be changed at runtime (for example, * CopyObject will change the type of the target object.) */ break; } } }
BOOLEAN ApCheckForPredefinedMethod ( ACPI_PARSE_OBJECT *Op, ASL_METHOD_INFO *MethodInfo) { UINT32 Index; UINT32 RequiredArgsCurrent; UINT32 RequiredArgsOld; /* Check for a match against the predefined name list */ Index = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); switch (Index) { case ACPI_NOT_RESERVED_NAME: /* No underscore or _Txx or _xxx name not matched */ case ACPI_PREDEFINED_NAME: /* Resource Name or reserved scope name */ case ACPI_COMPILER_RESERVED_NAME: /* A _Txx that was not emitted by compiler */ /* Just return, nothing to do */ return (FALSE); case ACPI_EVENT_RESERVED_NAME: /* _Lxx/_Exx/_Wxx/_Qxx methods */ Gbl_ReservedMethods++; /* NumArguments must be zero for all _Lxx/_Exx/_Wxx/_Qxx methods */ if (MethodInfo->NumArguments != 0) { sprintf (MsgBuffer, "%s requires %u", Op->Asl.ExternalName, 0); AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, MsgBuffer); } break; default: /* * Matched a predefined method name * * Validate the ASL-defined argument count. Allow two different legal * arg counts. */ Gbl_ReservedMethods++; RequiredArgsCurrent = PredefinedNames[Index].Info.ParamCount & 0x0F; RequiredArgsOld = PredefinedNames[Index].Info.ParamCount >> 4; if ((MethodInfo->NumArguments != RequiredArgsCurrent) && (MethodInfo->NumArguments != RequiredArgsOld)) { sprintf (MsgBuffer, "%4.4s requires %u", PredefinedNames[Index].Info.Name, RequiredArgsCurrent); if (MethodInfo->NumArguments > RequiredArgsCurrent) { AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_HI, Op, MsgBuffer); } else { AslError (ASL_WARNING, ASL_MSG_RESERVED_ARG_COUNT_LO, Op, MsgBuffer); } } /* * Check if method returns no value, but the predefined name is * required to return a value */ if (MethodInfo->NumReturnNoValue && PredefinedNames[Index].Info.ExpectedBtypes) { ApGetExpectedTypes (StringBuffer, PredefinedNames[Index].Info.ExpectedBtypes); sprintf (MsgBuffer, "%s required for %4.4s", StringBuffer, PredefinedNames[Index].Info.Name); AslError (ASL_WARNING, ASL_MSG_RESERVED_RETURN_VALUE, Op, MsgBuffer); } break; } return (TRUE); }
ACPI_STATUS AnMethodAnalysisWalkBegin ( ACPI_PARSE_OBJECT *Op, UINT32 Level, void *Context) { ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context; ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack; ACPI_PARSE_OBJECT *Next; UINT32 RegisterNumber; UINT32 i; char LocalName[] = "Local0"; char ArgName[] = "Arg0"; ACPI_PARSE_OBJECT *ArgNode; ACPI_PARSE_OBJECT *NextType; ACPI_PARSE_OBJECT *NextParamType; UINT8 ActualArgs = 0; switch (Op->Asl.ParseOpcode) { case PARSEOP_METHOD: TotalMethods++; /* Create and init method info */ MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO)); MethodInfo->Next = WalkInfo->MethodStack; MethodInfo->Op = Op; WalkInfo->MethodStack = MethodInfo; /* Get the name node, ignored here */ Next = Op->Asl.Child; /* Get the NumArguments node */ Next = Next->Asl.Next; MethodInfo->NumArguments = (UINT8) (((UINT8) Next->Asl.Value.Integer) & 0x07); /* Get the SerializeRule and SyncLevel nodes, ignored here */ Next = Next->Asl.Next; Next = Next->Asl.Next; ArgNode = Next; /* Get the ReturnType node */ Next = Next->Asl.Next; NextType = Next->Asl.Child; while (NextType) { /* Get and map each of the ReturnTypes */ MethodInfo->ValidReturnTypes |= AnMapObjTypeToBtype (NextType); NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; NextType = NextType->Asl.Next; } /* Get the ParameterType node */ Next = Next->Asl.Next; NextType = Next->Asl.Child; while (NextType) { if (NextType->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG) { NextParamType = NextType->Asl.Child; while (NextParamType) { MethodInfo->ValidArgTypes[ActualArgs] |= AnMapObjTypeToBtype (NextParamType); NextParamType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; NextParamType = NextParamType->Asl.Next; } } else { MethodInfo->ValidArgTypes[ActualArgs] = AnMapObjTypeToBtype (NextType); NextType->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG; ActualArgs++; } NextType = NextType->Asl.Next; } if ((MethodInfo->NumArguments) && (MethodInfo->NumArguments != ActualArgs)) { /* error: Param list did not match number of args */ } /* Allow numarguments == 0 for Function() */ if ((!MethodInfo->NumArguments) && (ActualArgs)) { MethodInfo->NumArguments = ActualArgs; ArgNode->Asl.Value.Integer |= ActualArgs; } /* * Actual arguments are initialized at method entry. * All other ArgX "registers" can be used as locals, so we * track their initialization. */ for (i = 0; i < MethodInfo->NumArguments; i++) { MethodInfo->ArgInitialized[i] = TRUE; } break; case PARSEOP_METHODCALL: if (MethodInfo && (Op->Asl.Node == MethodInfo->Op->Asl.Node)) { AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName); } break; case PARSEOP_LOCAL0: case PARSEOP_LOCAL1: case PARSEOP_LOCAL2: case PARSEOP_LOCAL3: case PARSEOP_LOCAL4: case PARSEOP_LOCAL5: case PARSEOP_LOCAL6: case PARSEOP_LOCAL7: if (!MethodInfo) { /* * Local was used outside a control method, or there was an error * in the method declaration. */ AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); return (AE_ERROR); } RegisterNumber = (Op->Asl.AmlOpcode & 0x000F); /* * If the local is being used as a target, mark the local * initialized */ if (Op->Asl.CompileFlags & NODE_IS_TARGET) { MethodInfo->LocalInitialized[RegisterNumber] = TRUE; } /* * Otherwise, this is a reference, check if the local * has been previously initialized. * * The only operator that accepts an uninitialized value is ObjectType() */ else if ((!MethodInfo->LocalInitialized[RegisterNumber]) && (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) { LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30); AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName); } break; case PARSEOP_ARG0: case PARSEOP_ARG1: case PARSEOP_ARG2: case PARSEOP_ARG3: case PARSEOP_ARG4: case PARSEOP_ARG5: case PARSEOP_ARG6: if (!MethodInfo) { /* * Arg was used outside a control method, or there was an error * in the method declaration. */ AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD, Op, Op->Asl.ExternalName); return (AE_ERROR); } RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8; ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30); /* * If the Arg is being used as a target, mark the local * initialized */ if (Op->Asl.CompileFlags & NODE_IS_TARGET) { MethodInfo->ArgInitialized[RegisterNumber] = TRUE; } /* * Otherwise, this is a reference, check if the Arg * has been previously initialized. * * The only operator that accepts an uninitialized value is ObjectType() */ else if ((!MethodInfo->ArgInitialized[RegisterNumber]) && (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE)) { AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName); } /* Flag this arg if it is not a "real" argument to the method */ if (RegisterNumber >= MethodInfo->NumArguments) { AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName); } break; case PARSEOP_RETURN: if (!MethodInfo) { /* * Probably was an error in the method declaration, * no additional error here */ ACPI_WARNING ((AE_INFO, "%p, No parent method", Op)); return (AE_ERROR); } /* Child indicates a return value */ if ((Op->Asl.Child) && (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)) { MethodInfo->NumReturnWithValue++; } else { MethodInfo->NumReturnNoValue++; } break; case PARSEOP_BREAK: case PARSEOP_CONTINUE: Next = Op->Asl.Parent; while (Next) { if (Next->Asl.ParseOpcode == PARSEOP_WHILE) { break; } Next = Next->Asl.Parent; } if (!Next) { AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL); } break; case PARSEOP_STALL: /* We can range check if the argument is an integer */ if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) && (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX)) { AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL); } break; case PARSEOP_DEVICE: case PARSEOP_EVENT: case PARSEOP_MUTEX: case PARSEOP_OPERATIONREGION: case PARSEOP_POWERRESOURCE: case PARSEOP_PROCESSOR: case PARSEOP_THERMALZONE: /* * The first operand is a name to be created in the namespace. * Check against the reserved list. */ i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg); if (i < ACPI_VALID_RESERVED_NAME_MAX) { AslError (ASL_ERROR, ASL_MSG_RESERVED_USE, Op, Op->Asl.ExternalName); } break; case PARSEOP_NAME: /* Typecheck any predefined names statically defined with Name() */ ApCheckForPredefinedObject (Op, Op->Asl.NameSeg); /* Special typechecking for _HID */ if (!ACPI_STRCMP (METHOD_NAME__HID, Op->Asl.NameSeg)) { Next = Op->Asl.Child->Asl.Next; AnCheckId (Next, ASL_TYPE_HID); } /* Special typechecking for _CID */ else if (!ACPI_STRCMP (METHOD_NAME__CID, Op->Asl.NameSeg)) { Next = Op->Asl.Child->Asl.Next; if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) || (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) { Next = Next->Asl.Child; while (Next) { AnCheckId (Next, ASL_TYPE_CID); Next = Next->Asl.Next; } } else { AnCheckId (Next, ASL_TYPE_CID); } } break; default: break; } return (AE_OK); }