minix/drivers/acpi/parser/psloop.c
Tomas Hruby 9560b6dea8 ACPI driver
- 99% of the code is Intel's ACPICA. The license is compliant with BSD
  and GNU and virtually all systems that use ACPI use this code, For
  instance it is part of the Linux kernel.

- The only minix specific files are

  acpi.c
  osminixxf.c
  platform/acminix.h

  and

  include/minix/acpi.h

- At the moment the driver does not register interrupt hooks which I
  believe is mainly for handling PnP, events like "battery level is
  low" and power management. Should not be difficult to add it if need
  be.

- The interface to the outside world is virtually non-existent except
  a trivial message based service for PCI driver to query which device
  is connected to what IRQ line. This will evolve as more components
  start using this driver. VM, Scheduler and IOMMU are the possible
  users right now.

- because of dependency on a native 64bit (long long, part of c99) it
  is compiled only with a gnu-like compilers which in case of Minix
  includes gcc llvm-gcc and clang
2010-09-02 15:44:04 +00:00

1340 lines
41 KiB
C

/******************************************************************************
*
* 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);
}