summaryrefslogtreecommitdiffstats
authorRobert Moore <Robert.Moore@intel.com>2009-07-23 16:53:29 (GMT)
committer Robert Moore <Robert.Moore@intel.com>2009-07-23 16:53:29 (GMT)
commit80d7951177315f70b5ffd8663985fbf725d07799 (patch)
tree089bf6dc9d3392e9ac1d809b13855b41ca19e96e
parent106406c1b87b6f7f28e7cc8ab086db2635178ee0 (diff)
downloadacpica-80d7951177315f70b5ffd8663985fbf725d07799.zip
acpica-80d7951177315f70b5ffd8663985fbf725d07799.tar.gz
acpica-80d7951177315f70b5ffd8663985fbf725d07799.tar.bz2
Add support for module-level executable AML code.
Add limited support for executable AML code that exists outside of any control method. This type of code has been illegal since ACPI 2.0. The code must exist in an If/Else/While block. All AML tables are supported, including tables that are dynamically loaded. ACPICA BZ 762. Lin Ming.
-rw-r--r--source/compiler/aslstubs.c7
-rw-r--r--source/components/dispatcher/dsfield.c18
-rw-r--r--source/components/dispatcher/dsmethod.c16
-rw-r--r--source/components/dispatcher/dswload.c39
-rw-r--r--source/components/executer/exconfig.c7
-rw-r--r--source/components/namespace/nseval.c149
-rw-r--r--source/components/parser/psloop.c128
-rw-r--r--source/components/parser/psxface.c5
-rw-r--r--source/components/utilities/utglobal.c1
-rw-r--r--source/components/utilities/utxface.c10
-rw-r--r--source/include/acglobal.h2
-rw-r--r--source/include/acnamesp.h4
-rw-r--r--source/include/acobject.h1
-rw-r--r--source/include/acparser.h1
14 files changed, 337 insertions, 51 deletions
diff --git a/source/compiler/aslstubs.c b/source/compiler/aslstubs.c
index cb822e5..b352a68 100644
--- a/source/compiler/aslstubs.c
+++ b/source/compiler/aslstubs.c
@@ -119,6 +119,7 @@
#include "actables.h"
#include "acevents.h"
#include "acinterp.h"
+#include "acnamesp.h"
#define _COMPONENT ACPI_COMPILER
ACPI_MODULE_NAME ("aslstubs")
@@ -136,6 +137,12 @@ AeLocalGetRootPointer (
return 0;
}
+void
+AcpiNsExecModuleCodeList (
+ void)
+{
+}
+
ACPI_STATUS
AcpiHwReadPort (
ACPI_IO_ADDRESS Address,
diff --git a/source/components/dispatcher/dsfield.c b/source/components/dispatcher/dsfield.c
index 2d8e586..12d55f4 100644
--- a/source/components/dispatcher/dsfield.c
+++ b/source/components/dispatcher/dsfield.c
@@ -211,9 +211,12 @@ AcpiDsCreateBufferField (
Flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;
- /* Mark node temporary if we are executing a method */
-
- if (WalkState->MethodNode)
+ /*
+ * Mark node temporary if we are executing a normal control
+ * method. (Don't mark if this is a module-level code method)
+ */
+ if (WalkState->MethodNode &&
+ !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL))
{
Flags |= ACPI_NS_TEMPORARY;
}
@@ -566,9 +569,12 @@ AcpiDsInitFieldObjects (
Flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
ACPI_NS_ERROR_IF_FOUND;
- /* Mark node(s) temporary if we are executing a method */
-
- if (WalkState->MethodNode)
+ /*
+ * Mark node(s) temporary if we are executing a normal control
+ * method. (Don't mark if this is a module-level code method)
+ */
+ if (WalkState->MethodNode &&
+ !(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL))
{
Flags |= ACPI_NS_TEMPORARY;
}
diff --git a/source/components/dispatcher/dsmethod.c b/source/components/dispatcher/dsmethod.c
index d4127fd..1766fc3 100644
--- a/source/components/dispatcher/dsmethod.c
+++ b/source/components/dispatcher/dsmethod.c
@@ -693,10 +693,15 @@ AcpiDsTerminateControlMethod (
}
/*
- * Delete any namespace objects created anywhere within
- * the namespace by the execution of this method
+ * Delete any namespace objects created anywhere within the
+ * namespace by the execution of this method. Unless this method
+ * is a module-level executable code method, in which case we
+ * want make the objects permanent.
*/
- AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
+ if (!(MethodDesc->Method.Flags & AOPOBJ_MODULE_LEVEL))
+ {
+ AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId);
+ }
}
/* Decrement the thread count on the method */
@@ -745,7 +750,10 @@ AcpiDsTerminateControlMethod (
/* No more threads, we can free the OwnerId */
- AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
+ if (!(MethodDesc->Method.Flags & AOPOBJ_MODULE_LEVEL))
+ {
+ AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId);
+ }
}
return_VOID;
diff --git a/source/components/dispatcher/dswload.c b/source/components/dispatcher/dswload.c
index d5a642c..2c067f1 100644
--- a/source/components/dispatcher/dswload.c
+++ b/source/components/dispatcher/dswload.c
@@ -672,20 +672,6 @@ AcpiDsLoad2BeginOp (
(WalkState->Opcode != AML_INT_NAMEPATH_OP)) ||
(!(WalkState->OpInfo->Flags & AML_NAMED)))
{
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- if ((WalkState->OpInfo->Class == AML_CLASS_EXECUTE) ||
- (WalkState->OpInfo->Class == AML_CLASS_CONTROL))
- {
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
- "Begin/EXEC: %s (fl %8.8X)\n", WalkState->OpInfo->Name,
- WalkState->OpInfo->Flags));
-
- /* Executing a type1 or type2 opcode outside of a method */
-
- Status = AcpiDsExecBeginOp (WalkState, OutOp);
- return_ACPI_STATUS (Status);
- }
-#endif
return_ACPI_STATUS (AE_OK);
}
@@ -862,7 +848,12 @@ AcpiDsLoad2BeginOp (
{
/* Execution mode, node cannot already exist, node is temporary */
- Flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+ Flags |= ACPI_NS_ERROR_IF_FOUND;
+
+ if (!(WalkState->ParseFlags & ACPI_PARSE_MODULE_LEVEL))
+ {
+ Flags |= ACPI_NS_TEMPORARY;
+ }
}
/* Add new entry or lookup existing entry */
@@ -952,24 +943,6 @@ AcpiDsLoad2EndOp (
if (!(WalkState->OpInfo->Flags & AML_NSOBJECT))
{
-#ifndef ACPI_NO_METHOD_EXECUTION
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
- /* No namespace object. Executable opcode? */
-
- if ((WalkState->OpInfo->Class == AML_CLASS_EXECUTE) ||
- (WalkState->OpInfo->Class == AML_CLASS_CONTROL))
- {
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
- "End/EXEC: %s (fl %8.8X)\n", WalkState->OpInfo->Name,
- WalkState->OpInfo->Flags));
-
- /* Executing a type1 or type2 opcode outside of a method */
-
- Status = AcpiDsExecEndOp (WalkState);
- return_ACPI_STATUS (Status);
- }
-#endif
-#endif
return_ACPI_STATUS (AE_OK);
}
diff --git a/source/components/executer/exconfig.c b/source/components/executer/exconfig.c
index 5b48bef..8c08165 100644
--- a/source/components/executer/exconfig.c
+++ b/source/components/executer/exconfig.c
@@ -196,8 +196,15 @@ AcpiExAddTable (
{
AcpiUtRemoveReference (ObjDesc);
*DdbHandle = NULL;
+ return_ACPI_STATUS (Status);
}
+ /* Execute any module-level code that was found in the table */
+
+ AcpiExExitInterpreter ();
+ AcpiNsExecModuleCodeList ();
+ AcpiExEnterInterpreter ();
+
return_ACPI_STATUS (Status);
}
diff --git a/source/components/namespace/nseval.c b/source/components/namespace/nseval.c
index 9b31a55..c84a4d5 100644
--- a/source/components/namespace/nseval.c
+++ b/source/components/namespace/nseval.c
@@ -126,6 +126,13 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nseval")
+/* Local prototypes */
+
+static void
+AcpiNsExecModuleCode (
+ ACPI_OPERAND_OBJECT *MethodObj,
+ ACPI_EVALUATE_INFO *Info);
+
/*******************************************************************************
*
@@ -360,3 +367,145 @@ AcpiNsEvaluate (
return_ACPI_STATUS (Status);
}
+
+/*******************************************************************************
+ *
+ * FUNCTION: AcpiNsExecModuleCodeList
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None. Exceptions during method execution are ignored, since
+ * we cannot abort a table load.
+ *
+ * DESCRIPTION: Execute all elements of the global module-level code list.
+ * Each element is executed as a single control method.
+ *
+ ******************************************************************************/
+
+void
+AcpiNsExecModuleCodeList (
+ void)
+{
+ ACPI_OPERAND_OBJECT *Prev;
+ ACPI_OPERAND_OBJECT *Next;
+ ACPI_EVALUATE_INFO *Info;
+ UINT32 MethodCount = 0;
+
+
+ ACPI_FUNCTION_TRACE (NsExecModuleCodeList);
+
+
+ /* Exit now if the list is empty */
+
+ Next = AcpiGbl_ModuleCodeList;
+ if (!Next)
+ {
+ return_VOID;
+ }
+
+ /* Allocate the evaluation information block */
+
+ Info = ACPI_ALLOCATE (sizeof (ACPI_EVALUATE_INFO));
+ if (!Info)
+ {
+ return_VOID;
+ }
+
+ /* Walk the list, executing each "method" */
+
+ while (Next)
+ {
+ Prev = Next;
+ Next = Next->Method.Mutex;
+
+ /* Clear the link field and execute the method */
+
+ Prev->Method.Mutex = NULL;
+ AcpiNsExecModuleCode (Prev, Info);
+ MethodCount++;
+
+ /* Delete the (temporary) method object */
+
+ AcpiUtRemoveReference (Prev);
+ }
+
+ ACPI_INFO ((AE_INFO,
+ "Executed %u blocks of module-level executable AML code",
+ MethodCount));
+
+ ACPI_FREE (Info);
+ AcpiGbl_ModuleCodeList = NULL;
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: AcpiNsExecModuleCode
+ *
+ * PARAMETERS: MethodObj - Object container for the module-level code
+ * Info - Info block for method evaluation
+ *
+ * RETURN: None. Exceptions during method execution are ignored, since
+ * we cannot abort a table load.
+ *
+ * DESCRIPTION: Execute a control method containing a block of module-level
+ * executable AML code. The control method is temporarily
+ * installed to the root node, then evaluated.
+ *
+ ******************************************************************************/
+
+static void
+AcpiNsExecModuleCode (
+ ACPI_OPERAND_OBJECT *MethodObj,
+ ACPI_EVALUATE_INFO *Info)
+{
+ ACPI_OPERAND_OBJECT *RootObj;
+ ACPI_STATUS Status;
+
+
+ ACPI_FUNCTION_TRACE (NsExecModuleCode);
+
+
+ /* Initialize the evaluation information block */
+
+ ACPI_MEMSET (Info, 0, sizeof (ACPI_EVALUATE_INFO));
+ Info->PrefixNode = AcpiGbl_RootNode;
+
+ /*
+ * Get the currently attached root object. Add a reference, because the
+ * ref count will be decreased when the method object is installed to
+ * the root node.
+ */
+ RootObj = AcpiNsGetAttachedObject (AcpiGbl_RootNode);
+ AcpiUtAddReference (RootObj);
+
+ /* Install the method (module-level code) in the root node */
+
+ Status = AcpiNsAttachObject (AcpiGbl_RootNode, MethodObj,
+ ACPI_TYPE_METHOD);
+ if (ACPI_FAILURE (Status))
+ {
+ goto Exit;
+ }
+
+ /* Execute the root node as a control method */
+
+ Status = AcpiNsEvaluate (Info);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Executed module-level code at %p\n",
+ MethodObj->Method.AmlStart));
+
+ /* Detach the temporary method object */
+
+ AcpiNsDetachObject (AcpiGbl_RootNode);
+
+ /* Restore the original root object */
+
+ Status = AcpiNsAttachObject (AcpiGbl_RootNode, RootObj, ACPI_TYPE_DEVICE);
+
+Exit:
+ AcpiUtRemoveReference (RootObj);
+ return_VOID;
+}
+
diff --git a/source/components/parser/psloop.c b/source/components/parser/psloop.c
index a6f4344..83a1be3 100644
--- a/source/components/parser/psloop.c
+++ b/source/components/parser/psloop.c
@@ -171,6 +171,12 @@ AcpiPsCompleteFinalOp (
ACPI_PARSE_OBJECT *Op,
ACPI_STATUS Status);
+static void
+AcpiPsLinkModuleCode (
+ UINT8 *AmlStart,
+ UINT32 AmlLength,
+ ACPI_OWNER_ID OwnerId);
+
/*******************************************************************************
*
@@ -502,6 +508,7 @@ AcpiPsGetArguments (
{
ACPI_STATUS Status = AE_OK;
ACPI_PARSE_OBJECT *Arg = NULL;
+ const ACPI_OPCODE_INFO *OpInfo;
ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);
@@ -558,13 +565,11 @@ AcpiPsGetArguments (
}
- /* Special processing for certain opcodes */
-
- /* TBD (remove): Temporary mechanism to disable this code if needed */
-
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
-
- if ((WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS1) &&
+ /*
+ * 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))
{
/*
@@ -580,6 +585,19 @@ AcpiPsGetArguments (
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 (AmlOpStart,
+ WalkState->ParserState.PkgEnd - AmlOpStart,
+ WalkState->OwnerId);
+ }
+
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
"Pass1: Skipping an If/Else/While body\n"));
@@ -590,10 +608,32 @@ AcpiPsGetArguments (
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: [%s] at table offset 0x%.4X",
+ OpInfo->Name,
+ (AmlOpStart - WalkState->ParserState.AmlStart) +
+ sizeof (ACPI_TABLE_HEADER)));
+ }
+ }
break;
}
}
-#endif
+
+ /* Special processing for certain opcodes */
switch (Op->Common.AmlOpcode)
{
@@ -661,6 +701,78 @@ AcpiPsGetArguments (
/*******************************************************************************
*
+ * FUNCTION: AcpiPsLinkModuleCode
+ *
+ * PARAMETERS: 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 (
+ UINT8 *AmlStart,
+ UINT32 AmlLength,
+ ACPI_OWNER_ID OwnerId)
+{
+ ACPI_OPERAND_OBJECT *Prev;
+ ACPI_OPERAND_OBJECT *Next;
+ ACPI_OPERAND_OBJECT *MethodObj;
+
+
+ /* 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;
+ }
+
+ MethodObj->Method.AmlStart = AmlStart;
+ MethodObj->Method.AmlLength = AmlLength;
+ MethodObj->Method.OwnerId = OwnerId;
+ MethodObj->Method.Flags |= AOPOBJ_MODULE_LEVEL;
+
+ if (!Prev)
+ {
+ AcpiGbl_ModuleCodeList = MethodObj;
+ }
+ else
+ {
+ Prev->Method.Mutex = MethodObj;
+ }
+ }
+ else
+ {
+ Prev->Method.AmlLength += AmlLength;
+ }
+}
+
+
+/*******************************************************************************
+ *
* FUNCTION: AcpiPsCompleteOp
*
* PARAMETERS: WalkState - Current state
diff --git a/source/components/parser/psxface.c b/source/components/parser/psxface.c
index d63abb6..1859b69 100644
--- a/source/components/parser/psxface.c
+++ b/source/components/parser/psxface.c
@@ -394,6 +394,11 @@ AcpiPsExecuteMethod (
goto Cleanup;
}
+ if (Info->ObjDesc->Method.Flags & AOPOBJ_MODULE_LEVEL)
+ {
+ WalkState->ParseFlags |= ACPI_PARSE_MODULE_LEVEL;
+ }
+
/* Invoke an internal method if necessary */
if (Info->ObjDesc->Method.MethodFlags & AML_METHOD_INTERNAL_ONLY)
diff --git a/source/components/utilities/utglobal.c b/source/components/utilities/utglobal.c
index 7b63b75..b61b3fb 100644
--- a/source/components/utilities/utglobal.c
+++ b/source/components/utilities/utglobal.c
@@ -938,6 +938,7 @@ AcpiUtInitGlobals (
/* Namespace */
+ AcpiGbl_ModuleCodeList = NULL;
AcpiGbl_RootNode = NULL;
AcpiGbl_RootNodeStruct.Name.Integer = ACPI_ROOT_NAME;
AcpiGbl_RootNodeStruct.DescriptorType = ACPI_DESC_TYPE_NAMED;
diff --git a/source/components/utilities/utxface.c b/source/components/utilities/utxface.c
index ad887c7..ba57f49 100644
--- a/source/components/utilities/utxface.c
+++ b/source/components/utilities/utxface.c
@@ -360,6 +360,16 @@ AcpiInitializeObjects (
}
/*
+ * Execute any module-level code that was detected during the table load
+ * phase. Although illegal since ACPI 2.0, there are many machines that
+ * contain this type of code. Each block of detected executable AML code
+ * outside of any control method is wrapped with a temporary control
+ * method object and placed on a global list. The methods on this list
+ * are executed below.
+ */
+ AcpiNsExecModuleCodeList ();
+
+ /*
* Initialize the objects that remain uninitialized. This runs the
* executable AML that may be part of the declaration of these objects:
* OperationRegions, BufferFields, Buffers, and Packages.
diff --git a/source/include/acglobal.h b/source/include/acglobal.h
index 8588843..42b0d82 100644
--- a/source/include/acglobal.h
+++ b/source/include/acglobal.h
@@ -356,6 +356,8 @@ ACPI_EXTERN BOOLEAN AcpiGbl_DisplayFinalMemStats;
ACPI_EXTERN ACPI_NAMESPACE_NODE AcpiGbl_RootNodeStruct;
ACPI_EXTERN ACPI_NAMESPACE_NODE *AcpiGbl_RootNode;
ACPI_EXTERN ACPI_NAMESPACE_NODE *AcpiGbl_FadtGpeDevice;
+ACPI_EXTERN ACPI_OPERAND_OBJECT *AcpiGbl_ModuleCodeList;
+
extern const UINT8 AcpiGbl_NsProperties [ACPI_NUM_NS_TYPES];
extern const ACPI_PREDEFINED_NAMES AcpiGbl_PreDefinedNames [NUM_PREDEFINED_NAMES];
diff --git a/source/include/acnamesp.h b/source/include/acnamesp.h
index ab967dc..ce0ba2a 100644
--- a/source/include/acnamesp.h
+++ b/source/include/acnamesp.h
@@ -322,6 +322,10 @@ ACPI_STATUS
AcpiNsEvaluate (
ACPI_EVALUATE_INFO *Info);
+void
+AcpiNsExecModuleCodeList (
+ void);
+
/*
* nspredef - Support for predefined/reserved names
diff --git a/source/include/acobject.h b/source/include/acobject.h
index 5941859..5a33fdc 100644
--- a/source/include/acobject.h
+++ b/source/include/acobject.h
@@ -170,6 +170,7 @@
#define AOPOBJ_OBJECT_INITIALIZED 0x08
#define AOPOBJ_SETUP_COMPLETE 0x10
#define AOPOBJ_SINGLE_DATUM 0x20
+#define AOPOBJ_MODULE_LEVEL 0x40
/******************************************************************************
diff --git a/source/include/acparser.h b/source/include/acparser.h
index b65177b..086688e 100644
--- a/source/include/acparser.h
+++ b/source/include/acparser.h
@@ -137,6 +137,7 @@
#define ACPI_PARSE_DEFERRED_OP 0x0100
#define ACPI_PARSE_DISASSEMBLE 0x0200
+#define ACPI_PARSE_MODULE_LEVEL 0x0400
/******************************************************************************
*