static ACPI_STATUS AcpiPsCreateOp ( ACPI_WALK_STATE *WalkState, UINT8 *AmlOpStart, ACPI_PARSE_OBJECT **NewOp) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Op; ACPI_PARSE_OBJECT *NamedOp = NULL; ACPI_PARSE_OBJECT *ParentScope; UINT8 ArgumentCount; const ACPI_OPCODE_INFO *OpInfo; ACPI_FUNCTION_TRACE_PTR (PsCreateOp, WalkState); Status = AcpiPsGetAmlOpcode (WalkState); if (Status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); } /* Create Op structure and append to parent's argument list */ WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode); Op = AcpiPsAllocOp (WalkState->Opcode); if (!Op) { return_ACPI_STATUS (AE_NO_MEMORY); } if (WalkState->OpInfo->Flags & AML_NAMED) { Status = AcpiPsBuildNamedOp (WalkState, AmlOpStart, Op, &NamedOp); AcpiPsFreeOp (Op); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } *NewOp = NamedOp; return_ACPI_STATUS (AE_OK); } /* Not a named opcode, just allocate Op and append to parent */ if (WalkState->OpInfo->Flags & AML_CREATE) { /* * Backup to beginning of CreateXXXfield declaration * BodyLength is unknown until we parse the body */ Op->Named.Data = AmlOpStart; Op->Named.Length = 0; } if (WalkState->Opcode == AML_BANK_FIELD_OP) { /* * Backup to beginning of BankField declaration * BodyLength is unknown until we parse the body */ Op->Named.Data = AmlOpStart; Op->Named.Length = 0; } ParentScope = AcpiPsGetParentScope (&(WalkState->ParserState)); AcpiPsAppendArg (ParentScope, Op); if (ParentScope) { OpInfo = AcpiPsGetOpcodeInfo (ParentScope->Common.AmlOpcode); if (OpInfo->Flags & AML_HAS_TARGET) { ArgumentCount = AcpiPsGetArgumentCount (OpInfo->Type); if (ParentScope->Common.ArgListLength > ArgumentCount) { Op->Common.Flags |= ACPI_PARSEOP_TARGET; } } else if (ParentScope->Common.AmlOpcode == AML_INCREMENT_OP) { Op->Common.Flags |= ACPI_PARSEOP_TARGET; } } if (WalkState->DescendingCallback != NULL) { /* * Find the object. This will either insert the object into * the namespace or simply look it up */ WalkState->Op = *NewOp = Op; Status = WalkState->DescendingCallback (WalkState, &Op); Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_CTRL_PARSE_PENDING; } } return_ACPI_STATUS (Status); }
static ACPI_STATUS AcpiPsGetArguments ( ACPI_WALK_STATE *WalkState, UINT8 *AmlOpStart, ACPI_PARSE_OBJECT *Op) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Arg = NULL; const ACPI_OPCODE_INFO *OpInfo; ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState); switch (Op->Common.AmlOpcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ case AML_DWORD_OP: /* AML_DWORDATA_ARG */ case AML_QWORD_OP: /* AML_QWORDATA_ARG */ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ /* Fill in constant or string argument directly */ AcpiPsGetNextSimpleArg (&(WalkState->ParserState), GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op); break; case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ Status = AcpiPsGetNextNamepath (WalkState, &(WalkState->ParserState), Op, 1); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } WalkState->ArgTypes = 0; break; default: /* * Op is not a constant or string, append each argument to the Op */ while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && !WalkState->ArgCount) { WalkState->AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->ParserState.Aml, WalkState->ParserState.AmlStart); Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } if (Arg) { Arg->Common.AmlOffset = WalkState->AmlOffset; AcpiPsAppendArg (Op, Arg); } INCREMENT_ARG_LIST (WalkState->ArgTypes); } /* * Handle executable code at "module-level". This refers to * executable opcodes that appear outside of any control method. */ if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) && ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0)) { /* * We want to skip If/Else/While constructs during Pass1 because we * want to actually conditionally execute the code during Pass2. * * Except for disassembly, where we always want to walk the * If/Else/While packages */ switch (Op->Common.AmlOpcode) { case AML_IF_OP: case AML_ELSE_OP: case AML_WHILE_OP: /* * Currently supported module-level opcodes are: * IF/ELSE/WHILE. These appear to be the most common, * and easiest to support since they open an AML * package. */ if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) { AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart, (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart), WalkState->OwnerId); } ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Pass1: Skipping an If/Else/While body\n")); /* Skip body of if/else/while in pass 1 */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; break; default: /* * Check for an unsupported executable opcode at module * level. We must be in PASS1, the parent must be a SCOPE, * The opcode class must be EXECUTE, and the opcode must * not be an argument to another opcode. */ if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) && (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) { OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); if ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Arg)) { ACPI_WARNING ((AE_INFO, "Unsupported module-level executable opcode " "0x%.2X at table offset 0x%.4X", Op->Common.AmlOpcode, (UINT32) (ACPI_PTR_DIFF (AmlOpStart, WalkState->ParserState.AmlStart) + sizeof (ACPI_TABLE_HEADER)))); } } break; } } /* Special processing for certain opcodes */ switch (Op->Common.AmlOpcode) { case AML_METHOD_OP: /* * Skip parsing of control method because we don't have enough * info in the first pass to parse it correctly. * * Save the length and address of the body */ Op->Named.Data = WalkState->ParserState.Aml; Op->Named.Length = (UINT32) (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml); /* Skip body of method */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; break; case AML_BUFFER_OP: case AML_PACKAGE_OP: case AML_VAR_PACKAGE_OP: if ((Op->Common.Parent) && (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) { /* * Skip parsing of Buffers and Packages because we don't have * enough info in the first pass to parse them correctly. */ Op->Named.Data = AmlOpStart; Op->Named.Length = (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart); /* Skip body */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; } break; case AML_WHILE_OP: if (WalkState->ControlState) { WalkState->ControlState->Control.PackageEnd = WalkState->ParserState.PkgEnd; } break; default: /* No action for all other opcodes */ break; } break; } return_ACPI_STATUS (AE_OK); }
ACPI_STATUS AcpiDsLoad1BeginOp ( ACPI_WALK_STATE *WalkState, ACPI_PARSE_OBJECT **OutOp) { ACPI_PARSE_OBJECT *Op; ACPI_NAMESPACE_NODE *Node; ACPI_STATUS Status; ACPI_OBJECT_TYPE ObjectType; char *Path; UINT32 Flags; ACPI_FUNCTION_TRACE (DsLoad1BeginOp); Op = WalkState->Op; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", Op, WalkState)); /* We are only interested in opcodes that have an associated name */ if (Op) { if (!(WalkState->OpInfo->Flags & AML_NAMED)) { *OutOp = Op; return_ACPI_STATUS (AE_OK); } /* Check if this object has already been installed in the namespace */ if (Op->Common.Node) { *OutOp = Op; return_ACPI_STATUS (AE_OK); } } Path = AcpiPsGetNextNamestring (&WalkState->ParserState); /* Map the raw opcode into an internal object type */ ObjectType = WalkState->OpInfo->ObjectType; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "State=%p Op=%p [%s]\n", WalkState, Op, AcpiUtGetTypeName (ObjectType))); switch (WalkState->Opcode) { case AML_SCOPE_OP: /* * The target name of the Scope() operator must exist at this point so * that we can actually open the scope to enter new names underneath it. * Allow search-to-root for single namesegs. */ Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, WalkState, &(Node)); #ifdef ACPI_ASL_COMPILER if (Status == AE_NOT_FOUND) { /* * Table disassembly: * Target of Scope() not found. Generate an External for it, and * insert the name into the namespace. */ AcpiDmAddOpToExternalList (Op, Path, ACPI_TYPE_DEVICE, 0, 0); Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, WalkState, &Node); } #endif if (ACPI_FAILURE (Status)) { ACPI_ERROR_NAMESPACE (Path, Status); return_ACPI_STATUS (Status); } /* * Check to make sure that the target is * one of the opcodes that actually opens a scope */ switch (Node->Type) { case ACPI_TYPE_ANY: case ACPI_TYPE_LOCAL_SCOPE: /* Scope */ case ACPI_TYPE_DEVICE: case ACPI_TYPE_POWER: case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_THERMAL: /* These are acceptable types */ break; case ACPI_TYPE_INTEGER: case ACPI_TYPE_STRING: case ACPI_TYPE_BUFFER: /* * These types we will allow, but we will change the type. * This enables some existing code of the form: * * Name (DEB, 0) * Scope (DEB) { ... } * * Note: silently change the type here. On the second pass, * we will report a warning */ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) " "for Scope operator, changed to type ANY\n", AcpiUtGetNodeName (Node), AcpiUtGetTypeName (Node->Type))); Node->Type = ACPI_TYPE_ANY; WalkState->ScopeInfo->Common.Value = ACPI_TYPE_ANY; break; case ACPI_TYPE_METHOD: /* * Allow scope change to root during execution of module-level * code. Root is typed METHOD during this time. */ if ((Node == AcpiGbl_RootNode) && (WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL)) { break; } /*lint -fallthrough */ default: /* All other types are an error */ ACPI_ERROR ((AE_INFO, "Invalid type (%s) for target of " "Scope operator [%4.4s] (Cannot override)", AcpiUtGetTypeName (Node->Type), AcpiUtGetNodeName (Node))); return_ACPI_STATUS (AE_AML_OPERAND_TYPE); } break; default: /* * For all other named opcodes, we will enter the name into * the namespace. * * Setup the search flags. * Since we are entering a name into the namespace, we do not want to * enable the search-to-root upsearch. * * There are only two conditions where it is acceptable that the name * already exists: * 1) the Scope() operator can reopen a scoping object that was * previously defined (Scope, Method, Device, etc.) * 2) Whenever we are parsing a deferred opcode (OpRegion, Buffer, * BufferField, or Package), the name of the object is already * in the namespace. */ if (WalkState->DeferredNode) { /* This name is already in the namespace, get the node */ Node = WalkState->DeferredNode; Status = AE_OK; break; } /* * If we are executing a method, do not create any namespace objects * during the load phase, only during execution. */ if (WalkState->MethodNode) { Node = NULL; Status = AE_OK; break; } Flags = ACPI_NS_NO_UPSEARCH; if ((WalkState->Opcode != AML_SCOPE_OP) && (!(WalkState->ParseFlags & ACPI_PARSE_DEFERRED_OP))) { if (WalkState->NamespaceOverride) { Flags |= ACPI_NS_OVERRIDE_IF_FOUND; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Override allowed\n", AcpiUtGetTypeName (ObjectType))); } else { Flags |= ACPI_NS_ERROR_IF_FOUND; ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n", AcpiUtGetTypeName (ObjectType))); } } else { ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n", AcpiUtGetTypeName (ObjectType))); } /* * Enter the named type into the internal namespace. We enter the name * as we go downward in the parse tree. Any necessary subobjects that * involve arguments to the opcode must be created as we go back up the * parse tree later. */ Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType, ACPI_IMODE_LOAD_PASS1, Flags, WalkState, &Node); if (ACPI_FAILURE (Status)) { if (Status == AE_ALREADY_EXISTS) { /* The name already exists in this scope */ if (Node->Flags & ANOBJ_IS_EXTERNAL) { /* * Allow one create on an object or segment that was * previously declared External */ Node->Flags &= ~ANOBJ_IS_EXTERNAL; Node->Type = (UINT8) ObjectType; /* Just retyped a node, probably will need to open a scope */ if (AcpiNsOpensScope (ObjectType)) { Status = AcpiDsScopeStackPush (Node, ObjectType, WalkState); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } } Status = AE_OK; } } if (ACPI_FAILURE (Status)) { ACPI_ERROR_NAMESPACE (Path, Status); return_ACPI_STATUS (Status); } } break; } /* Common exit */ if (!Op) { /* Create a new op */ Op = AcpiPsAllocOp (WalkState->Opcode); if (!Op) { return_ACPI_STATUS (AE_NO_MEMORY); } } /* Initialize the op */ #if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)) Op->Named.Path = ACPI_CAST_PTR (UINT8, Path); #endif if (Node) { /* * Put the Node in the "op" object that the parser uses, so we * can get it again quickly when this scope is closed */ Op->Common.Node = Node; Op->Named.Name = Node->Name.Integer; } AcpiPsAppendArg (AcpiPsGetParentScope (&WalkState->ParserState), Op); *OutOp = Op; return_ACPI_STATUS (Status); }
static ACPI_STATUS AcpiPsBuildNamedOp ( ACPI_WALK_STATE *WalkState, UINT8 *AmlOpStart, ACPI_PARSE_OBJECT *UnnamedOp, ACPI_PARSE_OBJECT **Op) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Arg = NULL; ACPI_FUNCTION_TRACE_PTR (PsBuildNamedOp, WalkState); UnnamedOp->Common.Value.Arg = NULL; UnnamedOp->Common.ArgListLength = 0; UnnamedOp->Common.AmlOpcode = WalkState->Opcode; /* * Get and append arguments until we find the node that contains * the name (the type ARGP_NAME). */ while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) != ARGP_NAME)) { Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } AcpiPsAppendArg (UnnamedOp, Arg); INCREMENT_ARG_LIST (WalkState->ArgTypes); } /* * Make sure that we found a NAME and didn't run out of arguments */ if (!GET_CURRENT_ARG_TYPE (WalkState->ArgTypes)) { return_ACPI_STATUS (AE_AML_NO_OPERAND); } /* We know that this arg is a name, move to next arg */ INCREMENT_ARG_LIST (WalkState->ArgTypes); /* * Find the object. This will either insert the object into * the namespace or simply look it up */ WalkState->Op = NULL; Status = WalkState->DescendingCallback (WalkState, Op); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "During name lookup/catalog")); return_ACPI_STATUS (Status); } if (!*Op) { return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); } Status = AcpiPsNextParseState (WalkState, *Op, Status); if (ACPI_FAILURE (Status)) { if (Status == AE_CTRL_PENDING) { return_ACPI_STATUS (AE_CTRL_PARSE_PENDING); } return_ACPI_STATUS (Status); } AcpiPsAppendArg (*Op, UnnamedOp->Common.Value.Arg); AcpiGbl_Depth++; if ((*Op)->Common.AmlOpcode == AML_REGION_OP || (*Op)->Common.AmlOpcode == AML_DATA_REGION_OP) { /* * Defer final parsing of an OperationRegion body, because we don't * have enough info in the first pass to parse it correctly (i.e., * there may be method calls within the TermArg elements of the body.) * * However, we must continue parsing because the opregion is not a * standalone package -- we don't know where the end is at this point. * * (Length is unknown until parse of the body complete) */ (*Op)->Named.Data = AmlOpStart; (*Op)->Named.Length = 0; } return_ACPI_STATUS (AE_OK); }
void AcpiPsGetNextNamepath ( ACPI_PARSE_STATE *ParserState, ACPI_PARSE_OBJECT *Arg, UINT32 *ArgCount, BOOLEAN MethodCall) { NATIVE_CHAR *Path; ACPI_PARSE_OBJECT *NameOp; ACPI_STATUS Status; ACPI_NAMESPACE_NODE *MethodNode = NULL; ACPI_NAMESPACE_NODE *Node; ACPI_GENERIC_STATE ScopeInfo; FUNCTION_TRACE ("PsGetNextNamepath"); Path = AcpiPsGetNextNamestring (ParserState); if (!Path || !MethodCall) { /* Null name case, create a null namepath object */ AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); Arg->Value.Name = Path; return_VOID; } if (MethodCall) { /* * Lookup the name in the internal namespace */ ScopeInfo.Scope.Node = NULL; Node = ParserState->StartNode; if (Node) { ScopeInfo.Scope.Node = Node; } /* * Lookup object. We don't want to add anything new to the namespace * here, however. So we use MODE_EXECUTE. Allow searching of the * parent tree, but don't open a new scope -- we just want to lookup the * object (MUST BE mode EXECUTE to perform upsearch) */ Status = AcpiNsLookup (&ScopeInfo, Path, ACPI_TYPE_ANY, IMODE_EXECUTE, NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE, NULL, &Node); if (ACPI_SUCCESS (Status)) { if (Node->Type == ACPI_TYPE_METHOD) { MethodNode = Node; ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "method - %p Path=%p\n", MethodNode, Path)); NameOp = AcpiPsAllocOp (AML_INT_NAMEPATH_OP); if (NameOp) { /* Change arg into a METHOD CALL and attach name to it */ AcpiPsInitOp (Arg, AML_INT_METHODCALL_OP); NameOp->Value.Name = Path; /* Point METHODCALL/NAME to the METHOD Node */ NameOp->Node = MethodNode; AcpiPsAppendArg (Arg, NameOp); if (!(ACPI_OPERAND_OBJECT *) MethodNode->Object) { return_VOID; } *ArgCount = ((ACPI_OPERAND_OBJECT *) MethodNode->Object)->Method.ParamCount; } return_VOID; } /* * Else this is normal named object reference. * Just init the NAMEPATH object with the pathname. * (See code below) */ } } /* * Either we didn't find the object in the namespace, or the object is * something other than a control method. Just initialize the Op with the * pathname. */ AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); Arg->Value.Name = Path; return_VOID; }
void AcpiPsGetNextNamepath ( ACPI_PARSE_STATE *ParserState, ACPI_PARSE_OBJECT *Arg, UINT32 *ArgCount, BOOLEAN MethodCall) { NATIVE_CHAR *Path; ACPI_PARSE_OBJECT *NameOp; ACPI_PARSE_OBJECT *Op; ACPI_PARSE_OBJECT *Count; FUNCTION_TRACE ("PsGetNextNamepath"); Path = AcpiPsGetNextNamestring (ParserState); if (!Path || !MethodCall) { /* Null name case, create a null namepath object */ AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); Arg->Value.Name = Path; return_VOID; } if (AcpiGbl_ParsedNamespaceRoot) { /* * Lookup the name in the parsed namespace */ Op = NULL; if (MethodCall) { Op = AcpiPsFind (AcpiPsGetParentScope (ParserState), Path, AML_METHOD_OP, 0); } if (Op) { if (Op->Opcode == AML_METHOD_OP) { /* * The name refers to a control method, so this namepath is a * method invocation. We need to 1) Get the number of arguments * associated with this method, and 2) Change the NAMEPATH * object into a METHODCALL object. */ Count = AcpiPsGetArg (Op, 0); if (Count && Count->Opcode == AML_BYTE_OP) { NameOp = AcpiPsAllocOp (AML_INT_NAMEPATH_OP); if (NameOp) { /* Change arg into a METHOD CALL and attach the name */ AcpiPsInitOp (Arg, AML_INT_METHODCALL_OP); NameOp->Value.Name = Path; /* Point METHODCALL/NAME to the METHOD Node */ NameOp->Node = (ACPI_NAMESPACE_NODE *) Op; AcpiPsAppendArg (Arg, NameOp); *ArgCount = (UINT32) Count->Value.Integer & METHOD_FLAGS_ARG_COUNT; } } return_VOID; } /* * Else this is normal named object reference. * Just init the NAMEPATH object with the pathname. * (See code below) */ } } /* * Either we didn't find the object in the namespace, or the object is * something other than a control method. Just initialize the Op with the * pathname */ AcpiPsInitOp (Arg, AML_INT_NAMEPATH_OP); Arg->Value.Name = Path; return_VOID; }
ACPI_STATUS AcpiPsParseLoop ( ACPI_WALK_STATE *WalkState) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Op = NULL; /* current op */ const ACPI_OPCODE_INFO *OpInfo; ACPI_PARSE_OBJECT *Arg = NULL; ACPI_PARSE2_OBJECT *DeferredOp; UINT32 ArgCount; /* push for fixed or var args */ UINT32 ArgTypes = 0; UINT32 AmlOffset; UINT16 Opcode; ACPI_PARSE_OBJECT PreOp; ACPI_PARSE_STATE *ParserState; UINT8 *AmlOpStart; FUNCTION_TRACE_PTR ("PsParseLoop", WalkState); ParserState = WalkState->ParserState; #ifndef PARSER_ONLY if (WalkState->WalkType & WALK_METHOD_RESTART) { /* We are restarting a preempted control method */ if (AcpiPsHasCompletedScope (ParserState)) { /* * We must check if a predicate to an IF or WHILE statement * was just completed */ if ((ParserState->Scope->ParseScope.Op) && ((ParserState->Scope->ParseScope.Op->Opcode == AML_IF_OP) || (ParserState->Scope->ParseScope.Op->Opcode == AML_WHILE_OP)) && (WalkState->ControlState) && (WalkState->ControlState->Common.State == CONTROL_PREDICATE_EXECUTING)) { /* * A predicate was just completed, get the value of the * predicate and branch based on that value */ Status = AcpiDsGetPredicateValue (WalkState, NULL, TRUE); if (ACPI_FAILURE (Status) && ((Status & AE_CODE_MASK) != AE_CODE_CONTROL)) { if (Status == AE_AML_NO_RETURN_VALUE) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invoked method did not return a value, %s\n", AcpiFormatException (Status))); } ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "GetPredicate Failed, %s\n", AcpiFormatException (Status))); return_ACPI_STATUS (Status); } Status = AcpiPsNextParseState (WalkState, Op, Status); } AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op)); } else if (WalkState->PrevOp) { /* We were in the middle of an op */ Op = WalkState->PrevOp; ArgTypes = WalkState->PrevArgTypes; } } #endif /* * Iterative parsing loop, while there is more aml to process: */ while ((ParserState->Aml < ParserState->AmlEnd) || (Op)) { if (!Op) { /* Get the next opcode from the AML stream */ AmlOpStart = ParserState->Aml; AmlOffset = ParserState->Aml - ParserState->AmlStart; Opcode = AcpiPsPeekOpcode (ParserState); /* * First cut to determine what we have found: * 1) A valid AML opcode * 2) A name string * 3) An unknown/invalid opcode */ OpInfo = AcpiPsGetOpcodeInfo (Opcode); switch (ACPI_GET_OP_TYPE (OpInfo)) { case ACPI_OP_TYPE_OPCODE: /* Found opcode info, this is a normal opcode */ ParserState->Aml += AcpiPsGetOpcodeSize (Opcode); ArgTypes = OpInfo->ParseArgs; break; case ACPI_OP_TYPE_ASCII: case ACPI_OP_TYPE_PREFIX: /* * Starts with a valid prefix or ASCII char, this is a name * string. Convert the bare name string to a namepath. */ Opcode = AML_INT_NAMEPATH_OP; ArgTypes = ARGP_NAMESTRING; break; case ACPI_OP_TYPE_UNKNOWN: /* The opcode is unrecognized. Just skip unknown opcodes */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found unknown opcode %lX at AML offset %X, ignoring\n", Opcode, AmlOffset)); DUMP_BUFFER (ParserState->Aml, 128); /* Assume one-byte bad opcode */ ParserState->Aml++; continue; } /* Create Op structure and append to parent's argument list */ if (OpInfo->Flags & AML_NAMED) { PreOp.Value.Arg = NULL; PreOp.Opcode = Opcode; while (GET_CURRENT_ARG_TYPE (ArgTypes) != ARGP_NAME) { Arg = AcpiPsGetNextArg (ParserState, GET_CURRENT_ARG_TYPE (ArgTypes), &ArgCount); AcpiPsAppendArg (&PreOp, Arg); INCREMENT_ARG_LIST (ArgTypes); } /* We know that this arg is a name, move to next arg */ INCREMENT_ARG_LIST (ArgTypes); if (WalkState->DescendingCallback != NULL) { /* * Find the object. This will either insert the object into * the namespace or simply look it up */ Status = WalkState->DescendingCallback (Opcode, NULL, WalkState, &Op); if (Op == NULL) { continue; } Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_OK; goto CloseThisOp; } if (ACPI_FAILURE (Status)) { goto CloseThisOp; } } AcpiPsAppendArg (Op, PreOp.Value.Arg); AcpiGbl_Depth++; if (Op->Opcode == AML_REGION_OP) { DeferredOp = (ACPI_PARSE2_OBJECT *) Op; /* * Defer final parsing of an OperationRegion body, * because we don't have enough info in the first pass * to parse it correctly (i.e., there may be method * calls within the TermArg elements of the body. * * However, we must continue parsing because * the opregion is not a standalone package -- * we don't know where the end is at this point. * * (Length is unknown until parse of the body complete) */ DeferredOp->Data = AmlOpStart; DeferredOp->Length = 0; } } else { /* Not a named opcode, just allocate Op and append to parent */ OpInfo = AcpiPsGetOpcodeInfo (Opcode); Op = AcpiPsAllocOp (Opcode); if (!Op) { return_ACPI_STATUS (AE_NO_MEMORY); } if (OpInfo->Flags & AML_CREATE) { /* * Backup to beginning of CreateXXXfield declaration * BodyLength is unknown until we parse the body */ DeferredOp = (ACPI_PARSE2_OBJECT *) Op; DeferredOp->Data = AmlOpStart; DeferredOp->Length = 0; } AcpiPsAppendArg (AcpiPsGetParentScope (ParserState), Op); if ((WalkState->DescendingCallback != NULL)) { /* * Find the object. This will either insert the object into * the namespace or simply look it up */ Status = WalkState->DescendingCallback (Opcode, Op, WalkState, &Op); Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_OK; goto CloseThisOp; } if (ACPI_FAILURE (Status)) { goto CloseThisOp; } } } Op->AmlOffset = AmlOffset; if (OpInfo) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Op=%p Opcode=%4.4lX Aml %p Oft=%5.5lX\n", Op, Op->Opcode, ParserState->Aml, Op->AmlOffset)); } } /* Start ArgCount at zero because we don't know if there are any args yet */ ArgCount = 0; if (ArgTypes) /* Are there any arguments that must be processed? */ { /* get arguments */ switch (Op->Opcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ case AML_DWORD_OP: /* AML_DWORDATA_ARG */ case AML_QWORD_OP: /* AML_QWORDATA_ARG */ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ /* fill in constant or string argument directly */ AcpiPsGetNextSimpleArg (ParserState, GET_CURRENT_ARG_TYPE (ArgTypes), Op); break; case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ AcpiPsGetNextNamepath (ParserState, Op, &ArgCount, 1); ArgTypes = 0; break; default: /* Op is not a constant or string, append each argument */ while (GET_CURRENT_ARG_TYPE (ArgTypes) && !ArgCount) { AmlOffset = ParserState->Aml - ParserState->AmlStart; Arg = AcpiPsGetNextArg (ParserState, GET_CURRENT_ARG_TYPE (ArgTypes), &ArgCount); if (Arg) { Arg->AmlOffset = AmlOffset; AcpiPsAppendArg (Op, Arg); } INCREMENT_ARG_LIST (ArgTypes); } /* For a method, save the length and address of the body */ if (Op->Opcode == AML_METHOD_OP) { DeferredOp = (ACPI_PARSE2_OBJECT *) Op; /* * Skip parsing of control method or opregion body, * because we don't have enough info in the first pass * to parse them correctly. */ DeferredOp->Data = ParserState->Aml; DeferredOp->Length = (UINT32) (ParserState->PkgEnd - ParserState->Aml); /* * Skip body of method. For OpRegions, we must continue * parsing because the opregion is not a standalone * package (We don't know where the end is). */ ParserState->Aml = ParserState->PkgEnd; ArgCount = 0; } break; } } /* * Zero ArgCount means that all arguments for this op have been processed */ if (!ArgCount) { /* completed Op, prepare for next */ OpInfo = AcpiPsGetOpcodeInfo (Op->Opcode); if (OpInfo->Flags & AML_NAMED) { if (AcpiGbl_Depth) { AcpiGbl_Depth--; } if (Op->Opcode == AML_REGION_OP) { DeferredOp = (ACPI_PARSE2_OBJECT *) Op; /* * Skip parsing of control method or opregion body, * because we don't have enough info in the first pass * to parse them correctly. * * Completed parsing an OpRegion declaration, we now * know the length. */ DeferredOp->Length = (UINT32) (ParserState->Aml - DeferredOp->Data); } } if (OpInfo->Flags & AML_CREATE) { /* * Backup to beginning of CreateXXXfield declaration (1 for * Opcode) * * BodyLength is unknown until we parse the body */ DeferredOp = (ACPI_PARSE2_OBJECT *) Op; DeferredOp->Length = (UINT32) (ParserState->Aml - DeferredOp->Data); } /* This op complete, notify the dispatcher */ if (WalkState->AscendingCallback != NULL) { Status = WalkState->AscendingCallback (WalkState, Op); Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_OK; goto CloseThisOp; } } CloseThisOp: /* * Finished one argument of the containing scope */ ParserState->Scope->ParseScope.ArgCount--; /* Close this Op (may result in parse subtree deletion) */ if (AcpiPsCompleteThisOp (WalkState, Op)) { Op = NULL; } switch (Status) { case AE_OK: break; case AE_CTRL_TRANSFER: /* * We are about to transfer to a called method. */ WalkState->PrevOp = Op; WalkState->PrevArgTypes = ArgTypes; return_ACPI_STATUS (Status); break; case AE_CTRL_END: AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); Status = WalkState->AscendingCallback (WalkState, Op); Status = AcpiPsNextParseState (WalkState, Op, Status); AcpiPsCompleteThisOp (WalkState, Op); Op = NULL; Status = AE_OK; break; case AE_CTRL_TERMINATE: Status = AE_OK; /* Clean up */ do { if (Op) { AcpiPsCompleteThisOp (WalkState, Op); } AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); } while (Op); return_ACPI_STATUS (Status); break; default: /* All other non-AE_OK status */ if (Op == NULL) { AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); } WalkState->PrevOp = Op; WalkState->PrevArgTypes = ArgTypes; /* * TEMP: */ return_ACPI_STATUS (Status); break; } /* This scope complete? */ if (AcpiPsHasCompletedScope (ParserState)) { AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op)); } else { Op = NULL; } } /* ArgCount is non-zero */ else { /* complex argument, push Op and prepare for argument */ AcpiPsPushScope (ParserState, Op, ArgTypes, ArgCount); Op = NULL; } } /* while ParserState->Aml */ /* * Complete the last Op (if not completed), and clear the scope stack. * It is easily possible to end an AML "package" with an unbounded number * of open scopes (such as when several AML blocks are closed with * sequential closing braces). We want to terminate each one cleanly. */ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Package complete at Op %p\n", Op)); do { if (Op) { if (WalkState->AscendingCallback != NULL) { Status = WalkState->AscendingCallback (WalkState, Op); Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_OK; goto CloseThisOp; } if (Status == AE_CTRL_TERMINATE) { Status = AE_OK; /* Clean up */ do { if (Op) { AcpiPsCompleteThisOp (WalkState, Op); } AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); } while (Op); return_ACPI_STATUS (Status); } else if (ACPI_FAILURE (Status)) { AcpiPsCompleteThisOp (WalkState, Op); return_ACPI_STATUS (Status); } } AcpiPsCompleteThisOp (WalkState, Op); } AcpiPsPopScope (ParserState, &Op, &ArgTypes, &ArgCount); } while (Op); return_ACPI_STATUS (Status); }
static ACPI_STATUS AcpiPsGetArguments ( ACPI_WALK_STATE *WalkState, UINT8 *AmlOpStart, ACPI_PARSE_OBJECT *Op) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Arg = NULL; const ACPI_OPCODE_INFO *OpInfo; ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState); ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Get arguments for opcode [%s]\n", Op->Common.AmlOpName)); switch (Op->Common.AmlOpcode) { case AML_BYTE_OP: /* AML_BYTEDATA_ARG */ case AML_WORD_OP: /* AML_WORDDATA_ARG */ case AML_DWORD_OP: /* AML_DWORDATA_ARG */ case AML_QWORD_OP: /* AML_QWORDATA_ARG */ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */ /* Fill in constant or string argument directly */ AcpiPsGetNextSimpleArg (&(WalkState->ParserState), GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op); break; case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */ Status = AcpiPsGetNextNamepath (WalkState, &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } WalkState->ArgTypes = 0; break; default: /* * Op is not a constant or string, append each argument to the Op */ while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) && !WalkState->ArgCount) { WalkState->Aml = WalkState->ParserState.Aml; switch (Op->Common.AmlOpcode) { case AML_METHOD_OP: case AML_BUFFER_OP: case AML_PACKAGE_OP: case AML_VARIABLE_PACKAGE_OP: case AML_WHILE_OP: break; default: ASL_CV_CAPTURE_COMMENTS (WalkState); break; } Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState), GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } if (Arg) { AcpiPsAppendArg (Op, Arg); } INCREMENT_ARG_LIST (WalkState->ArgTypes); } ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Final argument count: %8.8X pass %u\n", WalkState->ArgCount, WalkState->PassNumber)); /* * This case handles the legacy option that groups all module-level * code blocks together and defers execution until all of the tables * are loaded. Execute all of these blocks at this time. * Execute any module-level code that was detected during the table * load phase. * * Note: this option is deprecated and will be eliminated in the * future. Use of this option can cause problems with AML code that * depends upon in-order immediate execution of module-level code. */ if (AcpiGbl_GroupModuleLevelCode && (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) && ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0)) { /* * We want to skip If/Else/While constructs during Pass1 because we * want to actually conditionally execute the code during Pass2. * * Except for disassembly, where we always want to walk the * If/Else/While packages */ switch (Op->Common.AmlOpcode) { case AML_IF_OP: case AML_ELSE_OP: case AML_WHILE_OP: /* * Currently supported module-level opcodes are: * IF/ELSE/WHILE. These appear to be the most common, * and easiest to support since they open an AML * package. */ if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) { AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart, (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart), WalkState->OwnerId); } ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Pass1: Skipping an If/Else/While body\n")); /* Skip body of if/else/while in pass 1 */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; break; default: /* * Check for an unsupported executable opcode at module * level. We must be in PASS1, the parent must be a SCOPE, * The opcode class must be EXECUTE, and the opcode must * not be an argument to another opcode. */ if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) && (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP)) { OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); if ((OpInfo->Class == AML_CLASS_EXECUTE) && (!Arg)) { ACPI_WARNING ((AE_INFO, "Unsupported module-level executable opcode " "0x%.2X at table offset 0x%.4X", Op->Common.AmlOpcode, (UINT32) (ACPI_PTR_DIFF (AmlOpStart, WalkState->ParserState.AmlStart) + sizeof (ACPI_TABLE_HEADER)))); } } break; } } /* Special processing for certain opcodes */ switch (Op->Common.AmlOpcode) { case AML_METHOD_OP: /* * Skip parsing of control method because we don't have enough * info in the first pass to parse it correctly. * * Save the length and address of the body */ Op->Named.Data = WalkState->ParserState.Aml; Op->Named.Length = (UINT32) (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml); /* Skip body of method */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; break; case AML_BUFFER_OP: case AML_PACKAGE_OP: case AML_VARIABLE_PACKAGE_OP: if ((Op->Common.Parent) && (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) && (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2)) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Setup Package/Buffer: Pass %u, AML Ptr: %p\n", WalkState->PassNumber, AmlOpStart)); /* * Skip parsing of Buffers and Packages because we don't have * enough info in the first pass to parse them correctly. */ Op->Named.Data = AmlOpStart; Op->Named.Length = (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart); /* Skip body */ WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd; WalkState->ArgCount = 0; } break; case AML_WHILE_OP: if (WalkState->ControlState) { WalkState->ControlState->Control.PackageEnd = WalkState->ParserState.PkgEnd; } break; default: /* No action for all other opcodes */ break; } break; } return_ACPI_STATUS (AE_OK); }
ACPI_STATUS AcpiPsCreateOp ( ACPI_WALK_STATE *WalkState, UINT8 *AmlOpStart, ACPI_PARSE_OBJECT **NewOp) { ACPI_STATUS Status = AE_OK; ACPI_PARSE_OBJECT *Op; ACPI_PARSE_OBJECT *NamedOp = NULL; ACPI_PARSE_OBJECT *ParentScope; UINT8 ArgumentCount; const ACPI_OPCODE_INFO *OpInfo; ACPI_FUNCTION_TRACE_PTR (PsCreateOp, WalkState); Status = AcpiPsGetAmlOpcode (WalkState); if (Status == AE_CTRL_PARSE_CONTINUE) { return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); } if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Create Op structure and append to parent's argument list */ WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode); Op = AcpiPsAllocOp (WalkState->Opcode, AmlOpStart); if (!Op) { return_ACPI_STATUS (AE_NO_MEMORY); } if (WalkState->OpInfo->Flags & AML_NAMED) { Status = AcpiPsBuildNamedOp (WalkState, AmlOpStart, Op, &NamedOp); AcpiPsFreeOp (Op); #ifdef ACPI_ASL_COMPILER if (AcpiGbl_DisasmFlag && WalkState->Opcode == AML_EXTERNAL_OP && Status == AE_NOT_FOUND) { /* * If parsing of AML_EXTERNAL_OP's name path fails, then skip * past this opcode and keep parsing. This is a much better * alternative than to abort the entire disassembler. At this * point, the ParserState is at the end of the namepath of the * external declaration opcode. Setting WalkState->Aml to * WalkState->ParserState.Aml + 2 moves increments the * WalkState->Aml past the object type and the paramcount of the * external opcode. */ WalkState->Aml = WalkState->ParserState.Aml + 2; WalkState->ParserState.Aml = WalkState->Aml; return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); } #endif if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } *NewOp = NamedOp; return_ACPI_STATUS (AE_OK); } /* Not a named opcode, just allocate Op and append to parent */ if (WalkState->OpInfo->Flags & AML_CREATE) { /* * Backup to beginning of CreateXXXfield declaration * BodyLength is unknown until we parse the body */ Op->Named.Data = AmlOpStart; Op->Named.Length = 0; } if (WalkState->Opcode == AML_BANK_FIELD_OP) { /* * Backup to beginning of BankField declaration * BodyLength is unknown until we parse the body */ Op->Named.Data = AmlOpStart; Op->Named.Length = 0; } ParentScope = AcpiPsGetParentScope (&(WalkState->ParserState)); AcpiPsAppendArg (ParentScope, Op); if (ParentScope) { OpInfo = AcpiPsGetOpcodeInfo (ParentScope->Common.AmlOpcode); if (OpInfo->Flags & AML_HAS_TARGET) { ArgumentCount = AcpiPsGetArgumentCount (OpInfo->Type); if (ParentScope->Common.ArgListLength > ArgumentCount) { Op->Common.Flags |= ACPI_PARSEOP_TARGET; } } /* * Special case for both Increment() and Decrement(), where * the lone argument is both a source and a target. */ else if ((ParentScope->Common.AmlOpcode == AML_INCREMENT_OP) || (ParentScope->Common.AmlOpcode == AML_DECREMENT_OP)) { Op->Common.Flags |= ACPI_PARSEOP_TARGET; } } if (WalkState->DescendingCallback != NULL) { /* * Find the object. This will either insert the object into * the namespace or simply look it up */ WalkState->Op = *NewOp = Op; Status = WalkState->DescendingCallback (WalkState, &Op); Status = AcpiPsNextParseState (WalkState, Op, Status); if (Status == AE_CTRL_PENDING) { Status = AE_CTRL_PARSE_PENDING; } } return_ACPI_STATUS (Status); }