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.
This commit is contained in:
Robert Moore 2009-05-13 13:04:01 -07:00
parent 43cfa272f6
commit 7abcc2ea10
8 changed files with 234 additions and 5 deletions

View File

@ -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 */

View File

@ -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"},

View File

@ -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;

View File

@ -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)

View File

@ -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 */

View File

@ -334,6 +334,10 @@ AcpiGetObjectInfo (
ACPI_HANDLE Handle,
ACPI_BUFFER *ReturnBuffer);
ACPI_STATUS
AcpiInstallMethod (
UINT8 *Buffer);
ACPI_STATUS
AcpiGetNextObject (
ACPI_OBJECT_TYPE Type,

View File

@ -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 */

View File

@ -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);
}