You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1685 lines
50 KiB
1685 lines
50 KiB
/*** amliapi.c - AMLI APIs
|
|
*
|
|
* Copyright (c) 1996,1997 Microsoft Corporation
|
|
* Author: Michael Tsang (MikeTs)
|
|
* Created 08/13/96
|
|
*
|
|
* MODIFICATION HISTORY
|
|
*/
|
|
|
|
#include "pch.h"
|
|
//#include "amlihook.h"
|
|
//#include "amlitest.h"
|
|
|
|
#ifdef LOCKABLE_PRAGMA
|
|
#pragma ACPI_LOCKABLE_DATA
|
|
#pragma ACPI_LOCKABLE_CODE
|
|
#endif
|
|
|
|
/*++
|
|
OSIAML contains the AML for the _OSI Method. This AML is generated from the following ASL:
|
|
|
|
Method(_OSI, 0x1, NotSerialized)
|
|
{
|
|
Return(OSI(Arg0))
|
|
}
|
|
--*/
|
|
|
|
UCHAR OSIAML[] = {
|
|
0xa4, 0xca, 0x68
|
|
};
|
|
|
|
|
|
/***EP AMLIInitialize - Initialize AML interpreter
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIInitialize | AML Interpreter initialization.
|
|
*
|
|
* This function must be called before any AML interpreter functions
|
|
* can be called. This function will typically allocate and
|
|
* initialize global resources, create the ACPI name space etc.
|
|
* It is typically called in the initialization of the ACPI core
|
|
* driver.
|
|
*
|
|
* @PARM ULONG | dwCtxtBlkSize | Specifies the size of Context blocks. If
|
|
* zero, use default context block size.
|
|
*
|
|
* @PARM ULONG | dwGlobalHeapBlkSize | Specifies the size of Global heap.
|
|
* If zero, use default global heap size.
|
|
*
|
|
* @PARM ULONG | dwfAMLIInit | AMLI initialization flags.
|
|
*
|
|
* @FLAG AMLIIF_INIT_BREAK | Break into the debugger at initialization
|
|
* completion.
|
|
*
|
|
* @FLAG AMLIIF_LOADDDB_BREAK | Break into the debugger at load definition
|
|
* block completion.
|
|
*
|
|
* @PARM ULONG | dwmsTimeSliceLength | Time slice length in msec.
|
|
*
|
|
* @PARM ULONG | dwmsTimeSliceInterval | Time slice interval in msec.
|
|
*
|
|
* @PARM ULONG | dwmsMaxCTObjs | Number of context to allocate
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIInitialize(ULONG dwCtxtBlkSize, ULONG dwGlobalHeapBlkSize,
|
|
ULONG dwfAMLIInit, ULONG dwmsTimeSliceLength,
|
|
ULONG dwmsTimeSliceInterval, ULONG dwmsMaxCTObjs)
|
|
{
|
|
TRACENAME("AMLIINITIALIZE")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(1, ("AMLIInitialize(InitFlags=%x,CtxtBlkSize=%d,GlobalHeapBlkSize=%d,TimeSliceLen=%d,TimeSliceInterval=%d)\n",
|
|
dwfAMLIInit, dwCtxtBlkSize, dwGlobalHeapBlkSize,
|
|
dwmsTimeSliceLength, dwmsTimeSliceInterval));
|
|
|
|
#ifndef DEBUGGER
|
|
DEREF(dwfAMLIInit);
|
|
#endif
|
|
|
|
RESETERR();
|
|
if (gpnsNameSpaceRoot != NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_ALREADY_INITIALIZED,
|
|
("AMLIInitialize: interpreter already initialized"));
|
|
}
|
|
else
|
|
{
|
|
gdwCtxtBlkSize = dwCtxtBlkSize ? dwCtxtBlkSize: DEF_CTXTBLK_SIZE;
|
|
gdwGlobalHeapBlkSize = dwGlobalHeapBlkSize? dwGlobalHeapBlkSize:
|
|
DEF_GLOBALHEAPBLK_SIZE;
|
|
gdwfAMLIInit = dwfAMLIInit;
|
|
gdwfHacks = GetHackFlags(NULL);
|
|
|
|
//
|
|
// Sanity Check
|
|
//
|
|
if (dwmsMaxCTObjs > 1024) {
|
|
|
|
dwmsMaxCTObjs = 1024;
|
|
|
|
}
|
|
gdwcCTObjsMax = (dwmsMaxCTObjs > DEF_CTXTMAX_SIZE) ? dwmsMaxCTObjs :
|
|
DEF_CTXTMAX_SIZE;
|
|
|
|
#ifdef DEBUGGER
|
|
// gDebugger.dwfDebugger |= (DBGF_LOGEVENT_ON | DBGF_ERRBREAK_ON);
|
|
gDebugger.dwfDebugger |= DBGF_LOGEVENT_ON;
|
|
SetLogSize(DEF_MAXLOG_ENTRIES);
|
|
KeInitializeSpinLock( &gdwGHeapSpinLock );
|
|
#endif
|
|
KeInitializeSpinLock( &gdwGContextSpinLock );
|
|
|
|
//
|
|
// Initialize the LookAside lists.
|
|
//
|
|
ExInitializeNPagedLookasideList(
|
|
&AMLIContextLookAsideList,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
gdwCtxtBlkSize,
|
|
CTOBJ_TAG,
|
|
(USHORT) gdwcCTObjsMax
|
|
);
|
|
|
|
if ((rc = NewHeap(gdwGlobalHeapBlkSize, &gpheapGlobal)) ==
|
|
STATUS_SUCCESS)
|
|
{
|
|
int i;
|
|
PNSOBJ pns;
|
|
static PSZ apszDefinedRootObjs[] =
|
|
{
|
|
"_GPE", "_PR", "_SB", "_SI", "_TZ"
|
|
};
|
|
#define NUM_DEFINED_ROOT_OBJS (sizeof(apszDefinedRootObjs)/sizeof(PSZ))
|
|
|
|
gpheapGlobal->pheapHead = gpheapGlobal;
|
|
if ((rc = CreateNameSpaceObject(gpheapGlobal, NAMESTR_ROOT, NULL,
|
|
NULL, NULL, 0)) == STATUS_SUCCESS)
|
|
{
|
|
for (i = 0; i < NUM_DEFINED_ROOT_OBJS; ++i)
|
|
{
|
|
if ((rc = CreateNameSpaceObject(gpheapGlobal,
|
|
apszDefinedRootObjs[i],
|
|
NULL, NULL, NULL, 0)) !=
|
|
STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((rc == STATUS_SUCCESS) &&
|
|
((rc = CreateNameSpaceObject(gpheapGlobal, "_REV", NULL, NULL,
|
|
&pns, 0)) == STATUS_SUCCESS))
|
|
{
|
|
pns->ObjData.dwDataType = OBJTYPE_INTDATA;
|
|
pns->ObjData.uipDataValue = AMLI_REVISION;
|
|
}
|
|
|
|
if ((rc == STATUS_SUCCESS) &&
|
|
((rc = CreateNameSpaceObject(gpheapGlobal, "_OS", NULL, NULL,
|
|
&pns, 0)) == STATUS_SUCCESS))
|
|
{
|
|
pns->ObjData.dwDataType = OBJTYPE_STRDATA;
|
|
pns->ObjData.dwDataLen = STRLEN(gpszOSName) + 1;
|
|
if ((pns->ObjData.pbDataBuff = NEWSDOBJ(gpheapGlobal,
|
|
pns->ObjData.dwDataLen))
|
|
== NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("AMLIInitialize: failed to allocate \\_OS name object"));
|
|
}
|
|
else
|
|
{
|
|
MEMCPY(pns->ObjData.pbDataBuff, gpszOSName,
|
|
pns->ObjData.dwDataLen);
|
|
}
|
|
}
|
|
|
|
if ((rc == STATUS_SUCCESS) &&
|
|
((rc = CreateNameSpaceObject(gpheapGlobal,"_OSI", NULL, NULL,
|
|
&pns, 0)) == STATUS_SUCCESS))
|
|
{
|
|
|
|
pns->ObjData.dwDataType = OBJTYPE_METHOD;
|
|
pns->ObjData.dwDataLen = sizeof(METHODOBJ) + sizeof(OSIAML) - sizeof(UCHAR);
|
|
if ((pns->ObjData.pbDataBuff = NEWSDOBJ(gpheapGlobal,
|
|
pns->ObjData.dwDataLen))
|
|
== NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("AMLIInitiaize: failed to allocate \\_OSI name object"));
|
|
}
|
|
else
|
|
{
|
|
MEMZERO(pns->ObjData.pbDataBuff, pns->ObjData.dwDataLen);
|
|
//This method has one argument
|
|
((PMETHODOBJ)(pns->ObjData.pbDataBuff))->bMethodFlags |= 0x1;
|
|
|
|
MEMCPY(((PMETHODOBJ)(pns->ObjData.pbDataBuff))->abCodeBuff, (PUCHAR)OSIAML,
|
|
sizeof(OSIAML));
|
|
}
|
|
}
|
|
|
|
if ((rc == STATUS_SUCCESS) &&
|
|
((rc = CreateNameSpaceObject(gpheapGlobal, "_GL", NULL, NULL,
|
|
&pns, 0)) == STATUS_SUCCESS))
|
|
{
|
|
pns->ObjData.dwfData = DATAF_GLOBAL_LOCK;
|
|
rc = InitMutex(gpheapGlobal, pns, 0);
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
gReadyQueue.dwmsTimeSliceLength = dwmsTimeSliceLength?
|
|
dwmsTimeSliceLength:
|
|
DEF_TIMESLICE_LENGTH;
|
|
gReadyQueue.dwmsTimeSliceInterval = dwmsTimeSliceInterval?
|
|
dwmsTimeSliceInterval:
|
|
DEF_TIMESLICE_INTERVAL;
|
|
KeInitializeTimer(&gReadyQueue.Timer);
|
|
InitializeMutex(&gReadyQueue.mutCtxtQ);
|
|
ExInitializeWorkItem(&gReadyQueue.WorkItem,
|
|
StartTimeSlicePassive, &gReadyQueue);
|
|
InitializeMutex(&gmutCtxtList);
|
|
InitializeMutex(&gmutOwnerList);
|
|
InitializeMutex(&gmutHeap);
|
|
InitializeMutex(&gmutSleep);
|
|
KeInitializeDpc(&gReadyQueue.DpcStartTimeSlice,
|
|
StartTimeSlice,
|
|
&gReadyQueue);
|
|
KeInitializeDpc(&gReadyQueue.DpcExpireTimeSlice,
|
|
ExpireTimeSlice,
|
|
&gReadyQueue);
|
|
KeInitializeDpc(&SleepDpc, SleepQueueDpc, NULL);
|
|
KeInitializeTimer(&SleepTimer);
|
|
InitializeListHead(&SleepQueue);
|
|
InitializeRegOverrideFlags();
|
|
InitIllegalIOAddressListFromHAL();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gdwfAMLIInit & AMLIIF_INIT_BREAK)
|
|
{
|
|
PRINTF("\n" MODNAME ": Break at AMLI Initialization Completion.\n");
|
|
AMLIDebugger(FALSE);
|
|
}
|
|
#endif
|
|
|
|
EXIT(1, ("AMLIInitialize=%x\n", rc));
|
|
return rc;
|
|
} //AMLIInitialize
|
|
|
|
/***EP AMLITerminate - Terminate AML interpreter
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLITerminate | AML Interpreter termination.
|
|
*
|
|
* This function is called to clean up all the global resources used
|
|
* by the AML interpreter.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLITerminate(VOID)
|
|
{
|
|
TRACENAME("AMLITERMINATE")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(1, ("AMLITerminate()\n"));
|
|
|
|
RESETERR();
|
|
if (gpnsNameSpaceRoot == NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_NOT_INITIALIZED,
|
|
("AMLITerminate: interpreter not initialized"));
|
|
}
|
|
else
|
|
{
|
|
PLIST plist;
|
|
PHEAP pheap;
|
|
|
|
#ifdef DEBUGGER
|
|
FreeSymList();
|
|
if (gDebugger.pEventLog != NULL)
|
|
{
|
|
MFREE(gDebugger.pEventLog);
|
|
}
|
|
MEMZERO(&gDebugger, sizeof(DBGR));
|
|
#endif
|
|
|
|
ASSERT(gReadyQueue.pkthCurrent == NULL);
|
|
ASSERT(gReadyQueue.pctxtCurrent == NULL);
|
|
FreeNameSpaceObjects(gpnsNameSpaceRoot);
|
|
gpnsNameSpaceRoot = NULL;
|
|
MEMZERO(&gReadyQueue, sizeof(CTXTQ));
|
|
|
|
while ((plist = ListRemoveTail(&gplistCtxtHead)) != NULL)
|
|
{
|
|
FreeContext(CONTAINING_RECORD(plist, CTXT, listCtxt));
|
|
}
|
|
|
|
while ((plist = ListRemoveTail(&gplistObjOwners)) != NULL)
|
|
{
|
|
FreeObjOwner((POBJOWNER)plist, FALSE);
|
|
}
|
|
|
|
while ((plist = ListRemoveTail(&gplistDefuncNSObjs)) != NULL)
|
|
{
|
|
FREENSOBJ(CONTAINING_RECORD(plist, NSOBJ, list));
|
|
}
|
|
|
|
FreeRSAccessList(gpRSAccessHead);
|
|
gpRSAccessHead = NULL;
|
|
MEMZERO(&ghNotify, sizeof(EVHANDLE));
|
|
MEMZERO(&ghValidateTable, sizeof(EVHANDLE));
|
|
MEMZERO(&ghFatal, sizeof(EVHANDLE));
|
|
MEMZERO(&ghGlobalLock, sizeof(EVHANDLE));
|
|
MEMZERO(&ghCreate, sizeof(EVHANDLE));
|
|
MEMZERO(&ghDestroyObj,sizeof(EVHANDLE));
|
|
for (pheap = gpheapGlobal; pheap != NULL; pheap = gpheapGlobal)
|
|
{
|
|
gpheapGlobal = pheap->pheapNext;
|
|
FreeHeap(pheap);
|
|
}
|
|
|
|
FreellegalIOAddressList();
|
|
|
|
gdwfAMLI = 0;
|
|
|
|
#ifdef DEBUG
|
|
if (gdwcMemObjs != 0)
|
|
{
|
|
DumpMemObjCounts();
|
|
ASSERT(gdwcMemObjs == 0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
EXIT(1, ("AMLITerminate=%x\n", rc));
|
|
return rc;
|
|
} //AMLITerminate
|
|
|
|
/***EP AMLILoadDDB - Load and parse Differentiated Definition Block
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLILoadDDB | Load Differentiated Definition Block.
|
|
*
|
|
* This function loads and parses the given Differentiated System
|
|
* Description Table as well as any dynamic Differentiated Definition
|
|
* Block. It will parse the DDB and populate the ACPI name space
|
|
* accordingly.
|
|
*
|
|
* @PARM PDSDT | pDSDT | Pointer to a DSDT block.
|
|
*
|
|
* @PARM HANDLE * | phDDB | Pointer to the variable that will receive
|
|
* the DDB handle (can be NULL).
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code if encountering parse error.
|
|
*
|
|
* @DEVNOTE If an error occurs in the middle of loading a DDB, the loading
|
|
* will be aborted but the objects created prior to the error remain
|
|
* in the name space. Therefore, it is the responsibility of the
|
|
* caller to call AMLIUnLoadDDB to destroy the created objects if
|
|
* desired and the return handle is not NULL.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLILoadDDB(PDSDT pDSDT, HANDLE *phDDB)
|
|
{
|
|
TRACENAME("AMLILOADDDB")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PCTXT pctxt = NULL;
|
|
POBJOWNER powner = NULL;
|
|
|
|
ENTER(1, ("AMLILoadDDB(pDSDT=%x,phDDB=%x)\n", pDSDT, phDDB));
|
|
|
|
ASSERT(pDSDT != NULL);
|
|
RESETERR();
|
|
CHKDEBUGGERREQ();
|
|
|
|
gInitTime = TRUE;
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: Loading Definition Block %s at 0x%p.\n",
|
|
KeGetCurrentThread(), NameSegString(pDSDT->Header.Signature),
|
|
pDSDT);
|
|
}
|
|
#endif
|
|
|
|
gdwfHacks |= GetHackFlags(pDSDT);
|
|
|
|
if ((rc = NewContext(&pctxt)) == STATUS_SUCCESS)
|
|
{
|
|
ASSERT(gpheapGlobal != NULL);
|
|
pctxt->pheapCurrent = gpheapGlobal;
|
|
|
|
#ifdef DEBUG
|
|
gdwfAMLI |= AMLIF_LOADING_DDB;
|
|
#endif
|
|
|
|
if (atLoad.pfnCallBack != NULL && atLoad.dwfOpcode & OF_CALLBACK_EX) {
|
|
|
|
((PFNOPEX)atLoad.pfnCallBack)(
|
|
EVTYPE_OPCODE_EX,
|
|
OPEXF_NOTIFY_PRE,
|
|
atLoad.dwOpcode,
|
|
NULL,
|
|
atLoad.dwCBData
|
|
);
|
|
|
|
}
|
|
|
|
rc = LoadDDB(pctxt,pDSDT, gpnsNameSpaceRoot, &powner);
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
rc = SyncLoadDDB(pctxt);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
gdwfAMLI &= ~AMLIF_LOADING_DDB;
|
|
KeAcquireSpinLock( &gdwGHeapSpinLock, &oldIrql );
|
|
gdwGHeapSnapshot = gdwGlobalHeapSize;
|
|
KeReleaseSpinLock( &gdwGHeapSpinLock, oldIrql );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (phDDB != NULL)
|
|
{
|
|
*phDDB = (HANDLE)powner;
|
|
}
|
|
|
|
if ((powner != NULL) && (atLoad.pfnCallBack != NULL))
|
|
{
|
|
if (atLoad.dwfOpcode & OF_CALLBACK_EX) {
|
|
|
|
((PFNOPEX)atLoad.pfnCallBack)(
|
|
EVTYPE_OPCODE_EX,
|
|
OPEXF_NOTIFY_POST,
|
|
atLoad.dwOpcode,
|
|
NULL,
|
|
atLoad.dwCBData
|
|
);
|
|
|
|
} else {
|
|
|
|
atLoad.pfnCallBack(
|
|
EVTYPE_OPCODE,
|
|
atLoad.dwOpcode,
|
|
NULL,
|
|
atLoad.dwCBData
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
#ifdef DEBUGGER
|
|
if (gdwfAMLIInit & AMLIIF_LOADDDB_BREAK)
|
|
{
|
|
PRINTF("\n" MODNAME ": Break at Load Definition Block Completion.\n");
|
|
AMLIDebugger(FALSE);
|
|
}
|
|
#endif
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
gInitTime = FALSE;
|
|
|
|
EXIT(1, ("AMLILoadDDB=%x (powner=%x)\n", rc, powner));
|
|
return rc;
|
|
} //AMLILoadDDB
|
|
|
|
/***EP AMLIUnloadDDB - Unload Differentiated Definition Block
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC VOID | AMLIUnloadDDB | Unload the Differentiated Definition Block.
|
|
*
|
|
* This function is called to unload the given dynamic DDB object and
|
|
* clean it out of the name space. Note that this function does not
|
|
* differentiate between a DSDT from a dynamic DDB, so it is the
|
|
* caller's responsibility to not freeing the DSDT accidentally.
|
|
*
|
|
* @PARM HANDLE | hDDB | handle to the definition block context to be
|
|
* unloaded.
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
VOID AMLIAPI AMLIUnloadDDB(HANDLE hDDB)
|
|
{
|
|
TRACENAME("AMLIUNLOADDDB")
|
|
|
|
ENTER(1, ("AMLIUnloadDDB(hDDB=%x)\n", hDDB));
|
|
|
|
RESETERR();
|
|
if (hDDB != NULL)
|
|
{
|
|
ASSERT(((POBJOWNER)hDDB)->dwSig == SIG_OBJOWNER);
|
|
UnloadDDB((POBJOWNER)hDDB);
|
|
}
|
|
|
|
EXIT(1, ("AMLIUnloadDDB!\n"));
|
|
} //AMLIUnloadDDB
|
|
|
|
/***EP AMLIGetNameSpaceObject - Find a name space object
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIGetNameSpaceObject | Find an object in the ACPI
|
|
* name space.
|
|
*
|
|
* This function accepts an absolute object path as well as a
|
|
* relative object path in the form of an ASCIIZ string.
|
|
* It will search through the name space in the appropriate
|
|
* scope for the given object path and returns the object
|
|
* pointer when it is found.
|
|
*
|
|
* @PARM PSZ | pszObjPath | Pointer to an ASCIIZ string specifying the
|
|
* object path.
|
|
*
|
|
* @PARM PNSOBJ | pnsScope | If not NULL, this points to the object scope
|
|
* where the search starts. If pszObjPath is specifying an absolute
|
|
* path, this parameter is ignored.
|
|
*
|
|
* @PARM PPNSOBJ | ppns | Pointer to a variable to hold the object
|
|
* point.
|
|
*
|
|
* @PARM ULONG | dwfFlags | Option flags.
|
|
*
|
|
* @FLAG NSF_LOCAL_SCOPE | Search local scope only.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIGetNameSpaceObject(PSZ pszObjPath, PNSOBJ pnsScope,
|
|
PPNSOBJ ppns, ULONG dwfFlags)
|
|
{
|
|
TRACENAME("AMLIGETNAMESPACEOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIGetNameSpaceObject(ObjPath=%s,Scope=%s,ppns=%p,Flags=%x)\n",
|
|
pszObjPath, GetObjectPath(pnsScope), ppns, dwfFlags));
|
|
|
|
ASSERT(pszObjPath != NULL);
|
|
ASSERT(*pszObjPath != '\0');
|
|
ASSERT(ppns != NULL);
|
|
RESETERR();
|
|
CHKDEBUGGERREQ();
|
|
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_GetNameSpaceObject(
|
|
pszObjPath,pnsScope,ppns,dwfFlags,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
|
|
}
|
|
|
|
if ((pnsScope != NULL) && (pnsScope->ObjData.dwfData & DATAF_NSOBJ_DEFUNC))
|
|
{
|
|
AMLI_WARN(("AMLIGetNameSpaceObject: pnsScope is no longer valid"));
|
|
rc = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
ASSERT((pnsScope == NULL) || !(pnsScope->ObjData.dwfData & DATAF_NSOBJ_DEFUNC));
|
|
rc = GetNameSpaceObject(pszObjPath, pnsScope, ppns, dwfFlags);
|
|
}
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
rc = AMLITest_Post_GetNameSpaceObject(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
EXIT(1, ("AMLIGetNameSpaceObject=%x (pns=%p)\n", rc, *ppns));
|
|
return rc;
|
|
} //AMLIGetNameSpaceObject
|
|
|
|
/***EP AMLIGetFieldUnitRegionObj - Get OpRegion associated with FieldUnit
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIGetFieldUnitRegionObj | Get the OperationRegion
|
|
* object associated with the FieldUnit object.
|
|
*
|
|
* @PARM PFIELDUNITOBJ | pfu | Pointer to a FieldUnit object.
|
|
*
|
|
* @PARM PPNSOBJ | ppns | Pointer to a variable to hold the OperationRegion
|
|
* object.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIGetFieldUnitRegionObj(PFIELDUNITOBJ pfu, PPNSOBJ ppns)
|
|
{
|
|
TRACENAME("AMLIGETFIELDUNITREGIONOBJ")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
|
|
ENTER(1, ("AMLIGetFieldUnitRegionObj(pfu=%x,ppns=%x)\n", pfu, ppns));
|
|
|
|
ASSERT(pfu != NULL);
|
|
ASSERT(ppns != NULL);
|
|
RESETERR();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_GetFieldUnitRegionObj(
|
|
pfu,ppns,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
|
|
}
|
|
|
|
rc = GetFieldUnitRegionObj(pfu, ppns);
|
|
|
|
if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_GetFieldUnitRegionObj(
|
|
&pHData,rc);
|
|
}
|
|
|
|
EXIT(1, ("AMLIGetFieldUnitRegionObj=%x (pns=%x)\n", rc, *ppns));
|
|
return rc;
|
|
} //AMLIGetFieldUnitRegionObj
|
|
|
|
/***EP AMLIEvalNameSpaceObject - Evaluate a name space object
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIEvalNameSpaceObject | Evaluate a name space object.
|
|
*
|
|
* This function evaluate a given object. If the given object is a
|
|
* control method, it will execute it. If the given object is a data
|
|
* object, the data value is returned in a given buffer.
|
|
*
|
|
* @PARM PNSOBJ | pns | Pointer to the object to be evaluated.
|
|
*
|
|
* @PARM POBJDATA | pdataResult | Pointer to the OBJDATA structure which will
|
|
* hold the result of the evaluation (can be NULL if don't care about
|
|
* result).
|
|
*
|
|
* @PARM int | icArgs | Specify the number of arguments pass to the method
|
|
* object for evaluation (only valid if pns points to a method object).
|
|
*
|
|
* @PARM POBJDATA | pdataArgs | Pointer to an array of argument data object
|
|
* (only valid if pns points to a method object).
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*
|
|
* @DEVNOTE The returned object may contain buffer pointer to the actual
|
|
* data in the ACPI name space. Therefore, the caller must be very
|
|
* careful not to overwrite any data in the buffer. Also, the caller
|
|
* is responsible for calling AMLIFreeDataBuffs on the result object
|
|
* after the result object data is no longer needed.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIEvalNameSpaceObject(PNSOBJ pns, POBJDATA pdataResult,
|
|
int icArgs, POBJDATA pdataArgs)
|
|
{
|
|
TRACENAME("AMLIEVALNAMESPACEOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIEvalNameSpaceObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs));
|
|
|
|
ASSERT(pns != NULL);
|
|
ASSERT((icArgs == 0) || (pdataArgs != NULL));
|
|
RESETERR();
|
|
CHKGLOBALHEAP();
|
|
CHKDEBUGGERREQ();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_EvalNameSpaceObject(
|
|
pns,pdataResult,icArgs,pdataArgs,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
}
|
|
|
|
|
|
if (pns->ObjData.dwfData & DATAF_NSOBJ_DEFUNC)
|
|
{
|
|
AMLI_WARN(("AMLIEvalNameSpaceObject: pnsObj is no longer valid"));
|
|
rc = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
if (pdataResult != NULL)
|
|
MEMZERO(pdataResult, sizeof(OBJDATA));
|
|
|
|
pns = GetBaseObject(pns);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: EvalNameSpaceObject(%s)\n",
|
|
KeGetCurrentThread(), GetObjectPath(pns));
|
|
}
|
|
#endif
|
|
|
|
rc = SyncEvalObject(pns, pdataResult, icArgs, pdataArgs);
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
}
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_EvalNameSpaceObject(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
EXIT(1, ("AMLIEvalNameSpaceObject=%x\n", rc));
|
|
return rc;
|
|
} //AMLIEvalNameSpaceObject
|
|
|
|
/***EP AMLIAsyncEvalObject - Evaluate an object asynchronously
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIAsyncEvalObject | Evaluate an object asynchronously.
|
|
*
|
|
* @PARM PNSOBJ | pns | Pointer to the object to be evaluated.
|
|
*
|
|
* @PARM POBJDATA | pdataResult | Pointer to the OBJDATA structure which will
|
|
* hold the result of the evaluation (can be NULL if don't care about
|
|
* result).
|
|
*
|
|
* @PARM int | icArgs | Specify the number of arguments pass to the method
|
|
* object for evaluation (only valid if pns points to a method object).
|
|
*
|
|
* @PARM POBJDATA | pdataArgs | Pointer to an array of argument data object
|
|
* (only valid if pns points to a method object).
|
|
*
|
|
* @PARM PFNACB | pfnAsyncCallBack | Pointer to the asynchronous callback
|
|
* function in case the control method is blocked and has to be
|
|
* completed asynchronously (can be NULL if no Callback required).
|
|
*
|
|
* @PARM PVOID | pvContext | Pointer to some context data that the
|
|
* interpreter will pass to the Async callback handler.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*
|
|
* @DEVNOTE The returned object may contain buffer pointer to the actual
|
|
* data in the ACPI name space. Therefore, the caller must be very
|
|
* careful not to overwrite any data in the buffer. Also, the caller
|
|
* is responsible for calling AMLIFreeDataBuffs on the result object
|
|
* after the result object data is no longer needed.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIAsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult,
|
|
int icArgs, POBJDATA pdataArgs,
|
|
PFNACB pfnAsyncCallBack, PVOID pvContext)
|
|
{
|
|
TRACENAME("AMLIASYNCEVALOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIAsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack));
|
|
|
|
ASSERT(pns != NULL);
|
|
ASSERT((icArgs == 0) || (pdataArgs != NULL));
|
|
RESETERR();
|
|
CHKGLOBALHEAP();
|
|
CHKDEBUGGERREQ();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_AsyncEvalObject(
|
|
pns,pdataResult,icArgs,pdataArgs,
|
|
&pfnAsyncCallBack,&pvContext,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pns->ObjData.dwfData & DATAF_NSOBJ_DEFUNC)
|
|
{
|
|
AMLI_WARN(("AMLIAsyncEvalObject: pnsObj is no longer valid"));
|
|
rc = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
if (pdataResult != NULL)
|
|
MEMZERO(pdataResult, sizeof(OBJDATA));
|
|
|
|
pns = GetBaseObject(pns);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: AsyncEvalObject(%s)\n",
|
|
KeGetCurrentThread(), GetObjectPath(pns));
|
|
}
|
|
#endif
|
|
|
|
rc = AsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack, pvContext, TRUE);
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
}
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_AsyncEvalObject(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
EXIT(1, ("AMLIAsyncEvalObject=%x\n", rc));
|
|
return rc;
|
|
} //AMLIAsyncEvalObject
|
|
|
|
/***EP AMLINestAsyncEvalObject - Evaluate an object asynchronously from within
|
|
* the current context
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLINestAsyncEvalObject | Evaluate an object
|
|
* asynchronously from within the current context.
|
|
*
|
|
* @PARM PNSOBJ | pns | Pointer to the object to be evaluated.
|
|
*
|
|
* @PARM POBJDATA | pdataResult | Pointer to the OBJDATA structure which will
|
|
* hold the result of the evaluation (can be NULL if don't care about
|
|
* result).
|
|
*
|
|
* @PARM int | icArgs | Specify the number of arguments pass to the method
|
|
* object for evaluation (only valid if pns points to a method object).
|
|
*
|
|
* @PARM POBJDATA | pdataArgs | Pointer to an array of argument data object
|
|
* (only valid if pns points to a method object).
|
|
*
|
|
* @PARM PFNACB | pfnAsyncCallBack | Pointer to the asynchronous callback
|
|
* function in case the control method is blocked and has to be
|
|
* completed asynchronously (can be NULL if no Callback required).
|
|
*
|
|
* @PARM PVOID | pvContext | Pointer to some context data that the
|
|
* interpreter will pass to the Async callback handler.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*
|
|
* @DEVNOTE The returned object may contain buffer pointer to the actual
|
|
* data in the ACPI name space. Therefore, the caller must be very
|
|
* careful not to overwrite any data in the buffer. Also, the caller
|
|
* is responsible for calling AMLIFreeDataBuffs on the result object
|
|
* after the result object data is no longer needed.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLINestAsyncEvalObject(PNSOBJ pns, POBJDATA pdataResult,
|
|
int icArgs, POBJDATA pdataArgs,
|
|
PFNACB pfnAsyncCallBack,
|
|
PVOID pvContext)
|
|
{
|
|
TRACENAME("AMLINESTASYNCEVALOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
|
|
ENTER(1, ("AMLINestAsyncEvalObject(Obj=%s,pdataResult=%x,icArgs=%d,pdataArgs=%x,pfnAysnc=%x)\n",
|
|
GetObjectPath(pns), pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack));
|
|
|
|
ASSERT(pns != NULL);
|
|
ASSERT((icArgs == 0) || (pdataArgs != NULL));
|
|
RESETERR();
|
|
CHKGLOBALHEAP();
|
|
CHKDEBUGGERREQ();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_NestAsyncEvalObject(
|
|
pns,pdataResult,icArgs,pdataArgs,
|
|
&pfnAsyncCallBack,&pvContext,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (pns->ObjData.dwfData & DATAF_NSOBJ_DEFUNC)
|
|
{
|
|
AMLI_WARN(("AMLINestAsyncEvalObject: pnsObj is no longer valid"));
|
|
rc = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
if (pdataResult != NULL)
|
|
MEMZERO(pdataResult, sizeof(OBJDATA));
|
|
|
|
pns = GetBaseObject(pns);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: AsyncNestEvalObject(%s)\n",
|
|
KeGetCurrentThread(), GetObjectPath(pns));
|
|
}
|
|
#endif
|
|
|
|
rc = NestAsyncEvalObject(pns, pdataResult, icArgs, pdataArgs,
|
|
pfnAsyncCallBack, pvContext, TRUE);
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
}
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_NestAsyncEvalObject(
|
|
&pHData,rc);
|
|
}
|
|
|
|
EXIT(1, ("AMLINestAsyncEvalObject=%x\n", rc));
|
|
return rc;
|
|
} //AMLINestAsyncEvalObject
|
|
|
|
/***EP AMLIEvalPackageElement - Evaluate a package element
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIEvalPackageElement | Evaluate a package element.
|
|
*
|
|
* This function evaluate an element of a given package object.
|
|
* A package is essentially an array of objects. This API provides
|
|
* a way to evaluate individual element object inside a package.
|
|
*
|
|
* @PARM PNSOBJ | pns | Pointer to the package object to be evaluated. If
|
|
* the object is a method, then the method is evaluated first before
|
|
* the resulting package object is evaluated. It is an error if the
|
|
* resulting object is not of package type.
|
|
*
|
|
* @PARM int | iPkgIndex | Package index (0-based).
|
|
*
|
|
* @PARM POBJDATA | pdataResult | Pointer to the OBJDATA structure which will
|
|
* hold the result of the evaluation (can be NULL if don't care about
|
|
* result).
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*
|
|
* @DEVNOTE The returned object may contain buffer pointer to the actual
|
|
* data in the ACPI name space. Therefore, the caller must be very
|
|
* careful not to overwrite any data in the buffer. Also, the caller
|
|
* is responsible for calling AMLIFreeDataBuffs on the result object
|
|
* after the result object data is no longer needed.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIEvalPackageElement(PNSOBJ pns, int iPkgIndex,
|
|
POBJDATA pdataResult)
|
|
{
|
|
TRACENAME("AMLIEVALPACKAGEELEMENT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
OBJDATA data;
|
|
POBJDATA pdata = NULL;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIEvalPackageElement(Obj=%s,Index=%d,pdataResult=%x)\n",
|
|
GetObjectPath(pns), iPkgIndex, pdataResult));
|
|
|
|
ASSERT(pns != NULL);
|
|
ASSERT(pdataResult != NULL);
|
|
RESETERR();
|
|
CHKGLOBALHEAP();
|
|
CHKDEBUGGERREQ();
|
|
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_EvalPackageElement(
|
|
pns,iPkgIndex,pdataResult,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
if (pns->ObjData.dwfData & DATAF_NSOBJ_DEFUNC)
|
|
{
|
|
AMLI_WARN(("AMLIEvalPackageElement: pnsObj is no longer valid"));
|
|
rc = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
else
|
|
{
|
|
MEMZERO(pdataResult, sizeof(OBJDATA));
|
|
MEMZERO(&data, sizeof(data));
|
|
pns = GetBaseObject(pns);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: EvalPackageElement(%s,%d)\n",
|
|
KeGetCurrentThread(), GetObjectPath(pns), iPkgIndex);
|
|
}
|
|
#endif
|
|
|
|
if (pns->ObjData.dwDataType == OBJTYPE_METHOD)
|
|
{
|
|
if ((rc = SyncEvalObject(pns, &data, 0, NULL)) == STATUS_SUCCESS)
|
|
{
|
|
if (data.dwDataType == OBJTYPE_PKGDATA)
|
|
pdata = &data;
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("AMLIEvalPackageElement: result object of the method is not package (ObjType=%s)",
|
|
GetObjectTypeName(data.dwDataType)));
|
|
}
|
|
}
|
|
}
|
|
else if (pns->ObjData.dwDataType == OBJTYPE_PKGDATA)
|
|
{
|
|
pdata = &pns->ObjData;
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("AMLIEvalPackageElement: object is not a method or package (ObjType=%s)",
|
|
GetObjectTypeName(pns->ObjData.dwDataType)));
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
rc = EvalPackageElement((PPACKAGEOBJ)pdata->pbDataBuff, iPkgIndex,
|
|
pdataResult);
|
|
}
|
|
FreeDataBuffs(&data, 1);
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
else
|
|
{
|
|
ASSERT((pdataResult->pbDataBuff == NULL) ||
|
|
!(pdataResult->dwfData & DATAF_BUFF_ALIAS));
|
|
}
|
|
}
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_EvalPackageElement(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
EXIT(1, ("AMLIEvalPackageElement=%x\n", rc));
|
|
return rc;
|
|
} //AMLIEvalPackageElement
|
|
|
|
/***EP AMLIEvalPkgDataElement - Evaluate an element of a package data
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIEvalPkgDataElement | Evaluate a package data element.
|
|
*
|
|
* This function evaluate an element of a given package data object.
|
|
* A package is essentially an array of objects. This API provides
|
|
* a way to evaluate individual element object inside a package.
|
|
*
|
|
* @PARM POBJDATA | pdataPkg | Pointer to the package data object to be
|
|
* evaluated. It is an error if the data object is not of package
|
|
* type.
|
|
*
|
|
* @PARM int | iPkgIndex | Package index (0-based).
|
|
*
|
|
* @PARM POBJDATA | pdataResult | Pointer to the OBJDATA structure which will
|
|
* hold the result of the evaluation (can be NULL if don't care about
|
|
* result).
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*
|
|
* @DEVNOTE The returned object may contain buffer pointer to the actual
|
|
* data in the ACPI name space. Therefore, the caller must be very
|
|
* careful not to overwrite any data in the buffer. Also, the caller
|
|
* is responsible for calling AMLIFreeDataBuffs on the result object
|
|
* after the result object data is no longer needed.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIEvalPkgDataElement(POBJDATA pdataPkg, int iPkgIndex,
|
|
POBJDATA pdataResult)
|
|
{
|
|
TRACENAME("AMLIEVALPKGDATAELEMENT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIEvalPkgDataElement(pdataPkg=%x,Index=%d,pdataResult=%x)\n",
|
|
pdataPkg, iPkgIndex, pdataResult));
|
|
|
|
ASSERT(pdataResult != NULL);
|
|
RESETERR();
|
|
CHKGLOBALHEAP();
|
|
CHKDEBUGGERREQ();
|
|
|
|
MEMZERO(pdataResult, sizeof(OBJDATA));
|
|
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_EvalPkgDataElement(
|
|
pdataPkg,iPkgIndex,pdataResult,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
}
|
|
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
PRINTF(MODNAME ": %p: EvalPkgDataElement(%x,%d)\n",
|
|
KeGetCurrentThread(), pdataPkg, iPkgIndex);
|
|
}
|
|
#endif
|
|
|
|
if (pdataPkg->dwDataType != OBJTYPE_PKGDATA)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("AMLIEvalPkgDataElement: object is not a package (ObjType=%s)",
|
|
GetObjectTypeName(pdataPkg->dwDataType)));
|
|
}
|
|
else
|
|
{
|
|
rc = EvalPackageElement((PPACKAGEOBJ)pdataPkg->pbDataBuff, iPkgIndex,
|
|
pdataResult);
|
|
}
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
else
|
|
{
|
|
ASSERT((pdataResult->pbDataBuff == NULL) ||
|
|
!(pdataResult->dwfData & DATAF_BUFF_ALIAS));
|
|
}
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_EvalPkgDataElement(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
EXIT(1, ("AMLIEvalPkgDataElement=%x\n", rc));
|
|
return rc;
|
|
} //AMLIEvalPkgDataElement
|
|
|
|
/***EP AMLIFreeDataBuffs - Free data buffers of an object array
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC VOID | AMLIFreeDataBuffs | Free data buffers of a data object
|
|
* array.
|
|
*
|
|
* This function is typically called after evaluating an object to
|
|
* free the result object buffers.
|
|
*
|
|
* @PARM POBJDATA | pdata | Pointer to the object array.
|
|
*
|
|
* @PARM int | icData | Specifies the number of objects in the array.
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
VOID AMLIAPI AMLIFreeDataBuffs(POBJDATA pdata, int icData)
|
|
{
|
|
TRACENAME("AMLIFREEDATABUFFS")
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIFreeDataBuffs(pdata=%x,icData=%d)\n", pdata, icData));
|
|
|
|
ASSERT(pdata != NULL);
|
|
ASSERT(icData > 0);
|
|
RESETERR();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
AMLITest_Pre_FreeDataBuffs(
|
|
pdata,icData,&pHData);
|
|
|
|
}
|
|
|
|
FreeDataBuffs(pdata, icData);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
AMLITest_Post_FreeDataBuffs(
|
|
&pHData,STATUS_SUCCESS);
|
|
}
|
|
|
|
EXIT(1, ("AMLIFreeDataBuffs!\n"));
|
|
} //AMLIFreeDataBuffs
|
|
|
|
/***EP AMLIRegEventHandler - Register an event handler
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIRegEventHandler | Register an event handler.
|
|
* handler.
|
|
*
|
|
* This function allows the caller to hook a callback handler for some
|
|
* AMLI events.
|
|
*
|
|
* @PARM ULONG | dwEventType | Event type the handler will handle.
|
|
*
|
|
* @PARM ULONG_PTR | uipEventData | Event specific data the handler will
|
|
* handle.
|
|
*
|
|
* @PARM PFNHND | pfnHandler | Callback handler entry point (can be NULL
|
|
* if deregistering previous handler).
|
|
*
|
|
* @PARM ULONG_PTR | uipParam | Parameter Data (will be passed to the
|
|
* callback handler).
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIRegEventHandler(ULONG dwEventType, ULONG_PTR uipEventData,
|
|
PFNHND pfnHandler, ULONG_PTR uipParam)
|
|
{
|
|
TRACENAME("AMLIREGEVENTHANDLER")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
ENTER(1, ("AMLIRegEventHandler(EventType=%x,EventData=%x,pfnHandler=%x,Param=%x)\n",
|
|
dwEventType, uipEventData, pfnHandler, uipParam));
|
|
RESETERR();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLIHook_Pre_RegEventHandler(
|
|
dwEventType,uipEventData,&pfnHandler,&uipParam,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
|
|
|
|
}
|
|
|
|
switch (dwEventType)
|
|
{
|
|
case EVTYPE_OPCODE:
|
|
rc = RegOpcodeHandler((ULONG)uipEventData, (PFNOH)pfnHandler,
|
|
uipParam, 0);
|
|
break;
|
|
|
|
case EVTYPE_OPCODE_EX:
|
|
rc = RegOpcodeHandler((ULONG)uipEventData, (PFNOH)pfnHandler,
|
|
uipParam, OF_CALLBACK_EX);
|
|
break;
|
|
|
|
case EVTYPE_NOTIFY:
|
|
rc = RegEventHandler(&ghNotify, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_FATAL:
|
|
rc = RegEventHandler(&ghFatal, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_VALIDATE_TABLE:
|
|
rc = RegEventHandler(&ghValidateTable, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_ACQREL_GLOBALLOCK:
|
|
rc = RegEventHandler(&ghGlobalLock, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_RS_COOKACCESS:
|
|
rc = RegRSAccess((ULONG)uipEventData, pfnHandler, uipParam, FALSE);
|
|
break;
|
|
|
|
case EVTYPE_RS_RAWACCESS:
|
|
rc = RegRSAccess((ULONG)uipEventData, pfnHandler, uipParam, TRUE);
|
|
break;
|
|
|
|
case EVTYPE_CREATE:
|
|
rc = RegEventHandler(&ghCreate, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_DESTROYOBJ:
|
|
rc =RegEventHandler(&ghDestroyObj, pfnHandler, uipParam);
|
|
break;
|
|
|
|
#ifdef DEBUGGER
|
|
case EVTYPE_CON_MESSAGE:
|
|
rc = RegEventHandler(&gDebugger.hConMessage, pfnHandler, uipParam);
|
|
break;
|
|
|
|
case EVTYPE_CON_PROMPT:
|
|
rc = RegEventHandler(&gDebugger.hConPrompt, pfnHandler, uipParam);
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
rc = AMLI_LOGERR(AMLIERR_INVALID_EVENTTYPE,
|
|
("AMLIRegEventHandler: invalid event type %x",
|
|
dwEventType));
|
|
}
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLIHook_Post_RegEventHandler(
|
|
&pHData,rc);
|
|
}
|
|
|
|
|
|
EXIT(1, ("AMLIRegEventHandler=%x\n", rc));
|
|
return rc;
|
|
} //AMLIRegEventHandler
|
|
|
|
/***EP AMLIPauseInterpreter
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIPauseInterpreter | Flush the interpreter queue
|
|
* and pause the interpreter so that all subsequent new method
|
|
* execution requests will be queued.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIPauseInterpreter(PFNAA pfnCallback, PVOID Context)
|
|
{
|
|
TRACENAME("AMLIPAUSEINTERPRETER")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
|
|
ENTER(1, ("AMLIPauseInterpreter(Callback=%p,Context=%p)\n",
|
|
pfnCallback, Context));
|
|
RESETERR();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Pre_PauseInterpreter(
|
|
&pfnCallback,&Context,&pHData);
|
|
|
|
if(rc != STATUS_SUCCESS)
|
|
return(rc);
|
|
}
|
|
|
|
|
|
|
|
AcquireMutex(&gReadyQueue.mutCtxtQ);
|
|
if (!(gReadyQueue.dwfCtxtQ & (CQF_PAUSED | CQF_FLUSHING)))
|
|
{
|
|
if (gplistCtxtHead == NULL)
|
|
{
|
|
//
|
|
// There is no pending ctxt.
|
|
//
|
|
gReadyQueue.dwfCtxtQ |= CQF_PAUSED;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// There are pending ctxts, so we go into flushing mode.
|
|
//
|
|
gReadyQueue.dwfCtxtQ |= CQF_FLUSHING;
|
|
gReadyQueue.pfnPauseCallback = pfnCallback;
|
|
gReadyQueue.PauseCBContext = Context;
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_FATAL,
|
|
("AMLIPauseInterpreter: interpreter already entered paused state"));
|
|
}
|
|
ReleaseMutex(&gReadyQueue.mutCtxtQ);
|
|
|
|
LOGSCHEDEVENT('PAUS', (ULONG_PTR)rc, 0, 0);
|
|
|
|
if (rc == AMLISTA_PENDING)
|
|
rc = STATUS_PENDING;
|
|
else if (rc != STATUS_SUCCESS)
|
|
rc = NTERR(rc);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
rc = AMLITest_Post_PauseInterpreter(
|
|
&pHData,rc);
|
|
}
|
|
|
|
EXIT(1, ("AMLIPauseInterpreter=%x\n", rc));
|
|
return rc;
|
|
} //AMLIPauseInterpreter
|
|
|
|
/***EP AMLIResumeInterpreter
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC VOID | AMLIResumeInterpreter | Resume the interpreter from
|
|
* paused state.
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
VOID AMLIAPI AMLIResumeInterpreter(VOID)
|
|
{
|
|
|
|
PAMLIHOOK_DATA pHData = NULL;
|
|
|
|
TRACENAME("AMLIRESUMEINTERPRETER")
|
|
|
|
ENTER(1, ("AMLIResumeInterpreter()\n"));
|
|
RESETERR();
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
AMLITest_Pre_ResumeInterpreter(
|
|
&pHData);
|
|
}
|
|
|
|
AcquireMutex(&gReadyQueue.mutCtxtQ);
|
|
if (gReadyQueue.dwfCtxtQ & (CQF_PAUSED | CQF_FLUSHING))
|
|
{
|
|
gReadyQueue.dwfCtxtQ &= ~(CQF_PAUSED | CQF_FLUSHING);
|
|
gReadyQueue.pfnPauseCallback = NULL;
|
|
gReadyQueue.PauseCBContext = NULL;
|
|
LOGSCHEDEVENT('RSUM', 0, 0, 0);
|
|
if ((gReadyQueue.plistCtxtQ != NULL) &&
|
|
!(gReadyQueue.dwfCtxtQ & CQF_WORKITEM_SCHEDULED))
|
|
{
|
|
OSQueueWorkItem(&gReadyQueue.WorkItem);
|
|
gReadyQueue.dwfCtxtQ |= CQF_WORKITEM_SCHEDULED;
|
|
LOGSCHEDEVENT('RSTQ', 0, 0, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AMLI_WARN(("AMLIResumeInterpreter: not in paused state"));
|
|
}
|
|
ReleaseMutex(&gReadyQueue.mutCtxtQ);
|
|
|
|
if(IsAmliHookEnabled())
|
|
{
|
|
|
|
AMLITest_Post_ResumeInterpreter(
|
|
&pHData,STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
EXIT(1, ("AMLIResumeInterpreter!\n"));
|
|
} //AMLIResumeInterpreter
|
|
|
|
/***EP AMLIReferenceObject - Bump up the reference count of the object
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC VOID | AMLIReferenceObject | Bump up the reference count of the
|
|
* name space object.
|
|
*
|
|
* @PARM PNSOBJ | pnsObj | Points to the name space object.
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
VOID AMLIAPI AMLIReferenceObject(PNSOBJ pnsObj)
|
|
{
|
|
TRACENAME("AMLIREFERENCEOBJECT")
|
|
|
|
ENTER(1, ("AMLIReferenceObject(pnsObj=%x)\n", pnsObj));
|
|
|
|
RESETERR();
|
|
|
|
ASSERT(pnsObj != NULL);
|
|
pnsObj->dwRefCount++;
|
|
EXIT(1, ("AMLIReferenceObj!\n"));
|
|
} //AMLIReferenceObject
|
|
|
|
/***EP AMLIDereferenceObject - Bump down the reference count of the object
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC VOID | AMLIDereferenceObject | Bump down the reference count of the
|
|
* name space object. If it reaches zero and it is in defunc state,
|
|
* deallocate the object.
|
|
*
|
|
* @PARM PNSOBJ | pnsObj | Points to the name space object.
|
|
*
|
|
* @RDESC None.
|
|
*/
|
|
|
|
VOID AMLIAPI AMLIDereferenceObject(PNSOBJ pnsObj)
|
|
{
|
|
TRACENAME("AMLIDEREFERENCEOBJECT")
|
|
|
|
ENTER(1, ("AMLIDereferenceObject(pnsObj=%x)\n", pnsObj));
|
|
|
|
RESETERR();
|
|
|
|
ASSERT(pnsObj != NULL);
|
|
ASSERT(pnsObj->dwRefCount > 0);
|
|
|
|
if (pnsObj->dwRefCount > 0)
|
|
{
|
|
pnsObj->dwRefCount--;
|
|
if ((pnsObj->dwRefCount == 0) && (pnsObj->ObjData.dwfData & DATAF_NSOBJ_DEFUNC))
|
|
{
|
|
ListRemoveEntry(&pnsObj->list, &gplistDefuncNSObjs);
|
|
FREENSOBJ(pnsObj);
|
|
}
|
|
}
|
|
|
|
EXIT(1, ("AMLIDereferenceObj!\n"));
|
|
} //AMLIDereferenceObject
|
|
|
|
/***EP AMLIDestroyFreedObjs - Destroy freed objects during an unload
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIDestroyFreedObjs | Destroy freed objects from a
|
|
* previous unload.
|
|
*
|
|
* @PARM PNSOBJ | pnsObj | The object in the freed list to be destroyed.
|
|
*
|
|
* @RDESC SUCCESS - Returns STATUS_SUCCESS.
|
|
*
|
|
* @RDESC FAILURE - Returns NT status code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIDestroyFreedObjs(PNSOBJ pnsObj)
|
|
{
|
|
TRACENAME("AMLIDESTROYFREEDOBJS")
|
|
|
|
ENTER(1, ("AMLIDestroyFreedObjs(pnsObj=%x)\n",pnsObj));
|
|
|
|
RESETERR();
|
|
|
|
ASSERT(pnsObj != NULL);
|
|
|
|
//
|
|
// Destroy the namespace object
|
|
//
|
|
FreeNameSpaceObjects(pnsObj);
|
|
|
|
EXIT(1, ("AMLIDestroyFreedObjs=%x \n",STATUS_SUCCESS));
|
|
return STATUS_SUCCESS;
|
|
} //AMLIDestroyFreedObjs
|
|
|
|
#ifdef DEBUGGER
|
|
/***EP AMLIGetLastError - Get last error code and message
|
|
*
|
|
* @DOC EXTERNAL
|
|
*
|
|
* @FUNC NTSTATUS | AMLIGetLastError | Get last error code and associated
|
|
* error message.
|
|
*
|
|
* @PARM PSZ * | ppszErrMsg | Point to a variable to hold the error message
|
|
* buffer pointer. If there is no error, the variable is set to NULL.
|
|
*
|
|
* @RDESC Returns the last error code.
|
|
*/
|
|
|
|
NTSTATUS AMLIAPI AMLIGetLastError(PSZ *ppszErrMsg)
|
|
{
|
|
TRACENAME("AMLIGETLASTERROR")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(1, ("AMLIGetLastError(ppszErrMsg=%x)\n", ppszErrMsg));
|
|
|
|
ASSERT(ppszErrMsg != NULL);
|
|
|
|
if ((rc = gDebugger.rcLastError) != STATUS_SUCCESS)
|
|
*ppszErrMsg = gDebugger.szLastError;
|
|
else
|
|
*ppszErrMsg = NULL;
|
|
|
|
EXIT(1, ("AMLIGetLastError=%x (Msg=%s)\n",
|
|
rc, *ppszErrMsg? *ppszErrMsg: "<null>"));
|
|
return rc;
|
|
} //AMLIGetLastError
|
|
#endif //ifdef DEBUGGER
|