From 7abcc2ea1019f412ec899345495b820f30234603 Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Wed, 13 May 2009 13:04:01 -0700 Subject: [PATCH] New: AcpiInstallMethod - install a single control method. This interface enables the override or creation of a single control method. Useful to repair a bug or install a missing method. --- source/components/executer/excreate.c | 2 +- source/components/executer/exdump.c | 5 +- source/components/namespace/nsobject.c | 10 ++ source/components/namespace/nsxfname.c | 164 +++++++++++++++++++++++++ source/include/aclocal.h | 1 + source/include/acpixf.h | 4 + source/include/amlcode.h | 2 +- source/tools/acpiexec/aetables.c | 51 +++++++- 8 files changed, 234 insertions(+), 5 deletions(-) diff --git a/source/components/executer/excreate.c b/source/components/executer/excreate.c index 55385a089..e5463187a 100644 --- a/source/components/executer/excreate.c +++ b/source/components/executer/excreate.c @@ -614,7 +614,7 @@ AcpiExCreateMethod ( * ACPI 2.0: SyncLevel = SyncLevel in method declaration */ ObjDesc->Method.SyncLevel = (UINT8) - ((MethodFlags & AML_METHOD_SYNCH_LEVEL) >> 4); + ((MethodFlags & AML_METHOD_SYNC_LEVEL) >> 4); } /* Attach the new object to the method Node */ diff --git a/source/components/executer/exdump.c b/source/components/executer/exdump.c index f9b6066fa..d7745e7dc 100644 --- a/source/components/executer/exdump.c +++ b/source/components/executer/exdump.c @@ -213,10 +213,11 @@ static ACPI_EXDUMP_INFO AcpiExDumpEvent[2] = {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Event.OsSemaphore), "OsSemaphore"} }; -static ACPI_EXDUMP_INFO AcpiExDumpMethod[8] = +static ACPI_EXDUMP_INFO AcpiExDumpMethod[9] = { {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE (AcpiExDumpMethod), NULL}, - {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.ParamCount), "ParamCount"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.MethodFlags), "Method Flags"}, + {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.ParamCount), "Parameter Count"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.SyncLevel), "Sync Level"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET (Method.Mutex), "Mutex"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET (Method.OwnerId), "Owner Id"}, diff --git a/source/components/namespace/nsobject.c b/source/components/namespace/nsobject.c index 53afe6095..c0163f4ea 100644 --- a/source/components/namespace/nsobject.c +++ b/source/components/namespace/nsobject.c @@ -309,6 +309,16 @@ AcpiNsDetachObject ( return_VOID; } + if (Node->Flags & ANOBJ_ALLOCATED_BUFFER) + { + /* Free the dynamic aml buffer */ + + if (ObjDesc->Common.Type == ACPI_TYPE_METHOD) + { + ACPI_FREE (ObjDesc->Method.AmlStart); + } + } + /* Clear the entry in all cases */ Node->Object = NULL; diff --git a/source/components/namespace/nsxfname.c b/source/components/namespace/nsxfname.c index 21847a94a..49ccb5809 100644 --- a/source/components/namespace/nsxfname.c +++ b/source/components/namespace/nsxfname.c @@ -119,6 +119,8 @@ #include "acpi.h" #include "accommon.h" #include "acnamesp.h" +#include "acparser.h" +#include "amlcode.h" #define _COMPONENT ACPI_NAMESPACE @@ -478,3 +480,165 @@ Cleanup: ACPI_EXPORT_SYMBOL (AcpiGetObjectInfo) + +/****************************************************************************** + * + * FUNCTION: AcpiInstallMethod + * + * PARAMETERS: Buffer - An ACPI table containing one control method + * + * RETURN: Status + * + * DESCRIPTION: Install a control method into the namespace. If the method + * name already exists in the namespace, it is overwritten. The + * input buffer must contain a valid DSDT or SSDT containing a + * single control method. + * + ******************************************************************************/ + +ACPI_STATUS +AcpiInstallMethod ( + UINT8 *Buffer) +{ + ACPI_TABLE_HEADER *Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, Buffer); + UINT8 *AmlBuffer; + UINT8 *AmlStart; + char *Path; + ACPI_NAMESPACE_NODE *Node; + ACPI_OPERAND_OBJECT *MethodObj; + ACPI_PARSE_STATE ParserState; + UINT32 AmlLength; + UINT16 Opcode; + UINT8 MethodFlags; + ACPI_STATUS Status; + + + /* Parameter validation */ + + if (!Buffer) + { + return (AE_BAD_PARAMETER); + } + + /* Table must be a DSDT or SSDT */ + + if (!ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_DSDT) && + !ACPI_COMPARE_NAME (Table->Signature, ACPI_SIG_SSDT)) + { + return (AE_BAD_HEADER); + } + + /* First AML opcode in the table must be a control method */ + + ParserState.Aml = Buffer + sizeof (ACPI_TABLE_HEADER); + Opcode = AcpiPsPeekOpcode (&ParserState); + if (Opcode != AML_METHOD_OP) + { + return (AE_BAD_PARAMETER); + } + + /* Extract method information from the raw AML */ + + ParserState.Aml += AcpiPsGetOpcodeSize (Opcode); + ParserState.PkgEnd = AcpiPsGetNextPackageEnd (&ParserState); + Path = AcpiPsGetNextNamestring (&ParserState); + MethodFlags = *ParserState.Aml++; + AmlStart = ParserState.Aml; + AmlLength = ACPI_PTR_DIFF (ParserState.PkgEnd, AmlStart); + + /* + * Allocate resources up-front. We don't want to have to delete a new + * node from the namespace if we cannot allocate memory. + */ + AmlBuffer = ACPI_ALLOCATE (AmlLength); + if (!AmlBuffer) + { + return (AE_NO_MEMORY); + } + + MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD); + if (!MethodObj) + { + ACPI_FREE (AmlBuffer); + return (AE_NO_MEMORY); + } + + /* Lock namespace for AcpiNsLookup, we may be creating a new node */ + + Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE (Status)) + { + goto ErrorExit; + } + + /* The lookup either returns an existing node or creates a new one */ + + Status = AcpiNsLookup (NULL, Path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, + ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, NULL, &Node); + + (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); + + if (ACPI_FAILURE (Status)) /* NsLookup */ + { + if (Status != AE_ALREADY_EXISTS) + { + goto ErrorExit; + } + + /* Node existed previously, make sure it is a method node */ + + if (Node->Type != ACPI_TYPE_METHOD) + { + Status = AE_TYPE; + goto ErrorExit; + } + } + + /* Copy the method AML to the local buffer */ + + ACPI_MEMCPY (AmlBuffer, AmlStart, AmlLength); + + /* Initialize the method object with the new method's information */ + + MethodObj->Method.AmlStart = AmlBuffer; + MethodObj->Method.AmlLength = AmlLength; + + MethodObj->Method.ParamCount = (UINT8) + (MethodFlags & AML_METHOD_ARG_COUNT); + + MethodObj->Method.MethodFlags = (UINT8) + (MethodFlags & ~AML_METHOD_ARG_COUNT); + + if (MethodFlags & AML_METHOD_SERIALIZED) + { + MethodObj->Method.SyncLevel = (UINT8) + ((MethodFlags & AML_METHOD_SYNC_LEVEL) >> 4); + } + + /* + * Now that it is complete, we can attach the new method object to + * the method Node (detaches/deletes any existing object) + */ + Status = AcpiNsAttachObject (Node, MethodObj, + ACPI_TYPE_METHOD); + + /* + * Flag indicates AML buffer is dynamic, must be deleted later. + * Must be set only after attach above. + */ + Node->Flags |= ANOBJ_ALLOCATED_BUFFER; + + /* Remove local reference to the method object */ + + AcpiUtRemoveReference (MethodObj); + return (Status); + + +ErrorExit: + + ACPI_FREE (AmlBuffer); + ACPI_FREE (MethodObj); + return (Status); +} + +ACPI_EXPORT_SYMBOL (AcpiInstallMethod) diff --git a/source/include/aclocal.h b/source/include/aclocal.h index 4598d2826..0c566045f 100644 --- a/source/include/aclocal.h +++ b/source/include/aclocal.h @@ -298,6 +298,7 @@ typedef struct acpi_namespace_node #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ +#define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (InstallMethod) */ #define ANOBJ_IS_EXTERNAL 0x08 /* iASL only: This object created via External() */ #define ANOBJ_METHOD_NO_RETVAL 0x10 /* iASL only: Method has no return value */ diff --git a/source/include/acpixf.h b/source/include/acpixf.h index aab178d33..13c2da3dd 100644 --- a/source/include/acpixf.h +++ b/source/include/acpixf.h @@ -334,6 +334,10 @@ AcpiGetObjectInfo ( ACPI_HANDLE Handle, ACPI_BUFFER *ReturnBuffer); +ACPI_STATUS +AcpiInstallMethod ( + UINT8 *Buffer); + ACPI_STATUS AcpiGetNextObject ( ACPI_OBJECT_TYPE Type, diff --git a/source/include/amlcode.h b/source/include/amlcode.h index 5f2baf387..7694acc14 100644 --- a/source/include/amlcode.h +++ b/source/include/amlcode.h @@ -582,7 +582,7 @@ typedef enum #define AML_METHOD_ARG_COUNT 0x07 #define AML_METHOD_SERIALIZED 0x08 -#define AML_METHOD_SYNCH_LEVEL 0xF0 +#define AML_METHOD_SYNC_LEVEL 0xF0 /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ diff --git a/source/tools/acpiexec/aetables.c b/source/tools/acpiexec/aetables.c index bd2cbb9d4..1bf3b1e0d 100644 --- a/source/tools/acpiexec/aetables.c +++ b/source/tools/acpiexec/aetables.c @@ -189,6 +189,36 @@ unsigned char Oem1Code[] = 0x31,0x00,0x70,0x01,0x5F,0x58,0x54,0x32, /* 00000030 "1.p._XT2" */ }; +/* + * Example installable control method + * + * DefinitionBlock ("", "DSDT", 2, "Intel", "MTHDTEST", 0x20090512) + * { + * Method (\_SI_._T97, 1, Serialized) + * { + * Store ("Example installed method", Debug) + * Store (Arg0, Debug) + * Return () + * } + * } + * + * Compiled byte code below. + */ +unsigned char MethodCode[] = +{ + 0x44,0x53,0x44,0x54,0x53,0x00,0x00,0x00, /* 00000000 "DSDTS..." */ + 0x02,0xF9,0x49,0x6E,0x74,0x65,0x6C,0x00, /* 00000008 "..Intel." */ + 0x4D,0x54,0x48,0x44,0x54,0x45,0x53,0x54, /* 00000010 "MTHDTEST" */ + 0x12,0x05,0x09,0x20,0x49,0x4E,0x54,0x4C, /* 00000018 "... INTL" */ + 0x22,0x04,0x09,0x20,0x14,0x2E,0x2E,0x5F, /* 00000020 "".. ..._" */ + 0x54,0x49,0x5F,0x5F,0x54,0x39,0x37,0x09, /* 00000028 "SI__T97." */ + 0x70,0x0D,0x45,0x78,0x61,0x6D,0x70,0x6C, /* 00000030 "p.Exampl" */ + 0x65,0x20,0x69,0x6E,0x73,0x74,0x61,0x6C, /* 00000038 "e instal" */ + 0x6C,0x65,0x64,0x20,0x6D,0x65,0x74,0x68, /* 00000040 "led meth" */ + 0x6F,0x64,0x00,0x5B,0x31,0x70,0x68,0x5B, /* 00000048 "od.[1ph[" */ + 0x31,0xA4,0x00, +}; + /* * We need a local FADT so that the hardware subcomponent will function, @@ -427,7 +457,26 @@ AeInstallTables ( Status = AcpiInitializeTables (Tables, ACPI_MAX_INIT_TABLES, TRUE); Status = AcpiReallocateRootTable (); Status = AcpiLoadTables (); - return (Status); + + /* + * Test run-time control method installation. Do it twice to test code + * for an existing name. + */ + Status = AcpiInstallMethod (MethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install method\n", + AcpiFormatException (Status)); + } + + Status = AcpiInstallMethod (MethodCode); + if (ACPI_FAILURE (Status)) + { + AcpiOsPrintf ("%s, Could not install method\n", + AcpiFormatException (Status)); + } + + return (AE_OK); }