0,0 → 1,1340 |
/****************************************************************************** |
* |
* Module Name: psloop - Main AML parse loop |
* |
*****************************************************************************/ |
|
/****************************************************************************** |
* |
* 1. Copyright Notice |
* |
* Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. |
* All rights reserved. |
* |
* 2. License |
* |
* 2.1. This is your license from Intel Corp. under its intellectual property |
* rights. You may have additional license terms from the party that provided |
* you this software, covering your right to use that party's intellectual |
* property rights. |
* |
* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a |
* copy of the source code appearing in this file ("Covered Code") an |
* irrevocable, perpetual, worldwide license under Intel's copyrights in the |
* base code distributed originally by Intel ("Original Intel Code") to copy, |
* make derivatives, distribute, use and display any portion of the Covered |
* Code in any form, with the right to sublicense such rights; and |
* |
* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent |
* license (with the right to sublicense), under only those claims of Intel |
* patents that are infringed by the Original Intel Code, to make, use, sell, |
* offer to sell, and import the Covered Code and derivative works thereof |
* solely to the minimum extent necessary to exercise the above copyright |
* license, and in no event shall the patent license extend to any additions |
* to or modifications of the Original Intel Code. No other license or right |
* is granted directly or by implication, estoppel or otherwise; |
* |
* The above copyright and patent license is granted only if the following |
* conditions are met: |
* |
* 3. Conditions |
* |
* 3.1. Redistribution of Source with Rights to Further Distribute Source. |
* Redistribution of source code of any substantial portion of the Covered |
* Code or modification with rights to further distribute source must include |
* the above Copyright Notice, the above License, this list of Conditions, |
* and the following Disclaimer and Export Compliance provision. In addition, |
* Licensee must cause all Covered Code to which Licensee contributes to |
* contain a file documenting the changes Licensee made to create that Covered |
* Code and the date of any change. Licensee must include in that file the |
* documentation of any changes made by any predecessor Licensee. Licensee |
* must include a prominent statement that the modification is derived, |
* directly or indirectly, from Original Intel Code. |
* |
* 3.2. Redistribution of Source with no Rights to Further Distribute Source. |
* Redistribution of source code of any substantial portion of the Covered |
* Code or modification without rights to further distribute source must |
* include the following Disclaimer and Export Compliance provision in the |
* documentation and/or other materials provided with distribution. In |
* addition, Licensee may not authorize further sublicense of source of any |
* portion of the Covered Code, and must include terms to the effect that the |
* license from Licensee to its licensee is limited to the intellectual |
* property embodied in the software Licensee provides to its licensee, and |
* not to intellectual property embodied in modifications its licensee may |
* make. |
* |
* 3.3. Redistribution of Executable. Redistribution in executable form of any |
* substantial portion of the Covered Code or modification must reproduce the |
* above Copyright Notice, and the following Disclaimer and Export Compliance |
* provision in the documentation and/or other materials provided with the |
* distribution. |
* |
* 3.4. Intel retains all right, title, and interest in and to the Original |
* Intel Code. |
* |
* 3.5. Neither the name Intel nor any other trademark owned or controlled by |
* Intel shall be used in advertising or otherwise to promote the sale, use or |
* other dealings in products derived from or relating to the Covered Code |
* without prior written authorization from Intel. |
* |
* 4. Disclaimer and Export Compliance |
* |
* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED |
* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE |
* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, |
* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY |
* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY |
* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A |
* PARTICULAR PURPOSE. |
* |
* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES |
* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR |
* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, |
* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY |
* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL |
* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS |
* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY |
* LIMITED REMEDY. |
* |
* 4.3. Licensee shall not export, either directly or indirectly, any of this |
* software or system incorporating such software without first obtaining any |
* required license or other approval from the U. S. Department of Commerce or |
* any other agency or department of the United States Government. In the |
* event Licensee exports any such software from the United States or |
* re-exports any such software from a foreign destination, Licensee shall |
* ensure that the distribution and export/re-export of the software is in |
* compliance with all laws, regulations, orders, or other restrictions of the |
* U.S. Export Administration Regulations. Licensee agrees that neither it nor |
* any of its subsidiaries will export/re-export any technical data, process, |
* software, or service, directly or indirectly, to any country for which the |
* United States government or any agency thereof requires an export license, |
* other governmental approval, or letter of assurance, without first obtaining |
* such license, approval or letter. |
* |
*****************************************************************************/ |
|
|
/* |
* Parse the AML and build an operation tree as most interpreters, (such as |
* Perl) do. Parsing is done by hand rather than with a YACC generated parser |
* to tightly constrain stack and dynamic memory usage. Parsing is kept |
* flexible and the code fairly compact by parsing based on a list of AML |
* opcode templates in AmlOpInfo[]. |
*/ |
|
#include "acpi.h" |
#include "accommon.h" |
#include "acparser.h" |
#include "acdispat.h" |
#include "amlcode.h" |
|
#define _COMPONENT ACPI_PARSER |
ACPI_MODULE_NAME ("psloop") |
|
static UINT32 AcpiGbl_Depth = 0; |
|
|
/* Local prototypes */ |
|
static ACPI_STATUS |
AcpiPsGetAmlOpcode ( |
ACPI_WALK_STATE *WalkState); |
|
static ACPI_STATUS |
AcpiPsBuildNamedOp ( |
ACPI_WALK_STATE *WalkState, |
UINT8 *AmlOpStart, |
ACPI_PARSE_OBJECT *UnnamedOp, |
ACPI_PARSE_OBJECT **Op); |
|
static ACPI_STATUS |
AcpiPsCreateOp ( |
ACPI_WALK_STATE *WalkState, |
UINT8 *AmlOpStart, |
ACPI_PARSE_OBJECT **NewOp); |
|
static ACPI_STATUS |
AcpiPsGetArguments ( |
ACPI_WALK_STATE *WalkState, |
UINT8 *AmlOpStart, |
ACPI_PARSE_OBJECT *Op); |
|
static ACPI_STATUS |
AcpiPsCompleteOp ( |
ACPI_WALK_STATE *WalkState, |
ACPI_PARSE_OBJECT **Op, |
ACPI_STATUS Status); |
|
static ACPI_STATUS |
AcpiPsCompleteFinalOp ( |
ACPI_WALK_STATE *WalkState, |
ACPI_PARSE_OBJECT *Op, |
ACPI_STATUS Status); |
|
static void |
AcpiPsLinkModuleCode ( |
ACPI_PARSE_OBJECT *ParentOp, |
UINT8 *AmlStart, |
UINT32 AmlLength, |
ACPI_OWNER_ID OwnerId); |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsGetAmlOpcode |
* |
* PARAMETERS: WalkState - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Extract the next AML opcode from the input stream. |
* |
******************************************************************************/ |
|
static ACPI_STATUS |
AcpiPsGetAmlOpcode ( |
ACPI_WALK_STATE *WalkState) |
{ |
|
ACPI_FUNCTION_TRACE_PTR (PsGetAmlOpcode, WalkState); |
|
|
WalkState->AmlOffset = (UINT32) ACPI_PTR_DIFF (WalkState->ParserState.Aml, |
WalkState->ParserState.AmlStart); |
WalkState->Opcode = AcpiPsPeekOpcode (&(WalkState->ParserState)); |
|
/* |
* First cut to determine what we have found: |
* 1) A valid AML opcode |
* 2) A name string |
* 3) An unknown/invalid opcode |
*/ |
WalkState->OpInfo = AcpiPsGetOpcodeInfo (WalkState->Opcode); |
|
switch (WalkState->OpInfo->Class) |
{ |
case AML_CLASS_ASCII: |
case AML_CLASS_PREFIX: |
/* |
* Starts with a valid prefix or ASCII char, this is a name |
* string. Convert the bare name string to a namepath. |
*/ |
WalkState->Opcode = AML_INT_NAMEPATH_OP; |
WalkState->ArgTypes = ARGP_NAMESTRING; |
break; |
|
case AML_CLASS_UNKNOWN: |
|
/* The opcode is unrecognized. Just skip unknown opcodes */ |
|
ACPI_ERROR ((AE_INFO, |
"Found unknown opcode 0x%X at AML address %p offset 0x%X, ignoring", |
WalkState->Opcode, WalkState->ParserState.Aml, WalkState->AmlOffset)); |
|
ACPI_DUMP_BUFFER (WalkState->ParserState.Aml, 128); |
|
/* Assume one-byte bad opcode */ |
|
WalkState->ParserState.Aml++; |
return_ACPI_STATUS (AE_CTRL_PARSE_CONTINUE); |
|
default: |
|
/* Found opcode info, this is a normal opcode */ |
|
WalkState->ParserState.Aml += AcpiPsGetOpcodeSize (WalkState->Opcode); |
WalkState->ArgTypes = WalkState->OpInfo->ParseArgs; |
break; |
} |
|
return_ACPI_STATUS (AE_OK); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsBuildNamedOp |
* |
* PARAMETERS: WalkState - Current state |
* AmlOpStart - Begin of named Op in AML |
* UnnamedOp - Early Op (not a named Op) |
* Op - Returned Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse a named Op |
* |
******************************************************************************/ |
|
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); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsCreateOp |
* |
* PARAMETERS: WalkState - Current state |
* AmlOpStart - Op start in AML |
* NewOp - Returned Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get Op from AML |
* |
******************************************************************************/ |
|
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); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsGetArguments |
* |
* PARAMETERS: WalkState - Current state |
* AmlOpStart - Op start in AML |
* Op - Current Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Get arguments for passed Op. |
* |
******************************************************************************/ |
|
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, |
"Detected an unsupported executable opcode " |
"at module-level: [0x%.4X] 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); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsLinkModuleCode |
* |
* PARAMETERS: ParentOp - Parent parser op |
* AmlStart - Pointer to the AML |
* AmlLength - Length of executable AML |
* OwnerId - OwnerId of module level code |
* |
* RETURN: None. |
* |
* DESCRIPTION: Wrap the module-level code with a method object and link the |
* object to the global list. Note, the mutex field of the method |
* object is used to link multiple module-level code objects. |
* |
******************************************************************************/ |
|
static void |
AcpiPsLinkModuleCode ( |
ACPI_PARSE_OBJECT *ParentOp, |
UINT8 *AmlStart, |
UINT32 AmlLength, |
ACPI_OWNER_ID OwnerId) |
{ |
ACPI_OPERAND_OBJECT *Prev; |
ACPI_OPERAND_OBJECT *Next; |
ACPI_OPERAND_OBJECT *MethodObj; |
ACPI_NAMESPACE_NODE *ParentNode; |
|
|
/* Get the tail of the list */ |
|
Prev = Next = AcpiGbl_ModuleCodeList; |
while (Next) |
{ |
Prev = Next; |
Next = Next->Method.Mutex; |
} |
|
/* |
* Insert the module level code into the list. Merge it if it is |
* adjacent to the previous element. |
*/ |
if (!Prev || |
((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart)) |
{ |
/* Create, initialize, and link a new temporary method object */ |
|
MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); |
if (!MethodObj) |
{ |
return; |
} |
|
if (ParentOp->Common.Node) |
{ |
ParentNode = ParentOp->Common.Node; |
} |
else |
{ |
ParentNode = AcpiGbl_RootNode; |
} |
|
MethodObj->Method.AmlStart = AmlStart; |
MethodObj->Method.AmlLength = AmlLength; |
MethodObj->Method.OwnerId = OwnerId; |
MethodObj->Method.Flags |= AOPOBJ_MODULE_LEVEL; |
|
/* |
* Save the parent node in NextObject. This is cheating, but we |
* don't want to expand the method object. |
*/ |
MethodObj->Method.NextObject = |
ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode); |
|
if (!Prev) |
{ |
AcpiGbl_ModuleCodeList = MethodObj; |
} |
else |
{ |
Prev->Method.Mutex = MethodObj; |
} |
} |
else |
{ |
Prev->Method.AmlLength += AmlLength; |
} |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsCompleteOp |
* |
* PARAMETERS: WalkState - Current state |
* Op - Returned Op |
* Status - Parse status before complete Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Complete Op |
* |
******************************************************************************/ |
|
static ACPI_STATUS |
AcpiPsCompleteOp ( |
ACPI_WALK_STATE *WalkState, |
ACPI_PARSE_OBJECT **Op, |
ACPI_STATUS Status) |
{ |
ACPI_STATUS Status2; |
|
|
ACPI_FUNCTION_TRACE_PTR (PsCompleteOp, WalkState); |
|
|
/* |
* Finished one argument of the containing scope |
*/ |
WalkState->ParserState.Scope->ParseScope.ArgCount--; |
|
/* Close this Op (will result in parse subtree deletion) */ |
|
Status2 = AcpiPsCompleteThisOp (WalkState, *Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
|
*Op = NULL; |
|
switch (Status) |
{ |
case AE_OK: |
break; |
|
|
case AE_CTRL_TRANSFER: |
|
/* We are about to transfer to a called method */ |
|
WalkState->PrevOp = NULL; |
WalkState->PrevArgTypes = WalkState->ArgTypes; |
return_ACPI_STATUS (Status); |
|
|
case AE_CTRL_END: |
|
AcpiPsPopScope (&(WalkState->ParserState), Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
|
if (*Op) |
{ |
WalkState->Op = *Op; |
WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode); |
WalkState->Opcode = (*Op)->Common.AmlOpcode; |
|
Status = WalkState->AscendingCallback (WalkState); |
Status = AcpiPsNextParseState (WalkState, *Op, Status); |
|
Status2 = AcpiPsCompleteThisOp (WalkState, *Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
} |
|
Status = AE_OK; |
break; |
|
|
case AE_CTRL_BREAK: |
case AE_CTRL_CONTINUE: |
|
/* Pop off scopes until we find the While */ |
|
while (!(*Op) || ((*Op)->Common.AmlOpcode != AML_WHILE_OP)) |
{ |
AcpiPsPopScope (&(WalkState->ParserState), Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
} |
|
/* Close this iteration of the While loop */ |
|
WalkState->Op = *Op; |
WalkState->OpInfo = AcpiPsGetOpcodeInfo ((*Op)->Common.AmlOpcode); |
WalkState->Opcode = (*Op)->Common.AmlOpcode; |
|
Status = WalkState->AscendingCallback (WalkState); |
Status = AcpiPsNextParseState (WalkState, *Op, Status); |
|
Status2 = AcpiPsCompleteThisOp (WalkState, *Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
|
Status = AE_OK; |
break; |
|
|
case AE_CTRL_TERMINATE: |
|
/* Clean up */ |
do |
{ |
if (*Op) |
{ |
Status2 = AcpiPsCompleteThisOp (WalkState, *Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
|
AcpiUtDeleteGenericState ( |
AcpiUtPopGenericState (&WalkState->ControlState)); |
} |
|
AcpiPsPopScope (&(WalkState->ParserState), Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
|
} while (*Op); |
|
return_ACPI_STATUS (AE_OK); |
|
|
default: /* All other non-AE_OK status */ |
|
do |
{ |
if (*Op) |
{ |
Status2 = AcpiPsCompleteThisOp (WalkState, *Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
} |
|
AcpiPsPopScope (&(WalkState->ParserState), Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
|
} while (*Op); |
|
|
#if 0 |
/* |
* TBD: Cleanup parse ops on error |
*/ |
if (*Op == NULL) |
{ |
AcpiPsPopScope (ParserState, Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
} |
#endif |
WalkState->PrevOp = NULL; |
WalkState->PrevArgTypes = WalkState->ArgTypes; |
return_ACPI_STATUS (Status); |
} |
|
/* This scope complete? */ |
|
if (AcpiPsHasCompletedScope (&(WalkState->ParserState))) |
{ |
AcpiPsPopScope (&(WalkState->ParserState), Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *Op)); |
} |
else |
{ |
*Op = NULL; |
} |
|
return_ACPI_STATUS (AE_OK); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsCompleteFinalOp |
* |
* PARAMETERS: WalkState - Current state |
* Op - Current Op |
* Status - Current parse status before complete last |
* Op |
* |
* RETURN: Status |
* |
* DESCRIPTION: Complete last Op. |
* |
******************************************************************************/ |
|
static ACPI_STATUS |
AcpiPsCompleteFinalOp ( |
ACPI_WALK_STATE *WalkState, |
ACPI_PARSE_OBJECT *Op, |
ACPI_STATUS Status) |
{ |
ACPI_STATUS Status2; |
|
|
ACPI_FUNCTION_TRACE_PTR (PsCompleteFinalOp, WalkState); |
|
|
/* |
* 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 ASL blocks are closed with |
* sequential closing braces). We want to terminate each one cleanly. |
*/ |
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", Op)); |
do |
{ |
if (Op) |
{ |
if (WalkState->AscendingCallback != NULL) |
{ |
WalkState->Op = Op; |
WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); |
WalkState->Opcode = Op->Common.AmlOpcode; |
|
Status = WalkState->AscendingCallback (WalkState); |
Status = AcpiPsNextParseState (WalkState, Op, Status); |
if (Status == AE_CTRL_PENDING) |
{ |
Status = AcpiPsCompleteOp (WalkState, &Op, AE_OK); |
if (ACPI_FAILURE (Status)) |
{ |
return_ACPI_STATUS (Status); |
} |
} |
|
if (Status == AE_CTRL_TERMINATE) |
{ |
Status = AE_OK; |
|
/* Clean up */ |
do |
{ |
if (Op) |
{ |
Status2 = AcpiPsCompleteThisOp (WalkState, Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
} |
|
AcpiPsPopScope (&(WalkState->ParserState), &Op, |
&WalkState->ArgTypes, &WalkState->ArgCount); |
|
} while (Op); |
|
return_ACPI_STATUS (Status); |
} |
|
else if (ACPI_FAILURE (Status)) |
{ |
/* First error is most important */ |
|
(void) AcpiPsCompleteThisOp (WalkState, Op); |
return_ACPI_STATUS (Status); |
} |
} |
|
Status2 = AcpiPsCompleteThisOp (WalkState, Op); |
if (ACPI_FAILURE (Status2)) |
{ |
return_ACPI_STATUS (Status2); |
} |
} |
|
AcpiPsPopScope (&(WalkState->ParserState), &Op, &WalkState->ArgTypes, |
&WalkState->ArgCount); |
|
} while (Op); |
|
return_ACPI_STATUS (Status); |
} |
|
|
/******************************************************************************* |
* |
* FUNCTION: AcpiPsParseLoop |
* |
* PARAMETERS: WalkState - Current state |
* |
* RETURN: Status |
* |
* DESCRIPTION: Parse AML (pointed to by the current parser state) and return |
* a tree of ops. |
* |
******************************************************************************/ |
|
ACPI_STATUS |
AcpiPsParseLoop ( |
ACPI_WALK_STATE *WalkState) |
{ |
ACPI_STATUS Status = AE_OK; |
ACPI_PARSE_OBJECT *Op = NULL; /* current op */ |
ACPI_PARSE_STATE *ParserState; |
UINT8 *AmlOpStart = NULL; |
|
|
ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState); |
|
|
if (WalkState->DescendingCallback == NULL) |
{ |
return_ACPI_STATUS (AE_BAD_PARAMETER); |
} |
|
ParserState = &WalkState->ParserState; |
WalkState->ArgTypes = 0; |
|
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY)) |
|
if (WalkState->WalkType & ACPI_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->Common.AmlOpcode == AML_IF_OP) || |
(ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) && |
(WalkState->ControlState) && |
(WalkState->ControlState->Common.State == |
ACPI_CONTROL_PREDICATE_EXECUTING)) |
{ |
/* |
* A predicate was just completed, get the value of the |
* predicate and branch based on that value |
*/ |
WalkState->Op = NULL; |
Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE)); |
if (ACPI_FAILURE (Status) && |
((Status & AE_CODE_MASK) != AE_CODE_CONTROL)) |
{ |
if (Status == AE_AML_NO_RETURN_VALUE) |
{ |
ACPI_EXCEPTION ((AE_INFO, Status, |
"Invoked method did not return a value")); |
} |
|
ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed")); |
return_ACPI_STATUS (Status); |
} |
|
Status = AcpiPsNextParseState (WalkState, Op, Status); |
} |
|
AcpiPsPopScope (ParserState, &Op, |
&WalkState->ArgTypes, &WalkState->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; |
WalkState->ArgTypes = WalkState->PrevArgTypes; |
} |
} |
#endif |
|
/* Iterative parsing loop, while there is more AML to process: */ |
|
while ((ParserState->Aml < ParserState->AmlEnd) || (Op)) |
{ |
AmlOpStart = ParserState->Aml; |
if (!Op) |
{ |
Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op); |
if (ACPI_FAILURE (Status)) |
{ |
if (Status == AE_CTRL_PARSE_CONTINUE) |
{ |
continue; |
} |
|
if (Status == AE_CTRL_PARSE_PENDING) |
{ |
Status = AE_OK; |
} |
|
Status = AcpiPsCompleteOp (WalkState, &Op, Status); |
if (ACPI_FAILURE (Status)) |
{ |
return_ACPI_STATUS (Status); |
} |
|
continue; |
} |
|
Op->Common.AmlOffset = WalkState->AmlOffset; |
|
if (WalkState->OpInfo) |
{ |
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, |
"Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", |
(UINT32) Op->Common.AmlOpcode, WalkState->OpInfo->Name, |
Op, ParserState->Aml, Op->Common.AmlOffset)); |
} |
} |
|
|
/* |
* Start ArgCount at zero because we don't know if there are |
* any args yet |
*/ |
WalkState->ArgCount = 0; |
|
/* Are there any arguments that must be processed? */ |
|
if (WalkState->ArgTypes) |
{ |
/* Get arguments */ |
|
Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op); |
if (ACPI_FAILURE (Status)) |
{ |
Status = AcpiPsCompleteOp (WalkState, &Op, Status); |
if (ACPI_FAILURE (Status)) |
{ |
return_ACPI_STATUS (Status); |
} |
|
continue; |
} |
} |
|
/* Check for arguments that need to be processed */ |
|
if (WalkState->ArgCount) |
{ |
/* |
* There are arguments (complex ones), push Op and |
* prepare for argument |
*/ |
Status = AcpiPsPushScope (ParserState, Op, |
WalkState->ArgTypes, WalkState->ArgCount); |
if (ACPI_FAILURE (Status)) |
{ |
Status = AcpiPsCompleteOp (WalkState, &Op, Status); |
if (ACPI_FAILURE (Status)) |
{ |
return_ACPI_STATUS (Status); |
} |
|
continue; |
} |
|
Op = NULL; |
continue; |
} |
|
/* |
* All arguments have been processed -- Op is complete, |
* prepare for next |
*/ |
WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode); |
if (WalkState->OpInfo->Flags & AML_NAMED) |
{ |
if (AcpiGbl_Depth) |
{ |
AcpiGbl_Depth--; |
} |
|
if (Op->Common.AmlOpcode == AML_REGION_OP || |
Op->Common.AmlOpcode == AML_DATA_REGION_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. |
*/ |
Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); |
} |
} |
|
if (WalkState->OpInfo->Flags & AML_CREATE) |
{ |
/* |
* Backup to beginning of CreateXXXfield declaration (1 for |
* Opcode) |
* |
* BodyLength is unknown until we parse the body |
*/ |
Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); |
} |
|
if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP) |
{ |
/* |
* Backup to beginning of BankField declaration |
* |
* BodyLength is unknown until we parse the body |
*/ |
Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data); |
} |
|
/* This op complete, notify the dispatcher */ |
|
if (WalkState->AscendingCallback != NULL) |
{ |
WalkState->Op = Op; |
WalkState->Opcode = Op->Common.AmlOpcode; |
|
Status = WalkState->AscendingCallback (WalkState); |
Status = AcpiPsNextParseState (WalkState, Op, Status); |
if (Status == AE_CTRL_PENDING) |
{ |
Status = AE_OK; |
} |
} |
|
Status = AcpiPsCompleteOp (WalkState, &Op, Status); |
if (ACPI_FAILURE (Status)) |
{ |
return_ACPI_STATUS (Status); |
} |
|
} /* while ParserState->Aml */ |
|
Status = AcpiPsCompleteFinalOp (WalkState, Op, Status); |
return_ACPI_STATUS (Status); |
} |
|