| /****************************************************************************** |
| * |
| * Module Name: aslxref - Namespace cross-reference |
| * |
| *****************************************************************************/ |
| |
| /* |
| * Copyright (C) 2000 - 2023, Intel Corp. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions, and the following disclaimer, |
| * without modification. |
| * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
| * substantially similar to the "NO WARRANTY" disclaimer below |
| * ("Disclaimer") and any redistribution must be conditioned upon |
| * including a substantially similar Disclaimer requirement for further |
| * binary redistribution. |
| * 3. Neither the names of the above-listed copyright holders nor the names |
| * of any contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * Alternatively, this software may be distributed under the terms of the |
| * GNU General Public License ("GPL") version 2 as published by the Free |
| * Software Foundation. |
| * |
| * NO WARRANTY |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGES. |
| */ |
| |
| #include "aslcompiler.h" |
| #include "aslcompiler.y.h" |
| #include "acparser.h" |
| #include "amlcode.h" |
| #include "acnamesp.h" |
| #include "acdispat.h" |
| |
| |
| #define _COMPONENT ACPI_COMPILER |
| ACPI_MODULE_NAME ("aslxref") |
| |
| /* Local prototypes */ |
| |
| static ACPI_STATUS |
| XfNamespaceLocateBegin ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context); |
| |
| static ACPI_STATUS |
| XfNamespaceLocateEnd ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context); |
| |
| static BOOLEAN |
| XfValidateCrossReference ( |
| ACPI_PARSE_OBJECT *Op, |
| const ACPI_OPCODE_INFO *OpInfo, |
| ACPI_NAMESPACE_NODE *Node); |
| |
| static BOOLEAN |
| XfObjectExists ( |
| char *Name); |
| |
| static ACPI_STATUS |
| XfCompareOneNamespaceObject ( |
| ACPI_HANDLE ObjHandle, |
| UINT32 Level, |
| void *Context, |
| void **ReturnValue); |
| |
| static void |
| XfCheckFieldRange ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 RegionBitLength, |
| UINT32 FieldBitOffset, |
| UINT32 FieldBitLength, |
| UINT32 AccessBitWidth); |
| |
| static BOOLEAN |
| XfFindCondRefOfName ( |
| ACPI_NAMESPACE_NODE *Node, |
| ACPI_PARSE_OBJECT *Op); |
| |
| static BOOLEAN |
| XfRefIsGuardedByIfCondRefOf ( |
| ACPI_NAMESPACE_NODE *Node, |
| ACPI_PARSE_OBJECT *Op); |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfCrossReferenceNamespace |
| * |
| * PARAMETERS: None |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Perform a cross reference check of the parse tree against the |
| * namespace. Every named referenced within the parse tree |
| * should be get resolved with a namespace lookup. If not, the |
| * original reference in the ASL code is invalid -- i.e., refers |
| * to a non-existent object. |
| * |
| * NOTE: The ASL "External" operator causes the name to be inserted into the |
| * namespace so that references to the external name will be resolved |
| * correctly here. |
| * |
| ******************************************************************************/ |
| |
| ACPI_STATUS |
| XfCrossReferenceNamespace ( |
| void) |
| { |
| ACPI_WALK_STATE *WalkState; |
| |
| |
| /* |
| * Create a new walk state for use when looking up names |
| * within the namespace (Passed as context to the callbacks) |
| */ |
| WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL); |
| if (!WalkState) |
| { |
| return (AE_NO_MEMORY); |
| } |
| |
| /* Walk the entire parse tree */ |
| |
| TrWalkParseTree (AslGbl_ParseTreeRoot, ASL_WALK_VISIT_TWICE, |
| XfNamespaceLocateBegin, XfNamespaceLocateEnd, WalkState); |
| |
| ACPI_FREE (WalkState); |
| return (AE_OK); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfObjectExists |
| * |
| * PARAMETERS: Name - 4 char ACPI name |
| * |
| * RETURN: TRUE if name exists in namespace |
| * |
| * DESCRIPTION: Walk the namespace to find an object |
| * |
| ******************************************************************************/ |
| |
| static BOOLEAN |
| XfObjectExists ( |
| char *Name) |
| { |
| ACPI_STATUS Status; |
| |
| |
| /* Walk entire namespace from the supplied root */ |
| |
| Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, |
| ACPI_UINT32_MAX, FALSE, XfCompareOneNamespaceObject, NULL, |
| Name, NULL); |
| if (Status == AE_CTRL_TRUE) |
| { |
| /* At least one instance of the name was found */ |
| |
| return (TRUE); |
| } |
| |
| return (FALSE); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfCompareOneNamespaceObject |
| * |
| * PARAMETERS: ACPI_WALK_CALLBACK |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Compare name of one object. |
| * |
| ******************************************************************************/ |
| |
| static ACPI_STATUS |
| XfCompareOneNamespaceObject ( |
| ACPI_HANDLE ObjHandle, |
| UINT32 Level, |
| void *Context, |
| void **ReturnValue) |
| { |
| ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle; |
| |
| |
| /* Simply check the name */ |
| |
| if (*((UINT32 *) (Context)) == Node->Name.Integer) |
| { |
| /* Abort walk if we found one instance */ |
| |
| return (AE_CTRL_TRUE); |
| } |
| |
| return (AE_OK); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfCheckFieldRange |
| * |
| * PARAMETERS: RegionBitLength - Length of entire parent region |
| * FieldBitOffset - Start of the field unit (within region) |
| * FieldBitLength - Entire length of field unit |
| * AccessBitWidth - Access width of the field unit |
| * |
| * RETURN: None |
| * |
| * DESCRIPTION: Check one field unit to make sure it fits in the parent |
| * op region. |
| * |
| * Note: AccessBitWidth must be either 8,16,32, or 64 |
| * |
| ******************************************************************************/ |
| |
| static void |
| XfCheckFieldRange ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 RegionBitLength, |
| UINT32 FieldBitOffset, |
| UINT32 FieldBitLength, |
| UINT32 AccessBitWidth) |
| { |
| UINT32 FieldEndBitOffset; |
| |
| |
| /* |
| * Check each field unit against the region size. The entire |
| * field unit (start offset plus length) must fit within the |
| * region. |
| */ |
| FieldEndBitOffset = FieldBitOffset + FieldBitLength; |
| |
| if (FieldEndBitOffset > RegionBitLength) |
| { |
| /* Field definition itself is beyond the end-of-region */ |
| |
| AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_OFFSET, Op, NULL); |
| return; |
| } |
| |
| /* |
| * Now check that the field plus AccessWidth doesn't go beyond |
| * the end-of-region. Assumes AccessBitWidth is a power of 2 |
| */ |
| FieldEndBitOffset = ACPI_ROUND_UP (FieldEndBitOffset, AccessBitWidth); |
| |
| if (FieldEndBitOffset > RegionBitLength) |
| { |
| /* Field definition combined with the access is beyond EOR */ |
| |
| AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, Op, NULL); |
| } |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfNamespaceLocateBegin |
| * |
| * PARAMETERS: ASL_WALK_CALLBACK |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Descending callback used during cross-reference. For named |
| * object references, attempt to locate the name in the |
| * namespace. |
| * |
| * NOTE: ASL references to named fields within resource descriptors are |
| * resolved to integer values here. Therefore, this step is an |
| * important part of the code generation. We don't know that the |
| * name refers to a resource descriptor until now. |
| * |
| ******************************************************************************/ |
| |
| static ACPI_STATUS |
| XfNamespaceLocateBegin ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context) |
| { |
| ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; |
| ACPI_NAMESPACE_NODE *Node; |
| ACPI_STATUS Status; |
| ACPI_OBJECT_TYPE ObjectType; |
| char *Path; |
| UINT8 PassedArgs; |
| ACPI_PARSE_OBJECT *NextOp; |
| ACPI_PARSE_OBJECT *OwningOp; |
| ACPI_PARSE_OBJECT *SpaceIdOp; |
| UINT32 MinimumLength; |
| UINT32 Offset; |
| UINT32 FieldBitLength; |
| UINT32 TagBitLength; |
| UINT8 Message = 0; |
| const ACPI_OPCODE_INFO *OpInfo; |
| UINT32 Flags; |
| ASL_METHOD_LOCAL *MethodLocals = NULL; |
| ASL_METHOD_LOCAL *MethodArgs = NULL; |
| int RegisterNumber; |
| UINT32 i; |
| ACPI_NAMESPACE_NODE *DeclarationParentMethod; |
| ACPI_PARSE_OBJECT *ReferenceParentMethod; |
| char *ExternalPath; |
| |
| |
| ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op); |
| |
| |
| if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node) |
| { |
| Node = Op->Asl.Node; |
| |
| /* Support for method LocalX/ArgX analysis */ |
| |
| if (!Node->MethodLocals) |
| { |
| /* Create local/arg info blocks */ |
| |
| MethodLocals = UtLocalCalloc ( |
| sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS); |
| Node->MethodLocals = MethodLocals; |
| |
| MethodArgs = UtLocalCalloc ( |
| sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS); |
| Node->MethodArgs = MethodArgs; |
| |
| /* |
| * Get the method argument count |
| * First, get the name node |
| */ |
| NextOp = Op->Asl.Child; |
| |
| /* Get the NumArguments node */ |
| |
| NextOp = NextOp->Asl.Next; |
| Node->ArgCount = (UINT8) |
| (((UINT8) NextOp->Asl.Value.Integer) & 0x07); |
| |
| /* We will track all possible ArgXs */ |
| |
| for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) |
| { |
| if (i < Node->ArgCount) |
| { |
| /* Real Args are always "initialized" */ |
| |
| MethodArgs[i].Flags = ASL_ARG_INITIALIZED; |
| } |
| else |
| { |
| /* Other ArgXs can be used as locals */ |
| |
| MethodArgs[i].Flags = ASL_ARG_IS_LOCAL; |
| } |
| |
| MethodArgs[i].Op = Op; |
| } |
| } |
| } |
| |
| /* |
| * If this node is the actual declaration of a name |
| * [such as the XXXX name in "Method (XXXX)"], |
| * we are not interested in it here. We only care about names that are |
| * references to other objects within the namespace and the parent objects |
| * of name declarations |
| */ |
| if (Op->Asl.CompileFlags & OP_IS_NAME_DECLARATION) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); |
| |
| /* Check method LocalX variables */ |
| |
| if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE) |
| { |
| /* Find parent method Op */ |
| |
| NextOp = UtGetParentMethodOp (Op); |
| if (!NextOp) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Get method node */ |
| |
| Node = NextOp->Asl.Node; |
| |
| RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */ |
| MethodLocals = Node->MethodLocals; |
| |
| if (Op->Asl.CompileFlags & OP_IS_TARGET) |
| { |
| /* Local is being initialized */ |
| |
| MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED; |
| MethodLocals[RegisterNumber].Op = Op; |
| |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Mark this Local as referenced */ |
| |
| MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED; |
| MethodLocals[RegisterNumber].Op = Op; |
| |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Check method ArgX variables */ |
| |
| if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT) |
| { |
| /* Find parent method Op */ |
| |
| NextOp = UtGetParentMethodOp (Op); |
| if (!NextOp) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Get method node */ |
| |
| Node = NextOp->Asl.Node; |
| |
| /* Get Arg # */ |
| |
| RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */ |
| MethodArgs = Node->MethodArgs; |
| |
| /* Mark this Arg as referenced */ |
| |
| MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED; |
| MethodArgs[RegisterNumber].Op = Op; |
| |
| if (Op->Asl.CompileFlags & OP_IS_TARGET) |
| { |
| /* Arg is being initialized */ |
| |
| MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED; |
| } |
| |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* |
| * After method ArgX and LocalX, we are only interested in opcodes |
| * that have an associated name |
| */ |
| if ((!(OpInfo->Flags & AML_NAMED)) && |
| (!(OpInfo->Flags & AML_CREATE)) && |
| (Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) && |
| (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) && |
| (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) && |
| (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL)) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* |
| * We must enable the "search-to-root" for single NameSegs, but |
| * we have to be very careful about opening up scopes |
| */ |
| Flags = ACPI_NS_SEARCH_PARENT; |
| if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || |
| (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || |
| (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || |
| (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL) || |
| (Op->Asl.ParseOpcode == PARSEOP_CONDREFOF)) |
| { |
| /* |
| * These are name references, do not push the scope stack |
| * for them. |
| */ |
| Flags |= ACPI_NS_DONT_OPEN_SCOPE; |
| } |
| |
| /* Get the NamePath from the appropriate place */ |
| |
| if (OpInfo->Flags & AML_NAMED) |
| { |
| /* For nearly all NAMED operators, the name reference is the first child */ |
| |
| Path = Op->Asl.Child->Asl.Value.String; |
| if (Op->Asl.AmlOpcode == AML_ALIAS_OP) |
| { |
| /* |
| * ALIAS is the only oddball opcode, the name declaration |
| * (alias name) is the second operand |
| */ |
| Path = Op->Asl.Child->Asl.Next->Asl.Value.String; |
| } |
| } |
| else if (OpInfo->Flags & AML_CREATE) |
| { |
| /* Name must appear as the last parameter */ |
| |
| NextOp = Op->Asl.Child; |
| while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION)) |
| { |
| NextOp = NextOp->Asl.Next; |
| } |
| |
| Path = NextOp->Asl.Value.String; |
| } |
| else |
| { |
| Path = Op->Asl.Value.String; |
| } |
| |
| ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode); |
| ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
| "Type=%s\n", AcpiUtGetTypeName (ObjectType))); |
| |
| /* |
| * Lookup the name in the namespace. Name must exist at this point, or it |
| * is an invalid reference. |
| * |
| * The namespace is also used as a lookup table for references to resource |
| * descriptors and the fields within them. |
| */ |
| AslGbl_NsLookupCount++; |
| |
| Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, |
| ACPI_IMODE_EXECUTE, Flags, WalkState, &Node); |
| if (ACPI_FAILURE (Status)) |
| { |
| if (Status == AE_NOT_FOUND) |
| { |
| /* |
| * We didn't find the name reference by path -- we can qualify this |
| * a little better before we print an error message |
| */ |
| |
| if ((Op->Asl.Parent) && |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF)) |
| { |
| /* |
| * One special case: CondRefOf operator - if the name doesn't |
| * exist at this point, it means that there's no actual or |
| * external declaration. If the name is not found, just ignore |
| * it, the point of the operator is to determine if the name |
| * exists at runtime. We wanted to see if this named object |
| * exists to facilitate analysis to allow protected usage of |
| * undeclared externals. |
| */ |
| return_ACPI_STATUS (AE_OK); |
| } |
| else if (strlen (Path) == ACPI_NAMESEG_SIZE) |
| { |
| /* A simple, one-segment ACPI name */ |
| |
| if (XfObjectExists (Path)) |
| { |
| /* |
| * There exists such a name, but we couldn't get to it |
| * from this scope |
| */ |
| AslError (ASL_ERROR, ASL_MSG_NOT_REACHABLE, Op, |
| Op->Asl.ExternalName); |
| } |
| else |
| { |
| /* The name doesn't exist, period */ |
| |
| AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, |
| Op, Op->Asl.ExternalName); |
| } |
| } |
| else |
| { |
| /* The NamePath contains multiple NameSegs */ |
| |
| if ((OpInfo->Flags & AML_CREATE) || |
| (OpInfo->ObjectType == ACPI_TYPE_LOCAL_ALIAS)) |
| { |
| /* |
| * The new name is the last parameter. For the |
| * CreateXXXXField and Alias operators |
| */ |
| NextOp = Op->Asl.Child; |
| while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION)) |
| { |
| NextOp = NextOp->Asl.Next; |
| } |
| |
| AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, NextOp, |
| NextOp->Asl.ExternalName); |
| } |
| else if (OpInfo->Flags & AML_NAMED) |
| { |
| /* The new name is the first parameter */ |
| |
| AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, Op, |
| Op->Asl.ExternalName); |
| } |
| else if (Path[0] == AML_ROOT_PREFIX) |
| { |
| /* Full namepath from root, the object does not exist */ |
| |
| AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, Op, |
| Op->Asl.ExternalName); |
| } |
| else |
| { |
| /* |
| * Generic "not found" error. Cannot determine whether it |
| * doesn't exist or just can't be reached. However, we |
| * can differentiate between a NameSeg vs. NamePath. |
| */ |
| if (strlen (Op->Asl.ExternalName) == ACPI_NAMESEG_SIZE) |
| { |
| AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op, |
| Op->Asl.ExternalName); |
| } |
| else |
| { |
| AslError (ASL_ERROR, ASL_MSG_NAMEPATH_NOT_EXIST, Op, |
| Op->Asl.ExternalName); |
| } |
| } |
| } |
| |
| Status = AE_OK; |
| } |
| |
| return_ACPI_STATUS (Status); |
| } |
| |
| /* Check for an attempt to access an object in another method */ |
| |
| if (!XfValidateCrossReference (Op, OpInfo, Node)) |
| { |
| AslError (ASL_ERROR, ASL_MSG_TEMPORARY_OBJECT, Op, |
| Op->Asl.ExternalName); |
| return_ACPI_STATUS (Status); |
| } |
| |
| /* Object was found above, check for an illegal forward reference */ |
| |
| if (Op->Asl.CompileFlags & OP_NOT_FOUND_DURING_LOAD) |
| { |
| /* |
| * During the load phase, this Op was flagged as a possible |
| * illegal forward reference. In other words, Op is a name path or |
| * name segment that refers to a named object declared after the |
| * reference. In this scinario, Node refers to the actual declaration |
| * and Op is a parse node that references the named object. |
| * |
| * Note: |
| * |
| * Object references inside of control methods are allowed to |
| * refer to objects declared outside of control methods. |
| * |
| * If the declaration and reference are both contained inside of the |
| * same method or outside of any method, this is a forward reference |
| * and should be reported as a compiler error. |
| */ |
| DeclarationParentMethod = UtGetParentMethodNode (Node); |
| ReferenceParentMethod = UtGetParentMethodOp (Op); |
| |
| /* case 1: declaration and reference are both outside of method */ |
| |
| if (!ReferenceParentMethod && !DeclarationParentMethod) |
| { |
| AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, |
| Op->Asl.ExternalName); |
| } |
| |
| /* case 2: declaration and reference are both inside of the same method */ |
| |
| else if (ReferenceParentMethod && DeclarationParentMethod && |
| ReferenceParentMethod == DeclarationParentMethod->Op) |
| { |
| AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op, |
| Op->Asl.ExternalName); |
| } |
| } |
| |
| /* Check for a reference vs. name declaration */ |
| |
| if (!(OpInfo->Flags & AML_NAMED) && |
| !(OpInfo->Flags & AML_CREATE)) |
| { |
| /* This node has been referenced, mark it for reference check */ |
| |
| Node->Flags |= ANOBJ_IS_REFERENCED; |
| } |
| |
| /* |
| * Attempt to optimize the NamePath |
| * |
| * One special case: CondRefOf operator - not all AML interpreter |
| * implementations expect optimized namepaths as a parameter to this |
| * operator. They require relative name paths with prefix operators or |
| * namepaths starting with the root scope. |
| * |
| * Other AML interpreter implementations do not perform the namespace |
| * search that starts at the current scope and recursively searching the |
| * parent scope until the root scope. The lack of search is only known to |
| * occur for the namestring parameter for the CondRefOf operator. |
| */ |
| if ((Op->Asl.Parent) && |
| (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_CONDREFOF)) |
| { |
| OptOptimizeNamePath (Op, OpInfo->Flags, WalkState, Path, Node); |
| } |
| |
| /* |
| * 1) Dereference an alias (A name reference that is an alias) |
| * Aliases are not nested, the alias always points to the final object |
| */ |
| if ((Op->Asl.ParseOpcode != PARSEOP_ALIAS) && |
| (Node->Type == ACPI_TYPE_LOCAL_ALIAS)) |
| { |
| /* This node points back to the original PARSEOP_ALIAS */ |
| |
| NextOp = Node->Op; |
| |
| /* The first child is the alias target op */ |
| |
| NextOp = NextOp->Asl.Child; |
| |
| /* That in turn points back to original target alias node */ |
| |
| if (NextOp->Asl.Node) |
| { |
| Node = NextOp->Asl.Node; |
| } |
| |
| /* Else - forward reference to alias, will be resolved later */ |
| } |
| |
| /* 2) Check for a reference to a resource descriptor */ |
| |
| if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) || |
| (Node->Type == ACPI_TYPE_LOCAL_RESOURCE)) |
| { |
| /* |
| * This was a reference to a field within a resource descriptor. |
| * Extract the associated field offset (either a bit or byte |
| * offset depending on the field type) and change the named |
| * reference into an integer for AML code generation |
| */ |
| Offset = Node->Value; |
| TagBitLength = Node->Length; |
| |
| /* |
| * If a field is being created, generate the length (in bits) of |
| * the field. Note: Opcodes other than CreateXxxField and Index |
| * can come through here. For other opcodes, we just need to |
| * convert the resource tag reference to an integer offset. |
| */ |
| switch (Op->Asl.Parent->Asl.AmlOpcode) |
| { |
| case AML_CREATE_FIELD_OP: /* Variable "Length" field, in bits */ |
| /* |
| * We know the length operand is an integer constant because |
| * we know that it contains a reference to a resource |
| * descriptor tag. |
| */ |
| FieldBitLength = (UINT32) Op->Asl.Next->Asl.Value.Integer; |
| break; |
| |
| case AML_CREATE_BIT_FIELD_OP: |
| |
| FieldBitLength = 1; |
| break; |
| |
| case AML_CREATE_BYTE_FIELD_OP: |
| case AML_INDEX_OP: |
| |
| FieldBitLength = 8; |
| break; |
| |
| case AML_CREATE_WORD_FIELD_OP: |
| |
| FieldBitLength = 16; |
| break; |
| |
| case AML_CREATE_DWORD_FIELD_OP: |
| |
| FieldBitLength = 32; |
| break; |
| |
| case AML_CREATE_QWORD_FIELD_OP: |
| |
| FieldBitLength = 64; |
| break; |
| |
| default: |
| |
| FieldBitLength = 0; |
| break; |
| } |
| |
| /* Check the field length against the length of the resource tag */ |
| |
| if (FieldBitLength) |
| { |
| if (TagBitLength < FieldBitLength) |
| { |
| Message = ASL_MSG_TAG_SMALLER; |
| } |
| else if (TagBitLength > FieldBitLength) |
| { |
| Message = ASL_MSG_TAG_LARGER; |
| } |
| |
| if (Message) |
| { |
| sprintf (AslGbl_MsgBuffer, |
| "Size mismatch, Tag: %u bit%s, Field: %u bit%s", |
| TagBitLength, (TagBitLength > 1) ? "s" : "", |
| FieldBitLength, (FieldBitLength > 1) ? "s" : ""); |
| |
| AslError (ASL_WARNING, Message, Op, AslGbl_MsgBuffer); |
| } |
| } |
| |
| /* Convert the BitOffset to a ByteOffset for certain opcodes */ |
| |
| switch (Op->Asl.Parent->Asl.AmlOpcode) |
| { |
| case AML_CREATE_BYTE_FIELD_OP: |
| case AML_CREATE_WORD_FIELD_OP: |
| case AML_CREATE_DWORD_FIELD_OP: |
| case AML_CREATE_QWORD_FIELD_OP: |
| case AML_INDEX_OP: |
| |
| Offset = ACPI_DIV_8 (Offset); |
| break; |
| |
| default: |
| |
| break; |
| } |
| |
| /* Now convert this node to an integer whose value is the field offset */ |
| |
| Op->Asl.AmlLength = 0; |
| Op->Asl.ParseOpcode = PARSEOP_INTEGER; |
| Op->Asl.Value.Integer = (UINT64) Offset; |
| Op->Asl.CompileFlags |= OP_IS_RESOURCE_FIELD; |
| |
| OpcGenerateAmlOpcode (Op); |
| } |
| |
| /* 3) Check for a method invocation */ |
| |
| else if ((((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || (Op->Asl.ParseOpcode == PARSEOP_NAMESEG)) && |
| (Node->Type == ACPI_TYPE_METHOD) && |
| (Op->Asl.Parent) && |
| (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_METHOD)) || |
| |
| (Op->Asl.ParseOpcode == PARSEOP_METHODCALL)) |
| { |
| /* |
| * A reference to a method within one of these opcodes is not an |
| * invocation of the method, it is simply a reference to the method. |
| * |
| * September 2016: Removed DeRefOf from this list |
| * July 2020: Added Alias to this list |
| */ |
| if ((Op->Asl.Parent) && |
| ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) || |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) || |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)|| |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE) || |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_ALIAS))) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* |
| * There are two types of method invocation: |
| * 1) Invocation with arguments -- the parser recognizes this |
| * as a METHODCALL. |
| * 2) Invocation with no arguments --the parser cannot determine that |
| * this is a method invocation, therefore we have to figure it out |
| * here. |
| */ |
| if (Node->Type != ACPI_TYPE_METHOD) |
| { |
| sprintf (AslGbl_MsgBuffer, "%s is a %s", |
| Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type)); |
| |
| AslError (ASL_ERROR, ASL_MSG_NOT_METHOD, Op, AslGbl_MsgBuffer); |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Save the method node in the caller's op */ |
| |
| Op->Asl.Node = Node; |
| if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* |
| * This is a method invocation, with or without arguments. |
| * Count the number of arguments, each appears as a child |
| * under the parent node |
| */ |
| Op->Asl.ParseOpcode = PARSEOP_METHODCALL; |
| UtSetParseOpName (Op); |
| |
| PassedArgs = 0; |
| NextOp = Op->Asl.Child; |
| |
| while (NextOp) |
| { |
| PassedArgs++; |
| NextOp = NextOp->Asl.Next; |
| } |
| |
| if (Node->Value != ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS && |
| Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) |
| { |
| /* |
| * Check the parsed arguments with the number expected by the |
| * method declaration itself |
| */ |
| if (PassedArgs != Node->Value) |
| { |
| if (Node->Flags & ANOBJ_IS_EXTERNAL) |
| { |
| sprintf (AslGbl_MsgBuffer, |
| "according to previous use, %s requires %u", |
| Op->Asl.ExternalName, Node->Value); |
| } |
| else |
| { |
| sprintf (AslGbl_MsgBuffer, "%s requires %u", Op->Asl.ExternalName, |
| Node->Value); |
| } |
| |
| if (PassedArgs < Node->Value) |
| { |
| AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, AslGbl_MsgBuffer); |
| } |
| else |
| { |
| AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_HI, Op, AslGbl_MsgBuffer); |
| } |
| } |
| } |
| |
| /* |
| * At this point, a method call to an external method has been |
| * detected. As of 11/19/2019, iASL does not support parameter counts |
| * for methods declared as external. Therefore, save the parameter |
| * count of the first method call and use this count check other |
| * method calls to ensure that the methods are being called with the |
| * same amount of parameters. |
| */ |
| else if (Node->Type == ACPI_TYPE_METHOD && |
| (Node->Flags & ANOBJ_IS_EXTERNAL) && |
| Node->Value == ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS && |
| Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) |
| { |
| Node->Value = PassedArgs; |
| } |
| } |
| |
| /* 4) Check for an ASL Field definition */ |
| |
| else if ((Op->Asl.Parent) && |
| ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_FIELD) || |
| (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_BANKFIELD))) |
| { |
| /* |
| * Offset checking for fields. If the parent operation region has a |
| * constant length (known at compile time), we can check fields |
| * defined in that region against the region length. This will catch |
| * fields and field units that cannot possibly fit within the region. |
| * |
| * Note: Index fields do not directly reference an operation region, |
| * thus they are not included in this check. |
| */ |
| if (Op == Op->Asl.Parent->Asl.Child) |
| { |
| /* |
| * This is the first child of the field node, which is |
| * the name of the region. Get the parse node for the |
| * region -- which contains the length of the region. |
| */ |
| OwningOp = Node->Op; |
| Op->Asl.Parent->Asl.ExtraValue = |
| ACPI_MUL_8 ((UINT32) OwningOp->Asl.Value.Integer); |
| |
| /* Examine the field access width */ |
| |
| switch ((UINT8) Op->Asl.Parent->Asl.Value.Integer) |
| { |
| case AML_FIELD_ACCESS_ANY: |
| case AML_FIELD_ACCESS_BYTE: |
| case AML_FIELD_ACCESS_BUFFER: |
| default: |
| |
| MinimumLength = 1; |
| break; |
| |
| case AML_FIELD_ACCESS_WORD: |
| |
| MinimumLength = 2; |
| break; |
| |
| case AML_FIELD_ACCESS_DWORD: |
| |
| MinimumLength = 4; |
| break; |
| |
| case AML_FIELD_ACCESS_QWORD: |
| |
| MinimumLength = 8; |
| break; |
| } |
| |
| /* |
| * Is the region at least as big as the access width? |
| * Note: DataTableRegions have 0 length |
| */ |
| if (((UINT32) OwningOp->Asl.Value.Integer) && |
| ((UINT32) OwningOp->Asl.Value.Integer < MinimumLength)) |
| { |
| AslError (ASL_ERROR, ASL_MSG_FIELD_ACCESS_WIDTH, Op, NULL); |
| } |
| |
| /* |
| * Check EC/CMOS/SMBUS fields to make sure that the correct |
| * access type is used (BYTE for EC/CMOS, BUFFER for SMBUS) |
| */ |
| SpaceIdOp = OwningOp->Asl.Child->Asl.Next; |
| switch ((UINT32) SpaceIdOp->Asl.Value.Integer) |
| { |
| case ACPI_ADR_SPACE_EC: |
| case ACPI_ADR_SPACE_CMOS: |
| case ACPI_ADR_SPACE_GPIO: |
| |
| if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != |
| AML_FIELD_ACCESS_BYTE) |
| { |
| AslError (ASL_ERROR, ASL_MSG_REGION_BYTE_ACCESS, Op, NULL); |
| } |
| break; |
| |
| case ACPI_ADR_SPACE_SMBUS: |
| case ACPI_ADR_SPACE_IPMI: |
| case ACPI_ADR_SPACE_GSBUS: |
| |
| if ((UINT8) Op->Asl.Parent->Asl.Value.Integer != |
| AML_FIELD_ACCESS_BUFFER) |
| { |
| AslError (ASL_ERROR, ASL_MSG_REGION_BUFFER_ACCESS, Op, NULL); |
| } |
| break; |
| |
| default: |
| |
| /* Nothing to do for other address spaces */ |
| |
| break; |
| } |
| } |
| else |
| { |
| /* |
| * This is one element of the field list. Check to make sure |
| * that it does not go beyond the end of the parent operation region. |
| * |
| * In the code below: |
| * Op->Asl.Parent->Asl.ExtraValue - Region Length (bits) |
| * Op->Asl.ExtraValue - Field start offset (bits) |
| * Op->Asl.Child->Asl.Value.Integer32 - Field length (bits) |
| * Op->Asl.Child->Asl.ExtraValue - Field access width (bits) |
| */ |
| if (Op->Asl.Parent->Asl.ExtraValue && Op->Asl.Child) |
| { |
| XfCheckFieldRange (Op, |
| Op->Asl.Parent->Asl.ExtraValue, |
| Op->Asl.ExtraValue, |
| (UINT32) Op->Asl.Child->Asl.Value.Integer, |
| Op->Asl.Child->Asl.ExtraValue); |
| } |
| } |
| } |
| |
| /* |
| * 5) Check for external resolution |
| * |
| * By this point, everything should be loaded in the namespace. If a |
| * namespace lookup results in a namespace node that is an external, it |
| * means that this named object was not defined in the input ASL. This |
| * causes issues because there are plenty of incidents where developers |
| * use the external keyword to suppress compiler errors about undefined |
| * objects. Note: this only applies when compiling multiple definition |
| * blocks. |
| * |
| * Do not check for external resolution in the following cases: |
| * |
| * case 1) External (ABCD) |
| * |
| * This declares ABCD as an external so there is no requirement for |
| * ABCD to be loaded in the namespace when analyzing the actual |
| * External() statement. |
| * |
| * case 2) CondRefOf (ABCD) |
| * |
| * This operator will query the ACPI namespace on the existence of |
| * ABCD. If ABCD does not exist, this operator will return a 0 |
| * without incurring AML runtime errors. Therefore, ABCD is allowed |
| * to not exist when analyzing the CondRefOf operator. |
| * |
| * case 3) External (ABCD) |
| * if (CondRefOf (ABCD)) |
| * { |
| * Store (0, ABCD) |
| * } |
| * |
| * In this case, ABCD is accessed only if it exists due to the if |
| * statement so there is no need to flag the ABCD nested in the |
| * store operator. |
| */ |
| if (AslGbl_ParseTreeRoot->Asl.Child && AslGbl_ParseTreeRoot->Asl.Child->Asl.Next && |
| (Node->Flags & ANOBJ_IS_EXTERNAL) && |
| Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL && |
| Op->Asl.ParseOpcode != PARSEOP_EXTERNAL && |
| Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_CONDREFOF && |
| !XfRefIsGuardedByIfCondRefOf (Node, Op)) |
| { |
| ExternalPath = AcpiNsGetNormalizedPathname (Node, TRUE); |
| sprintf (AslGbl_MsgBuffer, "full path of external object: %s", |
| ExternalPath); |
| AslDualParseOpError (ASL_ERROR, ASL_MSG_UNDEFINED_EXTERNAL, Op, NULL, |
| ASL_MSG_EXTERNAL_FOUND_HERE, Node->Op, AslGbl_MsgBuffer); |
| if (ExternalPath) |
| { |
| ACPI_FREE (ExternalPath); |
| } |
| } |
| |
| /* 5) Check for a connection object */ |
| #if 0 |
| else if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION) |
| { |
| return_ACPI_STATUS (Status); |
| } |
| #endif |
| |
| Op->Asl.Node = Node; |
| return_ACPI_STATUS (Status); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfRefIsGuardedByIfCondRefOf |
| * |
| * PARAMETERS: Node - Named object reference node |
| * Op - Named object reference parse node |
| * |
| * RETURN: BOOLEAN |
| * |
| * DESCRIPTION: returns true if Op checked inside if (CondRefOf (...)) |
| * refers to Node. |
| * |
| ******************************************************************************/ |
| |
| static BOOLEAN |
| XfRefIsGuardedByIfCondRefOf ( |
| ACPI_NAMESPACE_NODE *Node, |
| ACPI_PARSE_OBJECT *Op) |
| { |
| ACPI_PARSE_OBJECT *Parent = Op->Asl.Parent; |
| |
| |
| while (Parent) |
| { |
| if (Parent->Asl.ParseOpcode == PARSEOP_IF && |
| XfFindCondRefOfName (Node, Parent->Asl.Child)) |
| { |
| return (TRUE); |
| } |
| |
| Parent = Parent->Asl.Parent; |
| } |
| |
| return (FALSE); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfRefIsGuardedByIfCondRefOf |
| * |
| * PARAMETERS: Node - Named object reference node |
| * Op - Named object reference parse node |
| * |
| * RETURN: BOOLEAN |
| * |
| * DESCRIPTION: returns true if Op checked inside if (CondRefOf (...)) |
| * refers to Node. |
| * |
| ******************************************************************************/ |
| |
| static BOOLEAN |
| XfFindCondRefOfName ( |
| ACPI_NAMESPACE_NODE *Node, |
| ACPI_PARSE_OBJECT *Op) |
| { |
| BOOLEAN CondRefOfFound = FALSE; |
| |
| |
| if (!Op) |
| { |
| return (FALSE); |
| } |
| |
| switch (Op->Asl.ParseOpcode) |
| { |
| case PARSEOP_CONDREFOF: |
| |
| return (Op->Asl.Child->Common.Node == Node); |
| break; |
| |
| case PARSEOP_LAND: |
| |
| CondRefOfFound = XfFindCondRefOfName (Node, Op->Asl.Child); |
| if (CondRefOfFound) |
| { |
| return (TRUE); |
| } |
| |
| return (XfFindCondRefOfName (Node, Op->Asl.Child->Asl.Next)); |
| break; |
| |
| default: |
| |
| return (FALSE); |
| break; |
| } |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfNamespaceLocateEnd |
| * |
| * PARAMETERS: ASL_WALK_CALLBACK |
| * |
| * RETURN: Status |
| * |
| * DESCRIPTION: Ascending callback used during cross reference. We only |
| * need to worry about scope management here. |
| * |
| ******************************************************************************/ |
| |
| static ACPI_STATUS |
| XfNamespaceLocateEnd ( |
| ACPI_PARSE_OBJECT *Op, |
| UINT32 Level, |
| void *Context) |
| { |
| ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context; |
| const ACPI_OPCODE_INFO *OpInfo; |
| |
| |
| ACPI_FUNCTION_TRACE (XfNamespaceLocateEnd); |
| |
| |
| /* We are only interested in opcodes that have an associated name */ |
| |
| OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode); |
| if (!(OpInfo->Flags & AML_NAMED)) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Not interested in name references, we did not open a scope for them */ |
| |
| if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || |
| (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) || |
| (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) || |
| (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL)) |
| { |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| /* Pop the scope stack if necessary */ |
| |
| if (AcpiNsOpensScope (AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode))) |
| { |
| |
| ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, |
| "%s: Popping scope for Op %p\n", |
| AcpiUtGetTypeName (OpInfo->ObjectType), Op)); |
| |
| (void) AcpiDsScopeStackPop (WalkState); |
| } |
| |
| return_ACPI_STATUS (AE_OK); |
| } |
| |
| |
| /******************************************************************************* |
| * |
| * FUNCTION: XfValidateCrossReference |
| * |
| * PARAMETERS: Op - Parse Op that references the object |
| * OpInfo - Parse Op info struct |
| * Node - Node for the referenced object |
| * |
| * RETURN: TRUE if the reference is legal, FALSE otherwise |
| * |
| * DESCRIPTION: Determine if a reference to another object is allowed. |
| * |
| * EXAMPLE: |
| * Method (A) {Name (INT1, 1)} Declaration of object INT1 |
| * Method (B) (Store (2, \A.INT1)} Illegal reference to object INT1 |
| * (INT1 is temporary, valid only during |
| * execution of A) |
| * |
| * NOTES: |
| * A null pointer returned by either UtGetParentMethodOp or |
| * UtGetParentMethodNode indicates that the parameter object is not |
| * within a control method. |
| * |
| * Five cases are handled: Case(Op, Node) |
| * 1) Case(0,0): Op is not within a method, Node is not --> OK |
| * 2) Case(0,1): Op is not within a method, but Node is --> Illegal |
| * 3) Case(1,0): Op is within a method, Node is not --> OK |
| * 4) Case(1,1): Both are within the same method --> OK |
| * 5) Case(1,1): Both are in methods, but not same method --> Illegal |
| * |
| ******************************************************************************/ |
| |
| static BOOLEAN |
| XfValidateCrossReference ( |
| ACPI_PARSE_OBJECT *Op, |
| const ACPI_OPCODE_INFO *OpInfo, |
| ACPI_NAMESPACE_NODE *Node) |
| { |
| ACPI_PARSE_OBJECT *ReferencingMethodOp; |
| ACPI_NAMESPACE_NODE *ReferencedMethodNode; |
| |
| |
| /* Ignore actual named (and related) object declarations */ |
| |
| if (OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_DEFER | AML_HAS_ARGS)) |
| { |
| return (TRUE); |
| } |
| |
| /* |
| * 1) Search upwards in parse tree for owner of the referencing object |
| * 2) Search upwards in namespace to find the owner of the referenced object |
| */ |
| ReferencingMethodOp = UtGetParentMethodOp (Op); |
| ReferencedMethodNode = UtGetParentMethodNode (Node); |
| |
| if (!ReferencingMethodOp && !ReferencedMethodNode) |
| { |
| /* |
| * 1) Case (0,0): Both Op and Node are not within methods |
| * --> OK |
| */ |
| return (TRUE); |
| } |
| |
| if (!ReferencingMethodOp && ReferencedMethodNode) |
| { |
| /* |
| * 2) Case (0,1): Op is not in a method, but Node is within a |
| * method --> illegal |
| */ |
| return (FALSE); |
| } |
| else if (ReferencingMethodOp && !ReferencedMethodNode) |
| { |
| /* |
| * 3) Case (1,0): Op is within a method, but Node is not |
| * --> OK |
| */ |
| return (TRUE); |
| } |
| else if (ReferencingMethodOp->Asl.Node == ReferencedMethodNode) |
| { |
| /* |
| * 4) Case (1,1): Both Op and Node are within the same method |
| * --> OK |
| */ |
| return (TRUE); |
| } |
| else |
| { |
| /* |
| * 5) Case (1,1), Op and Node are in different methods |
| * --> Illegal |
| */ |
| return (FALSE); |
| } |
| } |