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.
2533 lines
81 KiB
2533 lines
81 KiB
/*** object.c - Object access functions
|
|
*
|
|
* Copyright (c) 1996,1997 Microsoft Corporation
|
|
* Author: Michael Tsang (MikeTs)
|
|
* Created 01/27/97
|
|
*
|
|
* MODIFICATION HISTORY
|
|
*/
|
|
|
|
#include "pch.h"
|
|
|
|
#ifdef LOCKABLE_PRAGMA
|
|
#pragma ACPI_LOCKABLE_DATA
|
|
#pragma ACPI_LOCKABLE_CODE
|
|
#endif
|
|
|
|
/***LP ReadObject - Read object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* pdataResult -> result object
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ReadObject(PCTXT pctxt, POBJDATA pdataObj, POBJDATA pdataResult)
|
|
{
|
|
TRACENAME("READOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PACCFIELDUNIT pafu;
|
|
|
|
ENTER(3, ("ReadObject(pctxt=%x,pdataObj=%x,pdataResult=%x)\n",
|
|
pctxt, pdataObj, pdataResult));
|
|
|
|
pdataObj = GetBaseData(pdataObj);
|
|
|
|
switch (pdataObj->dwDataType)
|
|
{
|
|
case OBJTYPE_FIELDUNIT:
|
|
if ((rc = PushFrame(pctxt, SIG_ACCFIELDUNIT, sizeof(ACCFIELDUNIT),
|
|
AccFieldUnit, &pafu)) == STATUS_SUCCESS)
|
|
{
|
|
pafu->pdataObj = pdataObj;
|
|
pafu->FrameHdr.dwfFrame = AFUF_READFIELDUNIT;
|
|
pafu->pdata = pdataResult;
|
|
}
|
|
break;
|
|
|
|
case OBJTYPE_BUFFFIELD:
|
|
rc = ReadField(pctxt, pdataObj,
|
|
&((PBUFFFIELDOBJ)pdataObj->pbDataBuff)->FieldDesc,
|
|
pdataResult);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(pdataResult->dwDataType == OBJTYPE_UNKNOWN);
|
|
CopyObjData(pdataResult, pdataObj);
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
PRINTF("=");
|
|
PrintObject(pdataResult);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
EXIT(3, ("ReadObject=%x (Type=%s,Value=%x,Buff=%x)\n",
|
|
rc, GetObjectTypeName(pdataResult->dwDataType),
|
|
pdataResult->uipDataValue, pdataResult->pbDataBuff));
|
|
return rc;
|
|
} //ReadObject
|
|
|
|
/***LP WriteObject - Write object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* pdataSrc -> source data
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteObject(PCTXT pctxt, POBJDATA pdataObj, POBJDATA pdataSrc)
|
|
{
|
|
TRACENAME("WRITEOBJECT")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PACCFIELDUNIT pafu;
|
|
|
|
ENTER(3, ("WriteObject(pctxt=%x,pdataObj=%x,pdataSrc=%x)\n",
|
|
pctxt, pdataObj, pdataSrc));
|
|
|
|
pdataObj = GetBaseData(pdataObj);
|
|
|
|
switch (pdataObj->dwDataType)
|
|
{
|
|
case OBJTYPE_FIELDUNIT:
|
|
if ((rc = PushFrame(pctxt, SIG_ACCFIELDUNIT, sizeof(ACCFIELDUNIT),
|
|
AccFieldUnit, &pafu)) == STATUS_SUCCESS)
|
|
{
|
|
pafu->pdataObj = pdataObj;
|
|
pafu->pdata = pdataSrc;
|
|
}
|
|
break;
|
|
|
|
case OBJTYPE_BUFFFIELD:
|
|
rc = WriteField(pctxt, pdataObj,
|
|
&((PBUFFFIELDOBJ)pdataObj->pbDataBuff)->FieldDesc,
|
|
pdataSrc);
|
|
break;
|
|
|
|
case OBJTYPE_DEBUG:
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & DBGF_VERBOSE_ON)
|
|
{
|
|
DumpObject(pdataSrc, NULL, 0);
|
|
}
|
|
#endif
|
|
rc = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case OBJTYPE_UNKNOWN:
|
|
//
|
|
// Since the target object could be a global NameSpace object,
|
|
// allocate memory from the global heap just to be safe.
|
|
//
|
|
rc = DupObjData(gpheapGlobal, pdataObj, pdataSrc);
|
|
break;
|
|
|
|
case OBJTYPE_INTDATA:
|
|
rc = CopyObjBuffer((PUCHAR)&pdataObj->uipDataValue, sizeof(ULONG),
|
|
pdataSrc);
|
|
break;
|
|
|
|
case OBJTYPE_STRDATA:
|
|
rc = CopyObjBuffer(pdataObj->pbDataBuff, pdataObj->dwDataLen - 1,
|
|
pdataSrc);
|
|
break;
|
|
|
|
case OBJTYPE_BUFFDATA:
|
|
rc = CopyObjBuffer(pdataObj->pbDataBuff, pdataObj->dwDataLen,
|
|
pdataSrc);
|
|
break;
|
|
|
|
default:
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("WriteObject: unexpected target object type (type=%s)",
|
|
GetObjectTypeName(pdataObj->dwDataType)));
|
|
}
|
|
|
|
EXIT(3, ("WriteObject=%x (ObjType=%s,DataType=%x,Value=%x,Buff=%x)\n",
|
|
rc, GetObjectTypeName(pdataObj->dwDataType), pdataSrc->dwDataType,
|
|
pdataSrc->uipDataValue, pdataSrc->pbDataBuff));
|
|
return rc;
|
|
} //WriteObject
|
|
|
|
/***LP AccFieldUnit - Access a FieldUnit object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pafu -> ACCFIELDUNIT
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL AccFieldUnit(PCTXT pctxt, PACCFIELDUNIT pafu, NTSTATUS rc)
|
|
{
|
|
TRACENAME("ACCFIELDUNIT")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(pafu->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 3;
|
|
PFIELDUNITOBJ pfu;
|
|
POBJDATA pdataParent, pdataBank;
|
|
PBANKFIELDOBJ pbf;
|
|
|
|
ENTER(3, ("AccFieldUnit(Stage=%d,pctxt=%x,pafu=%x,rc=%x)\n",
|
|
dwStage, pctxt, pafu, rc));
|
|
|
|
ASSERT(pafu->FrameHdr.dwSig == SIG_ACCFIELDUNIT);
|
|
|
|
pfu = (PFIELDUNITOBJ)pafu->pdataObj->pbDataBuff;
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
//
|
|
// Stage 0: Set bank if necessary.
|
|
//
|
|
pafu->FrameHdr.dwfFrame++;
|
|
pdataParent = &pfu->pnsFieldParent->ObjData;
|
|
if (pdataParent->dwDataType == OBJTYPE_BANKFIELD)
|
|
{
|
|
pbf = (PBANKFIELDOBJ)pdataParent->pbDataBuff;
|
|
pdataBank = &pbf->pnsBank->ObjData;
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj, pdataBank,
|
|
&((PFIELDUNITOBJ)pdataBank->pbDataBuff)->FieldDesc,
|
|
(PUCHAR)&pbf->dwBankValue,
|
|
sizeof(ULONG));
|
|
break;
|
|
}
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: Acquire GlobalLock if necessary.
|
|
//
|
|
pafu->FrameHdr.dwfFrame++;
|
|
if (NeedGlobalLock(pfu))
|
|
{
|
|
if ((rc = AcquireGL(pctxt)) != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
case 2:
|
|
//
|
|
// Stage 2: Read/Write the field.
|
|
//
|
|
pafu->FrameHdr.dwfFrame++;
|
|
//
|
|
// If we come here and we need global lock, we must have got it.
|
|
//
|
|
if (pfu->FieldDesc.dwFieldFlags & FDF_NEEDLOCK)
|
|
{
|
|
pafu->FrameHdr.dwfFrame |= AFUF_HAVE_GLOBALLOCK;
|
|
}
|
|
|
|
if (pafu->FrameHdr.dwfFrame & AFUF_READFIELDUNIT)
|
|
{
|
|
rc = ReadField(pctxt, pafu->pdataObj, &pfu->FieldDesc,
|
|
pafu->pdata);
|
|
}
|
|
else
|
|
{
|
|
rc = WriteField(pctxt, pafu->pdataObj, &pfu->FieldDesc,
|
|
pafu->pdata);
|
|
}
|
|
|
|
if ((rc == AMLISTA_PENDING) ||
|
|
(&pafu->FrameHdr != (PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd))
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
//
|
|
// Stage 3: Clean up.
|
|
//
|
|
if (pafu->FrameHdr.dwfFrame & AFUF_HAVE_GLOBALLOCK)
|
|
{
|
|
ReleaseGL(pctxt);
|
|
}
|
|
|
|
#ifdef DEBUGGER
|
|
if (gDebugger.dwfDebugger & (DBGF_AMLTRACE_ON | DBGF_STEP_MODES))
|
|
{
|
|
if (pafu->FrameHdr.dwfFrame & AFUF_READFIELDUNIT)
|
|
{
|
|
PRINTF("=");
|
|
PrintObject(pafu->pdata);
|
|
}
|
|
}
|
|
#endif
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("AccFieldUnit=%x\n", rc));
|
|
return rc;
|
|
} //AccFieldUnit
|
|
|
|
/***LP ReadField - Read data from a field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* pfd -> field descriptor
|
|
* pdataResult -> result object
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ReadField(PCTXT pctxt, POBJDATA pdataObj, PFIELDDESC pfd,
|
|
POBJDATA pdataResult)
|
|
{
|
|
TRACENAME("READFIELD")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(3, ("ReadField(pctxt=%x,pdataObj=%x,FieldDesc=%x,pdataResult=%x)\n",
|
|
pctxt, pdataObj, pfd, pdataResult));
|
|
|
|
if ((pfd->dwFieldFlags & ACCTYPE_MASK) <= ACCTYPE_DWORD)
|
|
{
|
|
PUCHAR pb;
|
|
ULONG dwcb;
|
|
|
|
switch (pdataResult->dwDataType)
|
|
{
|
|
case OBJTYPE_UNKNOWN:
|
|
if (!(pfd->dwFieldFlags & FDF_BUFFER_TYPE) &&
|
|
(pfd->dwNumBits <= sizeof(ULONG)*8))
|
|
{
|
|
pdataResult->dwDataType = OBJTYPE_INTDATA;
|
|
pb = (PUCHAR)&pdataResult->uipDataValue;
|
|
dwcb = sizeof(ULONG);
|
|
}
|
|
else
|
|
{
|
|
pdataResult->dwDataType = OBJTYPE_BUFFDATA;
|
|
pdataResult->dwDataLen = (pfd->dwNumBits + 7)/8;
|
|
if ((pdataResult->pbDataBuff =
|
|
NEWBDOBJ(gpheapGlobal, pdataResult->dwDataLen))
|
|
== NULL)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("ReadField: failed to allocate target buffer (size=%d)",
|
|
pdataResult->dwDataLen));
|
|
pb = NULL;
|
|
dwcb = 0;
|
|
}
|
|
else
|
|
{
|
|
MEMZERO(pdataResult->pbDataBuff,
|
|
pdataResult->dwDataLen);
|
|
pb = pdataResult->pbDataBuff;
|
|
dwcb = pdataResult->dwDataLen;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OBJTYPE_INTDATA:
|
|
pb = (PUCHAR)&pdataResult->uipDataValue;
|
|
dwcb = sizeof(ULONG);
|
|
break;
|
|
|
|
case OBJTYPE_STRDATA:
|
|
pb = pdataResult->pbDataBuff;
|
|
dwcb = pdataResult->dwDataLen - 1;
|
|
break;
|
|
|
|
case OBJTYPE_BUFFDATA:
|
|
pb = pdataResult->pbDataBuff;
|
|
dwcb = pdataResult->dwDataLen;
|
|
break;
|
|
|
|
default:
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("ReadField: invalid target data type (type=%s)",
|
|
GetObjectTypeName(pdataResult->dwDataType)));
|
|
pb = NULL;
|
|
dwcb = 0;
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
rc = PushAccFieldObj(pctxt, ReadFieldObj, pdataObj, pfd, pb, dwcb);
|
|
}
|
|
else if (pdataObj->dwDataType == OBJTYPE_FIELDUNIT)
|
|
{
|
|
//
|
|
// This is an access type we don't know how to handle, so try to find
|
|
// a raw access handler to handle it.
|
|
//
|
|
rc = RawFieldAccess(pctxt, RSACCESS_READ, pdataObj, pdataResult);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INVALID_ACCSIZE,
|
|
("ReadField: invalid access size for buffer field (FieldFlags=%x)",
|
|
pfd->dwFieldFlags));
|
|
}
|
|
|
|
EXIT(3, ("ReadField=%x\n", rc));
|
|
return rc;
|
|
} //ReadField
|
|
|
|
/***LP WriteField - Write data to a field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* pfd -> field descriptor
|
|
* pdataSrc -> source data
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteField(PCTXT pctxt, POBJDATA pdataObj, PFIELDDESC pfd,
|
|
POBJDATA pdataSrc)
|
|
{
|
|
TRACENAME("WRITEFIELD")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
ULONG dwDataInc = (pfd->dwNumBits + 7)/8;
|
|
PUCHAR pbBuff;
|
|
ULONG dwBuffSize;
|
|
|
|
ENTER(3, ("WriteField(pctxt=%x,pdataObj=%x,FieldDesc=%x,pdataSrc=%x)\n",
|
|
pctxt, pdataObj, pfd, pdataSrc));
|
|
|
|
if ((pfd->dwFieldFlags & ACCTYPE_MASK) <= ACCTYPE_DWORD)
|
|
{
|
|
PWRFIELDLOOP pwfl;
|
|
|
|
switch (pdataSrc->dwDataType)
|
|
{
|
|
case OBJTYPE_INTDATA:
|
|
dwBuffSize = MIN(sizeof(ULONG), dwDataInc);
|
|
pbBuff = (PUCHAR)&pdataSrc->uipDataValue;
|
|
break;
|
|
|
|
case OBJTYPE_STRDATA:
|
|
dwBuffSize = pdataSrc->dwDataLen - 1;
|
|
pbBuff = pdataSrc->pbDataBuff;
|
|
break;
|
|
|
|
case OBJTYPE_BUFFDATA:
|
|
dwBuffSize = pdataSrc->dwDataLen;
|
|
pbBuff = pdataSrc->pbDataBuff;
|
|
break;
|
|
|
|
default:
|
|
rc = AMLI_LOGERR(AMLIERR_UNEXPECTED_OBJTYPE,
|
|
("WriteField: invalid source data type (type=%s)\n",
|
|
GetObjectTypeName(pdataSrc->dwDataType)));
|
|
dwBuffSize = 0;
|
|
pbBuff = NULL;
|
|
}
|
|
|
|
if ((rc == STATUS_SUCCESS) &&
|
|
((rc = PushFrame(pctxt, SIG_WRFIELDLOOP, sizeof(WRFIELDLOOP),
|
|
WriteFieldLoop, &pwfl)) == STATUS_SUCCESS))
|
|
{
|
|
pwfl->pdataObj = pdataObj;
|
|
pwfl->pfd = pfd;
|
|
pwfl->pbBuff = pbBuff;
|
|
pwfl->dwBuffSize = dwBuffSize;
|
|
pwfl->dwDataInc = dwDataInc;
|
|
}
|
|
}
|
|
else if (pdataObj->dwDataType == OBJTYPE_FIELDUNIT)
|
|
{
|
|
//
|
|
// This is an access type we don't know how to handle, so try to find
|
|
// a raw access handler to handle it.
|
|
//
|
|
rc = RawFieldAccess(pctxt, RSACCESS_WRITE, pdataObj, pdataSrc);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INVALID_ACCSIZE,
|
|
("WriteField: invalid access size for buffer field (FieldFlags=%x)",
|
|
pfd->dwFieldFlags));
|
|
}
|
|
|
|
EXIT(3, ("WriteField=%x\n", rc));
|
|
return rc;
|
|
} //WriteField
|
|
|
|
/***LP WriteFieldLoop - executing the loop for the WriteField operation
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pwfl -> WRFIELDLOOP
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteFieldLoop(PCTXT pctxt, PWRFIELDLOOP pwfl, NTSTATUS rc)
|
|
{
|
|
TRACENAME("WRITEFIELDLOOP")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(pwfl->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 1;
|
|
ULONG dwXactionSize;
|
|
|
|
ENTER(3, ("WriteFieldLoop(Stage=%d,pctxt=%x,pwfl=%x,rc=%x)\n",
|
|
dwStage, pctxt, pwfl, rc));
|
|
|
|
ASSERT(pwfl->FrameHdr.dwSig == SIG_WRFIELDLOOP);
|
|
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
//
|
|
// Stage 0: Do loop.
|
|
//
|
|
if (pwfl->dwBuffSize > 0)
|
|
{
|
|
dwXactionSize = MIN(pwfl->dwDataInc, pwfl->dwBuffSize);
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj, pwfl->pdataObj,
|
|
pwfl->pfd, pwfl->pbBuff, dwXactionSize);
|
|
pwfl->dwBuffSize -= dwXactionSize;
|
|
pwfl->pbBuff += dwXactionSize;
|
|
break;
|
|
}
|
|
|
|
pwfl->FrameHdr.dwfFrame++;
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: Clean up.
|
|
//
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("WriteFieldLoop=%x\n", rc));
|
|
return rc;
|
|
} //WriteFieldLoop
|
|
|
|
/***LP PushAccFieldObj - Push a AccFieldObj frame on the stack
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pfnAcc -> access function
|
|
* pdataObj -> object
|
|
* pfd -> field descriptor
|
|
* pb -> data buffer
|
|
* dwcb - buffer size
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL PushAccFieldObj(PCTXT pctxt, PFNPARSE pfnAcc, POBJDATA pdataObj,
|
|
PFIELDDESC pfd, PUCHAR pb, ULONG dwcb)
|
|
{
|
|
TRACENAME("PUSHACCFIELDOBJ")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PACCFIELDOBJ pafo;
|
|
|
|
ENTER(3, ("PushAccFieldObj(pctxt=%x,pfnAcc=%x,pdataObj=%x,FieldDesc=%x,pb=%x,Size=%d)\n",
|
|
pctxt, pfnAcc, pdataObj, pfd, pb, dwcb));
|
|
|
|
if ((rc = PushFrame(pctxt, SIG_ACCFIELDOBJ, sizeof(ACCFIELDOBJ), pfnAcc,
|
|
&pafo)) == STATUS_SUCCESS)
|
|
{
|
|
pafo->pdataObj = pdataObj;
|
|
pafo->pbBuff = pb;
|
|
pafo->pbBuffEnd = pb + dwcb;
|
|
pafo->dwAccSize = ACCSIZE(pfd->dwFieldFlags);
|
|
ASSERT((pafo->dwAccSize == sizeof(UCHAR)) ||
|
|
(pafo->dwAccSize == sizeof(USHORT)) ||
|
|
(pafo->dwAccSize == sizeof(ULONG)));
|
|
pafo->dwcAccesses = (pfd->dwStartBitPos + pfd->dwNumBits +
|
|
pafo->dwAccSize*8 - 1)/(pafo->dwAccSize*8);
|
|
pafo->dwDataMask = SHIFTLEFT(1L, pafo->dwAccSize*8) - 1;
|
|
pafo->iLBits = pafo->dwAccSize*8 - pfd->dwStartBitPos;
|
|
pafo->iRBits = (int)pfd->dwStartBitPos;
|
|
MEMCPY(&pafo->fd, pfd, sizeof(FIELDDESC));
|
|
}
|
|
|
|
EXIT(3, ("PushAccFieldObj=%x\n", rc));
|
|
return rc;
|
|
} //PushAccFieldObj
|
|
|
|
/***LP ReadFieldObj - Read data from a field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pafo -> ACCFIELDOBJ
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ReadFieldObj(PCTXT pctxt, PACCFIELDOBJ pafo, NTSTATUS rc)
|
|
{
|
|
TRACENAME("READFIELDOBJ")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(pafo->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 3;
|
|
POBJDATA pdataParent;
|
|
|
|
ENTER(3, ("ReadFieldObj(Stage=%d,pctxt=%x,pafo=%x,rc=%x)\n",
|
|
dwStage, pctxt, pafo, rc));
|
|
|
|
ASSERT(pafo->FrameHdr.dwSig == SIG_ACCFIELDOBJ);
|
|
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
Stage0:
|
|
//
|
|
// Stage 0: Set Index if necessary.
|
|
//
|
|
if (pafo->iAccess >= (int)pafo->dwcAccesses)
|
|
{
|
|
//
|
|
// No access necessary, go straight to clean up.
|
|
//
|
|
pafo->FrameHdr.dwfFrame += 3;
|
|
goto Stage3;
|
|
}
|
|
else
|
|
{
|
|
pafo->FrameHdr.dwfFrame++;
|
|
if (pafo->pdataObj->dwDataType == OBJTYPE_FIELDUNIT)
|
|
{
|
|
pdataParent =
|
|
&((PFIELDUNITOBJ)pafo->pdataObj->pbDataBuff)->pnsFieldParent->ObjData;
|
|
|
|
if (pdataParent->dwDataType == OBJTYPE_INDEXFIELD)
|
|
{
|
|
PINDEXFIELDOBJ pif = (PINDEXFIELDOBJ)pdataParent->pbDataBuff;
|
|
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj,
|
|
&pif->pnsIndex->ObjData,
|
|
&((PFIELDUNITOBJ)pif->pnsIndex->ObjData.pbDataBuff)->FieldDesc,
|
|
(PUCHAR)&pafo->fd.dwByteOffset,
|
|
sizeof(ULONG));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: Access field data.
|
|
//
|
|
pafo->FrameHdr.dwfFrame++;
|
|
rc = AccessFieldData(pctxt, pafo->pdataObj, &pafo->fd,
|
|
&pafo->dwData, TRUE);
|
|
|
|
if ((rc != STATUS_SUCCESS) ||
|
|
(&pafo->FrameHdr != (PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd))
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
//
|
|
// Stage 2: Massage data into the right bit position.
|
|
//
|
|
if (pafo->iAccess > 0)
|
|
{
|
|
WriteSystemMem((ULONG_PTR)pafo->pbBuff, pafo->dwAccSize,
|
|
SHIFTLEFT(pafo->dwData, pafo->iLBits) &
|
|
pafo->dwDataMask,
|
|
(SHIFTLEFT(1L, pafo->iRBits) - 1) << pafo->iLBits);
|
|
|
|
pafo->pbBuff += pafo->dwAccSize;
|
|
if (pafo->pbBuff >= pafo->pbBuffEnd)
|
|
{
|
|
//
|
|
// We ran out of buffer, so we are done (go to clean up).
|
|
//
|
|
pafo->FrameHdr.dwfFrame++;
|
|
goto Stage3;
|
|
}
|
|
}
|
|
|
|
pafo->dwData >>= pafo->iRBits;
|
|
if ((int)pafo->fd.dwNumBits < pafo->iLBits)
|
|
{
|
|
pafo->dwData &= SHIFTLEFT(1L, pafo->fd.dwNumBits) - 1;
|
|
}
|
|
|
|
WriteSystemMem((ULONG_PTR)pafo->pbBuff, pafo->dwAccSize,
|
|
pafo->dwData,
|
|
(SHIFTLEFT(1L, pafo->iLBits) - 1) >> pafo->iRBits);
|
|
|
|
pafo->fd.dwByteOffset += pafo->dwAccSize;
|
|
pafo->fd.dwNumBits -= pafo->dwAccSize*8 - pafo->fd.dwStartBitPos;
|
|
pafo->fd.dwStartBitPos = 0;
|
|
pafo->iAccess++;
|
|
if (pafo->iAccess < (int)pafo->dwcAccesses)
|
|
{
|
|
//
|
|
// Still more accesses to go, back to stage 0.
|
|
//
|
|
pafo->FrameHdr.dwfFrame -= 2;
|
|
goto Stage0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No more accesses, continue to clean up.
|
|
//
|
|
pafo->FrameHdr.dwfFrame++;
|
|
}
|
|
|
|
case 3:
|
|
Stage3:
|
|
//
|
|
// Stage 3: Clean up.
|
|
//
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("ReadFieldObj=%x\n", rc));
|
|
return rc;
|
|
} //ReadFieldObj
|
|
|
|
/***LP WriteFieldObj - Write data to a field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pafo -> ACCFIELDOBJ
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteFieldObj(PCTXT pctxt, PACCFIELDOBJ pafo, NTSTATUS rc)
|
|
{
|
|
TRACENAME("WRITEFIELDOBJ")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(pafo->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 3;
|
|
POBJDATA pdataParent;
|
|
ULONG dwData1;
|
|
|
|
ENTER(3, ("WriteFieldObj(Stage=%d,pctxt=%x,pafo=%x,rc=%x)\n",
|
|
dwStage, pctxt, pafo, rc));
|
|
|
|
ASSERT(pafo->FrameHdr.dwSig == SIG_ACCFIELDOBJ);
|
|
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
Stage0:
|
|
//
|
|
// Stage 0: Set Index if necessary.
|
|
//
|
|
if (pafo->iAccess >= (int)pafo->dwcAccesses)
|
|
{
|
|
//
|
|
// No access necessary, go straight to clean up.
|
|
//
|
|
pafo->FrameHdr.dwfFrame += 3;
|
|
goto Stage3;
|
|
}
|
|
else
|
|
{
|
|
pafo->FrameHdr.dwfFrame++;
|
|
if (pafo->pdataObj->dwDataType == OBJTYPE_FIELDUNIT)
|
|
{
|
|
pdataParent =
|
|
&((PFIELDUNITOBJ)pafo->pdataObj->pbDataBuff)->pnsFieldParent->ObjData;
|
|
|
|
if (pdataParent->dwDataType == OBJTYPE_INDEXFIELD)
|
|
{
|
|
PINDEXFIELDOBJ pif = (PINDEXFIELDOBJ)pdataParent->pbDataBuff;
|
|
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj,
|
|
&pif->pnsIndex->ObjData,
|
|
&((PFIELDUNITOBJ)pif->pnsIndex->ObjData.pbDataBuff)->FieldDesc,
|
|
(PUCHAR)&pafo->fd.dwByteOffset,
|
|
sizeof(ULONG));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: Massage data into the right bit position and write it.
|
|
//
|
|
pafo->FrameHdr.dwfFrame++;
|
|
dwData1 = ReadSystemMem((ULONG_PTR)pafo->pbBuff, pafo->dwAccSize,
|
|
pafo->dwDataMask);
|
|
if (pafo->iAccess > 0)
|
|
{
|
|
pafo->dwData = dwData1 >> pafo->iLBits;
|
|
pafo->pbBuff += pafo->dwAccSize;
|
|
if (pafo->pbBuff >= pafo->pbBuffEnd)
|
|
{
|
|
dwData1 = 0;
|
|
}
|
|
else
|
|
{
|
|
dwData1 = ReadSystemMem((ULONG_PTR)pafo->pbBuff,
|
|
pafo->dwAccSize, pafo->dwDataMask);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pafo->dwData = 0;
|
|
}
|
|
|
|
pafo->dwData |= (dwData1 << pafo->iRBits) & pafo->dwDataMask;
|
|
|
|
rc = AccessFieldData(pctxt, pafo->pdataObj, &pafo->fd,
|
|
&pafo->dwData, FALSE);
|
|
|
|
if ((rc == AMLISTA_PENDING) ||
|
|
(&pafo->FrameHdr != (PFRAMEHDR)pctxt->LocalHeap.pbHeapEnd))
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 2:
|
|
//
|
|
// Stage 2: Check for more iterations.
|
|
//
|
|
pafo->fd.dwByteOffset += pafo->dwAccSize;
|
|
pafo->fd.dwNumBits -= pafo->dwAccSize*8 - pafo->fd.dwStartBitPos;
|
|
pafo->fd.dwStartBitPos = 0;
|
|
pafo->iAccess++;
|
|
if (pafo->iAccess < (int)pafo->dwcAccesses)
|
|
{
|
|
//
|
|
// Still more accesses to go, back to stage 0.
|
|
//
|
|
pafo->FrameHdr.dwfFrame -= 2;
|
|
goto Stage0;
|
|
}
|
|
else
|
|
{
|
|
pafo->FrameHdr.dwfFrame++;
|
|
}
|
|
|
|
case 3:
|
|
Stage3:
|
|
//
|
|
// Stage 3: Clean up.
|
|
//
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("WriteFieldObj=%x\n", rc));
|
|
return rc;
|
|
} //WriteFieldObj
|
|
|
|
/***LP RawFieldAccess - Find and call the RawAccess handler for the RegionSpace
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* dwAccType - read/write
|
|
* pdataObj -> field unit object
|
|
* pdataResult -> result object
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL RawFieldAccess(PCTXT pctxt, ULONG dwAccType, POBJDATA pdataObj,
|
|
POBJDATA pdataResult)
|
|
{
|
|
TRACENAME("RAWFIELDACCESS")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
POBJDATA pdataParent;
|
|
POPREGIONOBJ pop;
|
|
PRSACCESS prsa;
|
|
PFIELDUNITOBJ pfuFieldUnit;
|
|
|
|
ENTER(3, ("RawFieldAccess(pctxt=%x,AccType=%x,pdataObj=%x,pdata=%x)\n",
|
|
pctxt, dwAccType, pdataObj, pdataResult));
|
|
|
|
pdataParent =
|
|
&((PFIELDUNITOBJ)pdataObj->pbDataBuff)->pnsFieldParent->ObjData;
|
|
|
|
switch (pdataParent->dwDataType)
|
|
{
|
|
case OBJTYPE_FIELD:
|
|
pop = (POPREGIONOBJ)
|
|
((PFIELDOBJ)pdataParent->pbDataBuff)->pnsBase->ObjData.pbDataBuff;
|
|
break;
|
|
|
|
default:
|
|
rc = AMLI_LOGERR(AMLIERR_ASSERT_FAILED,
|
|
("RawFieldAccess: invalid field parent type (type=%s)",
|
|
pdataParent->dwDataType));
|
|
pop = NULL;
|
|
}
|
|
|
|
if (rc == STATUS_SUCCESS)
|
|
{
|
|
if (((prsa = FindRSAccess(pop->bRegionSpace)) != NULL) &&
|
|
(prsa->pfnRawAccess != NULL))
|
|
{
|
|
#ifdef DEBUGGER
|
|
ULONG dwOldFlags = gDebugger.dwfDebugger;
|
|
|
|
if (dwOldFlags & DBGF_AMLTRACE_ON)
|
|
{
|
|
gDebugger.dwfDebugger &= ~DBGF_AMLTRACE_ON;
|
|
}
|
|
#endif
|
|
ASSERT(!(pctxt->dwfCtxt & CTXTF_READY));
|
|
|
|
if ((pfuFieldUnit = NEWFUOBJ(pctxt->pheapCurrent, sizeof (FIELDUNITOBJ))) == NULL) {
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("RawFieldAccess: failed to allocate Field unit"));
|
|
} else {
|
|
RtlCopyMemory (pfuFieldUnit, (PFIELDUNITOBJ)pdataObj->pbDataBuff, sizeof (FIELDUNITOBJ));
|
|
pfuFieldUnit->FieldDesc.dwByteOffset += (ULONG) pop->uipOffset;
|
|
rc = prsa->pfnRawAccess(dwAccType,
|
|
pfuFieldUnit,
|
|
pdataResult, prsa->uipRawParam,
|
|
RestartCtxtCallback, &pctxt->CtxtData);
|
|
if (rc == STATUS_BUFFER_TOO_SMALL) {
|
|
//
|
|
// When opregion handler returns STATUS_BUFFER_TOO_SMALL, this indicates that it
|
|
// needs to have a buffer alloocated for it. The buffer size is returned in
|
|
// pdataResult->dwDataValue
|
|
//
|
|
|
|
ASSERT(pdataResult->dwDataType == OBJTYPE_INTDATA);
|
|
if ((pdataResult->pbDataBuff = NEWBDOBJ(gpheapGlobal, pdataResult->dwDataValue)) == NULL) {
|
|
rc = AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("Buffer: failed to allocate data buffer (size=%d)",
|
|
pdataResult->dwDataValue));
|
|
} else {
|
|
pdataResult->dwDataLen = pdataResult->dwDataValue;
|
|
pdataResult->dwDataType = OBJTYPE_BUFFDATA;
|
|
rc = prsa->pfnRawAccess(dwAccType,
|
|
pfuFieldUnit,
|
|
pdataResult, prsa->uipRawParam,
|
|
RestartCtxtCallback, &pctxt->CtxtData);
|
|
}
|
|
}
|
|
}
|
|
#ifdef DEBUGGER
|
|
gDebugger.dwfDebugger = dwOldFlags;
|
|
#endif
|
|
|
|
if (rc == STATUS_PENDING)
|
|
{
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
else if (rc != STATUS_SUCCESS)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_RS_ACCESS,
|
|
("RawFieldAccess: RegionSpace %x handler returned error %x",
|
|
pop->bRegionSpace, rc));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INVALID_REGIONSPACE,
|
|
("RawFieldAccess: no handler for RegionSpace %x",
|
|
pop->bRegionSpace));
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("RawFieldAccess=%x\n", rc));
|
|
return rc;
|
|
} //RawFieldAccess
|
|
|
|
/***LP AccessFieldData - Read/Write field object data
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* pfd -> field descriptor
|
|
* pdwData -> to hold data read or data to be written
|
|
* fRead - TRUE if read access
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL AccessFieldData(PCTXT pctxt, POBJDATA pdataObj, PFIELDDESC pfd,
|
|
PULONG pdwData, BOOLEAN fRead)
|
|
{
|
|
TRACENAME("ACCESSFIELDDATA")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
|
|
ENTER(3, ("AccessFieldData(pctxt=%x,pdataObj=%x,FieldDesc=%x,pdwData=%x,fRead=%x)\n",
|
|
pctxt, pdataObj, pfd, pdwData, fRead));
|
|
|
|
if (pdataObj->dwDataType == OBJTYPE_BUFFFIELD)
|
|
{
|
|
if (fRead)
|
|
{
|
|
rc = ReadBuffField((PBUFFFIELDOBJ)pdataObj->pbDataBuff, pfd,
|
|
pdwData);
|
|
}
|
|
else
|
|
{
|
|
rc = WriteBuffField((PBUFFFIELDOBJ)pdataObj->pbDataBuff, pfd,
|
|
*pdwData);
|
|
}
|
|
}
|
|
else //must be OBJTYPE_FIELDUNIT
|
|
{
|
|
POBJDATA pdataParent;
|
|
PNSOBJ pnsBase = NULL;
|
|
|
|
pdataParent = &((PFIELDUNITOBJ)pdataObj->pbDataBuff)->pnsFieldParent->ObjData;
|
|
if (pdataParent->dwDataType == OBJTYPE_INDEXFIELD)
|
|
{
|
|
PINDEXFIELDOBJ pif = (PINDEXFIELDOBJ)pdataParent->pbDataBuff;
|
|
|
|
if (fRead)
|
|
{
|
|
rc = PushAccFieldObj(pctxt, ReadFieldObj,
|
|
&pif->pnsData->ObjData,
|
|
&((PFIELDUNITOBJ)pif->pnsData->ObjData.pbDataBuff)->FieldDesc,
|
|
(PUCHAR)pdwData, sizeof(ULONG));
|
|
}
|
|
else
|
|
{
|
|
ULONG dwPreserveMask, dwAccMask;
|
|
|
|
dwPreserveMask = ~((SHIFTLEFT(1L, pfd->dwNumBits) - 1) <<
|
|
pfd->dwStartBitPos);
|
|
dwAccMask = SHIFTLEFT(1L, ACCSIZE(pfd->dwFieldFlags)*8) - 1;
|
|
if (((pfd->dwFieldFlags & UPDATERULE_MASK) ==
|
|
UPDATERULE_PRESERVE) &&
|
|
((dwPreserveMask & dwAccMask) != 0))
|
|
{
|
|
rc = PushPreserveWriteObj(pctxt, &pif->pnsData->ObjData,
|
|
*pdwData, dwPreserveMask);
|
|
}
|
|
else
|
|
{
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj,
|
|
&pif->pnsData->ObjData,
|
|
&((PFIELDUNITOBJ)pif->pnsData->ObjData.pbDataBuff)->FieldDesc,
|
|
(PUCHAR)pdwData, sizeof(ULONG));
|
|
}
|
|
}
|
|
}
|
|
else if ((rc = GetFieldUnitRegionObj(
|
|
(PFIELDUNITOBJ)pdataObj->pbDataBuff, &pnsBase)) ==
|
|
STATUS_SUCCESS && pnsBase != NULL)
|
|
{
|
|
rc = AccessBaseField(pctxt, pnsBase, pfd, pdwData, fRead);
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("AccessFieldData=%x (Data=%x)\n", rc, pdwData? *pdwData: 0));
|
|
return rc;
|
|
} //AccessFieldData
|
|
|
|
/***LP PushPreserveWriteObj - Push a PreserveWrObj frame on the stack
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pdataObj -> object
|
|
* dwData - data to be written
|
|
* dwPreserveMask - preserve bit mask
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL PushPreserveWriteObj(PCTXT pctxt, POBJDATA pdataObj,
|
|
ULONG dwData, ULONG dwPreserveMask)
|
|
{
|
|
TRACENAME("PUSHPRESERVEWRITEOBJ")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
PPRESERVEWROBJ ppwro;
|
|
|
|
ENTER(3, ("PushPreserveWriteObj(pctxt=%x,pdataObj=%x,Data=%x,PreserveMask=%x)\n",
|
|
pctxt, pdataObj, dwData, dwPreserveMask));
|
|
|
|
if ((rc = PushFrame(pctxt, SIG_PRESERVEWROBJ, sizeof(PRESERVEWROBJ),
|
|
PreserveWriteObj, &ppwro)) == STATUS_SUCCESS)
|
|
{
|
|
ppwro->pdataObj = pdataObj;
|
|
ppwro->dwWriteData = dwData;
|
|
ppwro->dwPreserveMask = dwPreserveMask;
|
|
}
|
|
|
|
EXIT(3, ("PushPreserveWriteObj=%x\n", rc));
|
|
return rc;
|
|
} //PushPreserveWriteObj
|
|
|
|
/***LP PreserveWriteObj - Preserve Write data to a field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* ppwro -> PRESERVEWROBJ
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL PreserveWriteObj(PCTXT pctxt, PPRESERVEWROBJ ppwro, NTSTATUS rc)
|
|
{
|
|
TRACENAME("PRESERVEWRITEOBJ")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(ppwro->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 2;
|
|
|
|
ENTER(3, ("PreserveWriteObj(Stage=%d,pctxt=%x,ppwro=%x,rc=%x)\n",
|
|
dwStage, pctxt, ppwro, rc));
|
|
|
|
ASSERT(ppwro->FrameHdr.dwSig == SIG_PRESERVEWROBJ);
|
|
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
//
|
|
// Stage 0: Read the object first.
|
|
//
|
|
ppwro->FrameHdr.dwfFrame++;
|
|
rc = PushAccFieldObj(pctxt, ReadFieldObj, ppwro->pdataObj,
|
|
&((PFIELDUNITOBJ)ppwro->pdataObj->pbDataBuff)->FieldDesc,
|
|
(PUCHAR)&ppwro->dwReadData, sizeof(ULONG));
|
|
break;
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: OR the preserve bits to the data to be written and
|
|
// write it.
|
|
//
|
|
ppwro->FrameHdr.dwfFrame++;
|
|
ppwro->dwWriteData |= ppwro->dwReadData & ppwro->dwPreserveMask;
|
|
rc = PushAccFieldObj(pctxt, WriteFieldObj, ppwro->pdataObj,
|
|
&((PFIELDUNITOBJ)ppwro->pdataObj->pbDataBuff)->FieldDesc,
|
|
(PUCHAR)&ppwro->dwWriteData, sizeof(ULONG));
|
|
break;
|
|
|
|
case 2:
|
|
//
|
|
// Stage 2: Clean up.
|
|
//
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("PreserveWriteObj=%x\n", rc));
|
|
return rc;
|
|
} //PreserveWriteObj
|
|
|
|
/***LP AccessBaseField - Access the base field object
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pnsBase -> OpRegion object
|
|
* pfd -> FIELDDESC
|
|
* pdwData -> result data (for read access) or data to be written
|
|
* fRead - TRUE if read access
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*
|
|
* NOTE
|
|
* If pdwData is NULL, it implies a read access.
|
|
*/
|
|
|
|
NTSTATUS LOCAL AccessBaseField(PCTXT pctxt, PNSOBJ pnsBase, PFIELDDESC pfd,
|
|
PULONG pdwData, BOOLEAN fRead)
|
|
{
|
|
TRACENAME("ACCESSBASEFIELD")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
POPREGIONOBJ pop;
|
|
ULONG_PTR uipAddr;
|
|
ULONG dwSize, dwDataMask, dwAccMask;
|
|
PRSACCESS prsa;
|
|
BOOLEAN fPreserve;
|
|
|
|
ENTER(3, ("AccessBaseField(pctxt=%x,pnsBase=%x,pfd=%x,pdwData=%x,fRead=%x)\n",
|
|
pctxt, pnsBase, pfd, pdwData, fRead));
|
|
|
|
ASSERT(pnsBase->ObjData.dwDataType == OBJTYPE_OPREGION);
|
|
pop = (POPREGIONOBJ)pnsBase->ObjData.pbDataBuff;
|
|
uipAddr = (ULONG_PTR)(pop->uipOffset + pfd->dwByteOffset);
|
|
dwSize = ACCSIZE(pfd->dwFieldFlags);
|
|
dwDataMask = (SHIFTLEFT(1L, pfd->dwNumBits) - 1) << pfd->dwStartBitPos;
|
|
dwAccMask = SHIFTLEFT(1L, dwSize*8) - 1;
|
|
fPreserve = (BOOLEAN)(((pfd->dwFieldFlags & UPDATERULE_MASK) ==
|
|
UPDATERULE_PRESERVE) &&
|
|
((~dwDataMask & dwAccMask) != 0));
|
|
|
|
//
|
|
// update the result so we are left only with the relavant bits
|
|
//
|
|
*pdwData &= dwDataMask;
|
|
|
|
if (!fRead &&
|
|
((pfd->dwFieldFlags & UPDATERULE_MASK) == UPDATERULE_WRITEASONES))
|
|
{
|
|
*pdwData |= ~dwDataMask;
|
|
}
|
|
|
|
switch (pop->bRegionSpace)
|
|
{
|
|
case REGSPACE_MEM:
|
|
if (fRead)
|
|
{
|
|
*pdwData = ReadSystemMem(uipAddr, dwSize, dwDataMask);
|
|
}
|
|
else
|
|
{
|
|
if (fPreserve)
|
|
{
|
|
*pdwData |= ReadSystemMem(uipAddr, dwSize, ~dwDataMask);
|
|
}
|
|
|
|
WriteSystemMem(uipAddr, dwSize, *pdwData, dwAccMask);
|
|
}
|
|
break;
|
|
|
|
case REGSPACE_IO:
|
|
if (fRead)
|
|
{
|
|
*pdwData = ReadSystemIO((ULONG)uipAddr, dwSize, dwDataMask);
|
|
}
|
|
else
|
|
{
|
|
if (fPreserve)
|
|
{
|
|
*pdwData |= ReadSystemIO((ULONG)uipAddr, dwSize, ~dwDataMask);
|
|
}
|
|
|
|
WriteSystemIO((ULONG)uipAddr, dwSize, *pdwData);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (((prsa = FindRSAccess(pop->bRegionSpace)) != NULL) &&
|
|
(prsa->pfnCookAccess != NULL))
|
|
{
|
|
if (fRead)
|
|
{
|
|
#ifdef DEBUGGER
|
|
ULONG dwOldFlags = gDebugger.dwfDebugger;
|
|
|
|
if (dwOldFlags & DBGF_TRACE_NONEST)
|
|
{
|
|
gDebugger.dwfDebugger &= ~DBGF_AMLTRACE_ON;
|
|
}
|
|
#endif
|
|
//
|
|
// Read access.
|
|
//
|
|
ASSERT(!(pctxt->dwfCtxt & CTXTF_READY));
|
|
rc = prsa->pfnCookAccess(RSACCESS_READ, pnsBase, uipAddr,
|
|
dwSize, pdwData, prsa->uipCookParam,
|
|
RestartCtxtCallback,
|
|
&pctxt->CtxtData);
|
|
#ifdef DEBUGGER
|
|
gDebugger.dwfDebugger = dwOldFlags;
|
|
#endif
|
|
|
|
if (rc == STATUS_PENDING)
|
|
{
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
else if (rc != STATUS_SUCCESS)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_RS_ACCESS,
|
|
("AccessBaseField: RegionSpace %x read handler returned error %x",
|
|
pop->bRegionSpace, rc));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PWRCOOKACC pwca;
|
|
//
|
|
// Write access.
|
|
//
|
|
if ((rc = PushFrame(pctxt, SIG_WRCOOKACC, sizeof(WRCOOKACC),
|
|
WriteCookAccess, &pwca)) ==
|
|
STATUS_SUCCESS)
|
|
{
|
|
pwca->pnsBase = pnsBase;
|
|
pwca->prsa = prsa;
|
|
pwca->dwAddr = (ULONG)uipAddr;
|
|
pwca->dwSize = dwSize;
|
|
pwca->dwData = *pdwData;
|
|
pwca->dwDataMask = dwDataMask;
|
|
pwca->fPreserve = fPreserve;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INVALID_REGIONSPACE,
|
|
("AccessBaseField: no handler for RegionSpace %x",
|
|
pop->bRegionSpace));
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("AccessBaseField=%x (Value=%x,Addr=%x,Size=%d,DataMask=%x,AccMask=%x)\n",
|
|
rc, *pdwData, uipAddr, dwSize, dwDataMask, dwAccMask));
|
|
return rc;
|
|
} //AccessBaseField
|
|
|
|
/***LP WriteCookAccess - do a region space write cook access
|
|
*
|
|
* ENTRY
|
|
* pctxt -> CTXT
|
|
* pwca -> WRCOOKACC
|
|
* rc - status code
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteCookAccess(PCTXT pctxt, PWRCOOKACC pwca, NTSTATUS rc)
|
|
{
|
|
TRACENAME("WRCOOKACCESS")
|
|
ULONG dwStage = (rc == STATUS_SUCCESS)?
|
|
(pwca->FrameHdr.dwfFrame & FRAMEF_STAGE_MASK): 3;
|
|
KIRQL oldIrql;
|
|
LONG busy;
|
|
POPREGIONOBJ pop = (POPREGIONOBJ)pwca->pnsBase->ObjData.pbDataBuff;
|
|
|
|
ENTER(3, ("WriteCookAccess(Stage=%d,pctxt=%x,pwca=%x,rc=%x)\n",
|
|
dwStage, pctxt, pwca, rc));
|
|
|
|
ASSERT(pwca->FrameHdr.dwSig == SIG_WRCOOKACC);
|
|
|
|
switch (dwStage)
|
|
{
|
|
case 0:
|
|
//
|
|
// Stage 0: if PRESERVE, do read first.
|
|
//
|
|
if (pwca->fPreserve)
|
|
{
|
|
#ifdef DEBUGGER
|
|
ULONG dwOldFlags = gDebugger.dwfDebugger;
|
|
|
|
if (dwOldFlags & DBGF_TRACE_NONEST)
|
|
{
|
|
gDebugger.dwfDebugger &= ~DBGF_AMLTRACE_ON;
|
|
}
|
|
#endif
|
|
|
|
KeAcquireSpinLock(&pop->listLock, &oldIrql);
|
|
if (busy = InterlockedExchange(&pop->RegionBusy, TRUE)) {
|
|
|
|
//
|
|
// Somebody is currently using this operation region.
|
|
// Queue this context so that it can be re-started later.
|
|
//
|
|
|
|
QueueContext(pctxt,
|
|
0xffff,
|
|
&pop->plistWaiters);
|
|
|
|
}
|
|
KeReleaseSpinLock(&pop->listLock, oldIrql);
|
|
|
|
if (busy) {
|
|
rc = AMLISTA_PENDING;
|
|
break;
|
|
}
|
|
|
|
pwca->FrameHdr.dwfFrame++;
|
|
ASSERT(!(pctxt->dwfCtxt & CTXTF_READY));
|
|
rc = pwca->prsa->pfnCookAccess(RSACCESS_READ, pwca->pnsBase,
|
|
(ULONG_PTR)pwca->dwAddr,
|
|
pwca->dwSize,
|
|
&pwca->dwDataTmp,
|
|
pwca->prsa->uipCookParam,
|
|
RestartCtxtCallback,
|
|
&pctxt->CtxtData);
|
|
#ifdef DEBUGGER
|
|
gDebugger.dwfDebugger = dwOldFlags;
|
|
#endif
|
|
|
|
if (rc == STATUS_PENDING)
|
|
{
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
else if (rc != STATUS_SUCCESS)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_RS_ACCESS,
|
|
("WriteCookAccess: RegionSpace %x read handler returned error %x",
|
|
pop->bRegionSpace, rc));
|
|
}
|
|
|
|
if (rc != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// No preserve, we can skip the ORing.
|
|
//
|
|
pwca->FrameHdr.dwfFrame += 2;
|
|
goto Stage2;
|
|
}
|
|
|
|
case 1:
|
|
//
|
|
// Stage 1: OR the preserved bits.
|
|
//
|
|
pwca->dwData |= pwca->dwDataTmp & ~pwca->dwDataMask;
|
|
pwca->FrameHdr.dwfFrame++;
|
|
|
|
case 2:
|
|
Stage2:
|
|
//
|
|
// Stage 2: Write the data.
|
|
//
|
|
#ifdef DEBUGGER
|
|
{
|
|
ULONG dwOldFlags = gDebugger.dwfDebugger;
|
|
|
|
if (dwOldFlags & DBGF_TRACE_NONEST)
|
|
{
|
|
gDebugger.dwfDebugger &= ~DBGF_AMLTRACE_ON;
|
|
}
|
|
#endif
|
|
pwca->FrameHdr.dwfFrame++;
|
|
ASSERT(!(pctxt->dwfCtxt & CTXTF_READY));
|
|
rc = pwca->prsa->pfnCookAccess(RSACCESS_WRITE, pwca->pnsBase,
|
|
(ULONG_PTR)pwca->dwAddr,
|
|
pwca->dwSize,
|
|
&pwca->dwData,
|
|
pwca->prsa->uipCookParam,
|
|
RestartCtxtCallback,
|
|
&pctxt->CtxtData);
|
|
#ifdef DEBUGGER
|
|
gDebugger.dwfDebugger = dwOldFlags;
|
|
}
|
|
#endif
|
|
|
|
if (rc == STATUS_PENDING)
|
|
{
|
|
rc = AMLISTA_PENDING;
|
|
}
|
|
else if (rc != STATUS_SUCCESS)
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_RS_ACCESS,
|
|
("WriteCookAccess: RegionSpace %x read handler returned error %x",
|
|
pop->bRegionSpace, rc));
|
|
}
|
|
|
|
if (rc != STATUS_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
case 3:
|
|
|
|
if (pwca->fPreserve) {
|
|
|
|
KeAcquireSpinLock(&pop->listLock, &oldIrql);
|
|
|
|
//
|
|
// Restart anybody who blocked while we were in here.
|
|
//
|
|
|
|
DequeueAndReadyContext(&pop->plistWaiters);
|
|
|
|
//
|
|
// Release the lock on this op-region.
|
|
//
|
|
|
|
InterlockedExchange(&pop->RegionBusy, FALSE);
|
|
|
|
KeReleaseSpinLock(&pop->listLock, oldIrql);
|
|
}
|
|
|
|
//
|
|
// Stage 3: Clean up.
|
|
//
|
|
PopFrame(pctxt);
|
|
}
|
|
|
|
EXIT(3, ("WriteCookAccess=%x\n", rc));
|
|
return rc;
|
|
} //WriteCookAccess
|
|
|
|
/***LP ReadBuffField - Read data from a buffer field
|
|
*
|
|
* ENTRY
|
|
* pbf -> buffer field object
|
|
* pfd -> field descriptor
|
|
* pdwData -> to hold result data
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL ReadBuffField(PBUFFFIELDOBJ pbf, PFIELDDESC pfd, PULONG pdwData)
|
|
{
|
|
TRACENAME("READBUFFFIELD")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
ULONG dwAccSize = ACCSIZE(pfd->dwFieldFlags);
|
|
|
|
ENTER(3, ("ReadBuffField(pbf=%x,pfd=%x,pdwData=%x)\n", pbf, pfd, pdwData));
|
|
|
|
if (pfd->dwByteOffset + dwAccSize <= pbf->dwBuffLen)
|
|
{
|
|
ULONG dwMask = (SHIFTLEFT(1L, pfd->dwNumBits) - 1) <<
|
|
pfd->dwStartBitPos;
|
|
|
|
*pdwData = ReadSystemMem((ULONG_PTR)(pbf->pbDataBuff +
|
|
pfd->dwByteOffset),
|
|
dwAccSize, dwMask);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INDEX_TOO_BIG,
|
|
("ReadBuffField: offset exceeding buffer size (Offset=%x,BuffSize=%x,AccSize)",
|
|
pfd->dwByteOffset, pbf->dwBuffLen, dwAccSize));
|
|
}
|
|
|
|
EXIT(3, ("ReadBuffField=%x (Data=%x)\n", rc, *pdwData));
|
|
return rc;
|
|
} //ReadBuffField
|
|
|
|
/***LP WriteBuffField - Write data to a buffer field
|
|
*
|
|
* ENTRY
|
|
* pbf -> buffer field object
|
|
* pfd -> field descriptor
|
|
* dwData - data
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns STATUS_SUCCESS
|
|
* EXIT-FAILURE
|
|
* returns AMLIERR_ code
|
|
*/
|
|
|
|
NTSTATUS LOCAL WriteBuffField(PBUFFFIELDOBJ pbf, PFIELDDESC pfd, ULONG dwData)
|
|
{
|
|
TRACENAME("WRITEBUFFFIELD")
|
|
NTSTATUS rc = STATUS_SUCCESS;
|
|
ULONG dwAccSize = ACCSIZE(pfd->dwFieldFlags);
|
|
|
|
ENTER(3, ("WriteBuffField(pbf=%x,pfd=%x,dwData=%x)\n", pbf, pfd, dwData));
|
|
|
|
if (pfd->dwByteOffset + dwAccSize <= pbf->dwBuffLen)
|
|
{
|
|
ULONG dwMask = (SHIFTLEFT(1L, pfd->dwNumBits) - 1) <<
|
|
pfd->dwStartBitPos;
|
|
|
|
WriteSystemMem((ULONG_PTR)(pbf->pbDataBuff + pfd->dwByteOffset),
|
|
dwAccSize, dwData & dwMask, dwMask);
|
|
}
|
|
else
|
|
{
|
|
rc = AMLI_LOGERR(AMLIERR_INDEX_TOO_BIG,
|
|
("WriteBuffField: offset exceeding buffer size (Offset=%x,BuffSize=%x,AccSize=%x)",
|
|
pfd->dwByteOffset, pbf->dwBuffLen, dwAccSize));
|
|
}
|
|
|
|
EXIT(3, ("WriteBuffField=%x\n", rc));
|
|
return rc;
|
|
} //WriteBuffField
|
|
|
|
|
|
/***LP ReadSystemMem - Read system memory
|
|
*
|
|
* ENTRY
|
|
* uipAddr - memory address
|
|
* dwSize - size to read
|
|
* dwMask - data mask
|
|
*
|
|
* EXIT
|
|
* return memory content
|
|
*/
|
|
|
|
ULONG LOCAL ReadSystemMem(ULONG_PTR uipAddr, ULONG dwSize, ULONG dwMask)
|
|
{
|
|
TRACENAME("READSYSTEMMEM")
|
|
ULONG dwData = 0;
|
|
ULONG dwCount;
|
|
|
|
ENTER(3, ("ReadSystemMem(Addr=%x,Size=%d,Mask=%x)\n",
|
|
uipAddr, dwSize, dwMask));
|
|
|
|
ASSERT((dwSize == sizeof(UCHAR)) || (dwSize == sizeof(USHORT)) ||
|
|
(dwSize == sizeof(ULONG)));
|
|
|
|
#if defined(_IA64_)
|
|
|
|
dwCount = dwSize/sizeof(UCHAR);
|
|
|
|
ASSERT(dwCount <= (sizeof(ULONG)/sizeof(UCHAR)));
|
|
|
|
//
|
|
// check for misalignment
|
|
//
|
|
if (uipAddr % dwCount) {
|
|
//
|
|
// unaligned, do the operation byte-wise
|
|
//
|
|
MEMCPY(&dwData, (PVOID)uipAddr, dwSize);
|
|
|
|
} else {
|
|
//
|
|
// aligned, just do the read atomically
|
|
//
|
|
switch (dwSize)
|
|
{
|
|
case sizeof(UCHAR):
|
|
dwData = (ULONG)READ_REGISTER_UCHAR((PUCHAR)uipAddr);
|
|
break;
|
|
|
|
case sizeof(USHORT):
|
|
dwData = (ULONG)READ_REGISTER_USHORT((PUSHORT)uipAddr);
|
|
break;
|
|
|
|
case sizeof(ULONG):
|
|
dwData = READ_REGISTER_ULONG((PULONG)uipAddr);
|
|
break;
|
|
}
|
|
}
|
|
|
|
#else
|
|
|
|
MEMCPY(&dwData, (PVOID)uipAddr, dwSize);
|
|
|
|
#endif
|
|
|
|
dwData &= dwMask;
|
|
|
|
EXIT(3, ("ReadSystemMem=%x\n", dwData));
|
|
return dwData;
|
|
} //ReadSystemMem
|
|
|
|
/***LP WriteSystemMem - Write system memory
|
|
*
|
|
* ENTRY
|
|
* uipAddr - memory address
|
|
* dwSize - size to write
|
|
* dwData - data to write
|
|
* dwMask - data mask
|
|
*
|
|
* EXIT
|
|
* return memory content
|
|
*/
|
|
|
|
VOID LOCAL WriteSystemMem(ULONG_PTR uipAddr, ULONG dwSize, ULONG dwData,
|
|
ULONG dwMask)
|
|
{
|
|
TRACENAME("WRITESYSTEMMEM")
|
|
ULONG dwTmpData = 0;
|
|
ULONG dwCount;
|
|
ULONG SizeToMask[5] = { 0x0, 0xff, 0xffff, 0, 0xffffffff };
|
|
BOOLEAN SkipReadOperation = FALSE;
|
|
|
|
if (dwMask == SizeToMask[dwSize])
|
|
{
|
|
SkipReadOperation = TRUE;
|
|
}
|
|
|
|
ENTER(3, ("WriteSystemMem(Addr=%x,Size=%d,Data=%x,Mask=%x)\n",
|
|
uipAddr, dwSize, dwData, dwMask));
|
|
|
|
ASSERT((dwSize == sizeof(UCHAR)) || (dwSize == sizeof(USHORT)) ||
|
|
(dwSize == sizeof(ULONG)));
|
|
|
|
#if defined(_IA64_)
|
|
|
|
dwCount = dwSize/sizeof(UCHAR);
|
|
|
|
ASSERT(dwCount <= (sizeof(ULONG)/sizeof(UCHAR)));
|
|
|
|
//
|
|
// check for misalignment
|
|
//
|
|
if (uipAddr % dwCount)
|
|
{
|
|
//
|
|
// unaligned, do the operation byte-wise
|
|
//
|
|
if (!SkipReadOperation)
|
|
{
|
|
MEMCPY(&dwTmpData, (PVOID)uipAddr, dwSize);
|
|
}
|
|
|
|
dwTmpData &= ~dwMask;
|
|
dwTmpData |= dwData;
|
|
|
|
MEMCPY((PVOID)uipAddr, &dwTmpData, dwSize);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// aligned access. just get the data atomically.
|
|
//
|
|
switch (dwSize)
|
|
{
|
|
case sizeof(UCHAR):
|
|
if (!SkipReadOperation)
|
|
{
|
|
dwTmpData = READ_REGISTER_UCHAR((PUCHAR)uipAddr);
|
|
}
|
|
dwTmpData &= ~dwMask;
|
|
dwTmpData |= dwData;
|
|
WRITE_REGISTER_UCHAR((PUCHAR)uipAddr, (UCHAR)dwTmpData);
|
|
break;
|
|
|
|
case sizeof(USHORT):
|
|
if (!SkipReadOperation)
|
|
{
|
|
dwTmpData = READ_REGISTER_USHORT((PUCHAR)uipAddr);
|
|
}
|
|
dwTmpData &= ~dwMask;
|
|
dwTmpData |= dwData;
|
|
WRITE_REGISTER_USHORT((PUSHORT)uipAddr, (USHORT)dwTmpData);
|
|
break;
|
|
|
|
case sizeof(ULONG):
|
|
if (!SkipReadOperation)
|
|
{
|
|
dwTmpData = READ_REGISTER_ULONG((PUCHAR)uipAddr);
|
|
}
|
|
dwTmpData &= ~dwMask;
|
|
dwTmpData |= dwData;
|
|
WRITE_REGISTER_ULONG((PULONG)uipAddr, dwTmpData);
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
|
|
if (!SkipReadOperation)
|
|
{
|
|
MEMCPY(&dwTmpData, (PVOID)uipAddr, dwSize);
|
|
}
|
|
dwTmpData &= ~dwMask;
|
|
dwTmpData |= dwData;
|
|
MEMCPY((PVOID)uipAddr, &dwTmpData, dwSize);
|
|
|
|
#endif
|
|
|
|
EXIT(3, ("WriteSystemMem!\n"));
|
|
} //WriteSystemMem
|
|
|
|
|
|
|
|
/***LP ReadSystemIO - Read system IO
|
|
*
|
|
* ENTRY
|
|
* dwAddr - memory address
|
|
* dwSize - size to read
|
|
* dwMask - data mask
|
|
*
|
|
* EXIT
|
|
* return memory content
|
|
*/
|
|
|
|
ULONG LOCAL ReadSystemIO(ULONG dwAddr, ULONG dwSize, ULONG dwMask)
|
|
{
|
|
TRACENAME("READSYSTEMIO")
|
|
ULONG dwData = 0;
|
|
|
|
ENTER(3, ("ReadSystemIO(Addr=%x,Size=%d,Mask=%x)\n",
|
|
dwAddr, dwSize, dwMask));
|
|
|
|
ASSERT((dwSize == sizeof(UCHAR)) || (dwSize == sizeof(USHORT)) ||
|
|
(dwSize == sizeof(ULONG)));
|
|
|
|
if(CheckSystemIOAddressValidity(TRUE, dwAddr, dwSize, &dwData))
|
|
{
|
|
|
|
//
|
|
// HACKHACK: We are adding this here because Dell Latitude laptops with Older
|
|
// BIOS (A07 and older) hang in SMI because there is a non zero value\
|
|
// in CH. We now clear CX to work around their bug.
|
|
//
|
|
#ifdef _X86_
|
|
__asm
|
|
{
|
|
xor cx,cx
|
|
}
|
|
#endif //_X86_
|
|
|
|
switch (dwSize)
|
|
{
|
|
case sizeof(UCHAR):
|
|
dwData = (ULONG)READ_PORT_UCHAR((PUCHAR)UlongToPtr(dwAddr));
|
|
break;
|
|
|
|
case sizeof(USHORT):
|
|
dwData = (ULONG)READ_PORT_USHORT((PUSHORT)UlongToPtr(dwAddr));
|
|
break;
|
|
|
|
case sizeof(ULONG):
|
|
dwData = READ_PORT_ULONG((PULONG)UlongToPtr(dwAddr));
|
|
break;
|
|
}
|
|
}
|
|
|
|
dwData &= dwMask;
|
|
|
|
EXIT(3, ("ReadSystemIO=%x\n", dwData));
|
|
return dwData;
|
|
} //ReadSystemIO
|
|
|
|
/***LP WriteSystemIO - Write system IO
|
|
*
|
|
* ENTRY
|
|
* dwAddr - memory address
|
|
* dwSize - size to write
|
|
* dwData - data to write
|
|
*
|
|
* EXIT
|
|
* return memory content
|
|
*/
|
|
|
|
VOID LOCAL WriteSystemIO(ULONG dwAddr, ULONG dwSize, ULONG dwData)
|
|
{
|
|
TRACENAME("WRITESYSTEMIO")
|
|
|
|
ENTER(3, ("WriteSystemIO(Addr=%x,Size=%d,Data=%x)\n",
|
|
dwAddr, dwSize, dwData));
|
|
|
|
ASSERT((dwSize == sizeof(UCHAR)) || (dwSize == sizeof(USHORT)) ||
|
|
(dwSize == sizeof(ULONG)));
|
|
|
|
if(CheckSystemIOAddressValidity(FALSE, dwAddr, dwSize, &dwData))
|
|
{
|
|
//
|
|
// HACKHACK: We are adding this here because Dell Latitude laptops with Older
|
|
// BIOS (A07 and older) hang in SMI because there is a non zero value\
|
|
// in CH. We now clear CX to work around their bug.
|
|
//
|
|
#ifdef _X86_
|
|
__asm
|
|
{
|
|
xor cx,cx
|
|
}
|
|
#endif //_X86_
|
|
|
|
switch (dwSize)
|
|
{
|
|
case sizeof(UCHAR):
|
|
WRITE_PORT_UCHAR((PUCHAR)UlongToPtr(dwAddr), (UCHAR)dwData);
|
|
break;
|
|
|
|
case sizeof(USHORT):
|
|
WRITE_PORT_USHORT((PUSHORT)UlongToPtr(dwAddr), (USHORT)dwData);
|
|
break;
|
|
|
|
case sizeof(ULONG):
|
|
WRITE_PORT_ULONG((PULONG)UlongToPtr(dwAddr), dwData);
|
|
break;
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("WriteSystemIO!\n"));
|
|
} //WriteSystemIO
|
|
|
|
#ifdef DEBUGGER
|
|
/***LP DumpObject - Dump object info.
|
|
*
|
|
* ENTRY
|
|
* pdata -> data
|
|
* pszName -> object name
|
|
* iLevel - indent level
|
|
*
|
|
* EXIT
|
|
* None
|
|
*
|
|
* NOTE
|
|
* If iLevel is negative, no indentation and newline are printed.
|
|
*/
|
|
|
|
VOID LOCAL DumpObject(POBJDATA pdata, PSZ pszName, int iLevel)
|
|
{
|
|
TRACENAME("DUMPOBJECT")
|
|
BOOLEAN fPrintNewLine;
|
|
int i;
|
|
char szName1[sizeof(NAMESEG) + 1],
|
|
szName2[sizeof(NAMESEG) + 1];
|
|
|
|
ENTER(3, ("DumpObject(pdata=%x,Name=%s,Level=%d)\n",
|
|
pdata, pszName, iLevel));
|
|
|
|
fPrintNewLine = (BOOLEAN)(iLevel >= 0);
|
|
|
|
for (i = 0; i < iLevel; ++i)
|
|
{
|
|
PRINTF("| ");
|
|
}
|
|
|
|
if (pszName == NULL)
|
|
{
|
|
pszName = "";
|
|
}
|
|
|
|
switch (pdata->dwDataType)
|
|
{
|
|
case OBJTYPE_UNKNOWN:
|
|
PRINTF("Unknown(%s)", pszName);
|
|
break;
|
|
|
|
case OBJTYPE_INTDATA:
|
|
PRINTF("Integer(%s:Value=0x%08x[%d])",
|
|
pszName, pdata->uipDataValue, pdata->uipDataValue);
|
|
break;
|
|
|
|
case OBJTYPE_STRDATA:
|
|
PRINTF("String(%s:Str=\"%s\")", pszName, pdata->pbDataBuff);
|
|
break;
|
|
|
|
case OBJTYPE_BUFFDATA:
|
|
PRINTF("Buffer(%s:Ptr=%x,Len=%d)",
|
|
pszName, pdata->pbDataBuff, pdata->dwDataLen);
|
|
PrintBuffData(pdata->pbDataBuff, pdata->dwDataLen);
|
|
break;
|
|
|
|
case OBJTYPE_PKGDATA:
|
|
PRINTF("Package(%s:NumElements=%d){",
|
|
pszName, ((PPACKAGEOBJ)pdata->pbDataBuff)->dwcElements);
|
|
|
|
if (fPrintNewLine)
|
|
{
|
|
PRINTF("\n");
|
|
}
|
|
|
|
for (i = 0;
|
|
i < (int)((PPACKAGEOBJ)pdata->pbDataBuff)->dwcElements;
|
|
++i)
|
|
{
|
|
DumpObject(&((PPACKAGEOBJ)pdata->pbDataBuff)->adata[i], NULL,
|
|
fPrintNewLine? iLevel + 1: -1);
|
|
|
|
if (!fPrintNewLine &&
|
|
(i < (int)((PPACKAGEOBJ)pdata->pbDataBuff)->dwcElements))
|
|
{
|
|
PRINTF(",");
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < iLevel; ++i)
|
|
{
|
|
PRINTF("| ");
|
|
}
|
|
|
|
PRINTF("}");
|
|
break;
|
|
|
|
case OBJTYPE_FIELDUNIT:
|
|
PRINTF("FieldUnit(%s:FieldParent=%p,ByteOffset=0x%x,StartBit=0x%x,NumBits=%d,FieldFlags=0x%x)",
|
|
pszName,
|
|
((PFIELDUNITOBJ)pdata->pbDataBuff)->pnsFieldParent,
|
|
((PFIELDUNITOBJ)pdata->pbDataBuff)->FieldDesc.dwByteOffset,
|
|
((PFIELDUNITOBJ)pdata->pbDataBuff)->FieldDesc.dwStartBitPos,
|
|
((PFIELDUNITOBJ)pdata->pbDataBuff)->FieldDesc.dwNumBits,
|
|
((PFIELDUNITOBJ)pdata->pbDataBuff)->FieldDesc.dwFieldFlags);
|
|
break;
|
|
|
|
case OBJTYPE_DEVICE:
|
|
PRINTF("Device(%s)", pszName);
|
|
break;
|
|
|
|
case OBJTYPE_EVENT:
|
|
PRINTF("Event(%s:pKEvent=%x)", pszName, pdata->pbDataBuff);
|
|
break;
|
|
|
|
case OBJTYPE_METHOD:
|
|
PRINTF("Method(%s:Flags=0x%x,CodeBuff=%p,Len=%d)",
|
|
pszName, ((PMETHODOBJ)pdata->pbDataBuff)->bMethodFlags,
|
|
((PMETHODOBJ)pdata->pbDataBuff)->abCodeBuff,
|
|
pdata->dwDataLen - FIELD_OFFSET(METHODOBJ, abCodeBuff));
|
|
break;
|
|
|
|
case OBJTYPE_MUTEX:
|
|
PRINTF("Mutex(%s:pKMutex=%x)", pszName, pdata->pbDataBuff);
|
|
break;
|
|
|
|
case OBJTYPE_OPREGION:
|
|
PRINTF("OpRegion(%s:RegionSpace=%s,Offset=0x%x,Len=%d)",
|
|
pszName,
|
|
GetRegionSpaceName(((POPREGIONOBJ)pdata->pbDataBuff)->bRegionSpace),
|
|
((POPREGIONOBJ)pdata->pbDataBuff)->uipOffset,
|
|
((POPREGIONOBJ)pdata->pbDataBuff)->dwLen);
|
|
break;
|
|
|
|
case OBJTYPE_POWERRES:
|
|
PRINTF("PowerResource(%s:SystemLevel=0x%x,ResOrder=%d)",
|
|
pszName, ((PPOWERRESOBJ)pdata->pbDataBuff)->bSystemLevel,
|
|
((PPOWERRESOBJ)pdata->pbDataBuff)->bResOrder);
|
|
break;
|
|
|
|
case OBJTYPE_PROCESSOR:
|
|
PRINTF("Processor(%s:ApicID=0x%x,PBlk=0x%x,PBlkLen=%d)",
|
|
pszName, ((PPROCESSOROBJ)pdata->pbDataBuff)->bApicID,
|
|
((PPROCESSOROBJ)pdata->pbDataBuff)->dwPBlk,
|
|
((PPROCESSOROBJ)pdata->pbDataBuff)->dwPBlkLen);
|
|
break;
|
|
|
|
case OBJTYPE_THERMALZONE:
|
|
PRINTF("ThermalZone(%s)", pszName);
|
|
break;
|
|
|
|
case OBJTYPE_BUFFFIELD:
|
|
PRINTF("BufferField(%s:Ptr=%x,Len=%d,ByteOffset=0x%x,StartBit=0x%x,NumBits=%d,FieldFlags=0x%x)",
|
|
pszName, ((PBUFFFIELDOBJ)pdata->pbDataBuff)->pbDataBuff,
|
|
((PBUFFFIELDOBJ)pdata->pbDataBuff)->dwBuffLen,
|
|
((PBUFFFIELDOBJ)pdata->pbDataBuff)->FieldDesc.dwByteOffset,
|
|
((PBUFFFIELDOBJ)pdata->pbDataBuff)->FieldDesc.dwStartBitPos,
|
|
((PBUFFFIELDOBJ)pdata->pbDataBuff)->FieldDesc.dwNumBits,
|
|
((PBUFFFIELDOBJ)pdata->pbDataBuff)->FieldDesc.dwFieldFlags);
|
|
break;
|
|
|
|
case OBJTYPE_DDBHANDLE:
|
|
PRINTF("DDBHandle(%s:Handle=%x)", pszName, pdata->pbDataBuff);
|
|
break;
|
|
|
|
case OBJTYPE_OBJALIAS:
|
|
PRINTF("ObjectAlias(%s:Alias=%s,Type=%s)",
|
|
pszName, GetObjectPath(pdata->pnsAlias),
|
|
GetObjectTypeName(pdata->pnsAlias->ObjData.dwDataType));
|
|
break;
|
|
|
|
case OBJTYPE_DATAALIAS:
|
|
PRINTF("DataAlias(%s:Link=%x)", pszName, pdata->pdataAlias);
|
|
if (fPrintNewLine)
|
|
{
|
|
DumpObject(pdata->pdataAlias, NULL, iLevel + 1);
|
|
fPrintNewLine = FALSE;
|
|
}
|
|
break;
|
|
|
|
case OBJTYPE_BANKFIELD:
|
|
STRCPYN(szName1,
|
|
(PSZ)(&((PBANKFIELDOBJ)pdata->pbDataBuff)->pnsBase->dwNameSeg),
|
|
sizeof(NAMESEG));
|
|
STRCPYN(szName2,
|
|
(PSZ)(&((PBANKFIELDOBJ)pdata->pbDataBuff)->pnsBank->dwNameSeg),
|
|
sizeof(NAMESEG));
|
|
PRINTF("BankField(%s:Base=%s,BankName=%s,BankValue=0x%x)",
|
|
pszName, szName1, szName2,
|
|
((PBANKFIELDOBJ)pdata->pbDataBuff)->dwBankValue);
|
|
break;
|
|
|
|
case OBJTYPE_FIELD:
|
|
STRCPYN(szName1,
|
|
(PSZ)(&((PFIELDOBJ)pdata->pbDataBuff)->pnsBase->dwNameSeg),
|
|
sizeof(NAMESEG));
|
|
PRINTF("Field(%s:Base=%s)", pszName, szName1);
|
|
break;
|
|
|
|
case OBJTYPE_INDEXFIELD:
|
|
STRCPYN(szName1,
|
|
(PSZ)(&((PINDEXFIELDOBJ)pdata->pbDataBuff)->pnsIndex->dwNameSeg),
|
|
sizeof(NAMESEG));
|
|
STRCPYN(szName2,
|
|
(PSZ)(&((PINDEXFIELDOBJ)pdata->pbDataBuff)->pnsData->dwNameSeg),
|
|
sizeof(NAMESEG));
|
|
PRINTF("IndexField(%s:IndexName=%s,DataName=%s)",
|
|
pszName, szName1, szName2);
|
|
break;
|
|
|
|
default:
|
|
AMLI_ERROR(("DumpObject: unexpected data object type (type=%x)",
|
|
pdata->dwDataType));
|
|
}
|
|
|
|
if (fPrintNewLine)
|
|
{
|
|
PRINTF("\n");
|
|
}
|
|
|
|
EXIT(3, ("DumpObject!\n"));
|
|
} //DumpObject
|
|
#endif
|
|
|
|
/***LP NeedGlobalLock - check if global lock is required
|
|
*
|
|
* ENTRY
|
|
* pfu - FIELDUNITOBJ
|
|
*
|
|
* EXIT-SUCCESS
|
|
* returns TRUE
|
|
* EXIT-FAILURE
|
|
* returns FALSE
|
|
*/
|
|
|
|
BOOLEAN LOCAL NeedGlobalLock(PFIELDUNITOBJ pfu)
|
|
{
|
|
TRACENAME("NEEDGLOBALLOCK")
|
|
BOOLEAN rc = FALSE;
|
|
|
|
ENTER(3, ("NeedGlobalLock(pfu=%x)\n", pfu));
|
|
|
|
if ((pfu->FieldDesc.dwFieldFlags & FDF_NEEDLOCK) ||
|
|
(pfu->FieldDesc.dwFieldFlags & LOCKRULE_LOCK))
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
POBJDATA pdataParent = &pfu->pnsFieldParent->ObjData;
|
|
PFIELDUNITOBJ pfuParent;
|
|
|
|
if (pdataParent->dwDataType == OBJTYPE_BANKFIELD)
|
|
{
|
|
pfuParent = (PFIELDUNITOBJ)
|
|
((PBANKFIELDOBJ)pdataParent->pbDataBuff)->pnsBank->ObjData.pbDataBuff;
|
|
if (pfuParent->FieldDesc.dwFieldFlags & LOCKRULE_LOCK)
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
}
|
|
else if (pdataParent->dwDataType == OBJTYPE_INDEXFIELD)
|
|
{
|
|
pfuParent = (PFIELDUNITOBJ)
|
|
((PINDEXFIELDOBJ)pdataParent->pbDataBuff)->pnsIndex->ObjData.pbDataBuff;
|
|
if (pfuParent->FieldDesc.dwFieldFlags & LOCKRULE_LOCK)
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pfuParent = (PFIELDUNITOBJ)
|
|
((PINDEXFIELDOBJ)pdataParent->pbDataBuff)->pnsData->ObjData.pbDataBuff;
|
|
if (pfuParent->FieldDesc.dwFieldFlags & LOCKRULE_LOCK)
|
|
{
|
|
rc = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (rc == TRUE)
|
|
{
|
|
pfu->FieldDesc.dwFieldFlags |= FDF_NEEDLOCK;
|
|
}
|
|
|
|
EXIT(3, ("NeedGlobalLock=%x\n", rc));
|
|
return rc;
|
|
} //NeedGlobalLock
|
|
|
|
|
|
/***LP CheckSystemIOAddressValidity - Check if the address is a legal IO address
|
|
*
|
|
* ENTRY
|
|
* fRead - TRUE iff access is a read. FALSE on write
|
|
* dwAddr - memory address
|
|
* ULONG dwSize - Size of data
|
|
* PULONG pdwData - Pointer to the data buffer.
|
|
*
|
|
* EXIT
|
|
* return TRUE on Valid address
|
|
*/
|
|
|
|
BOOLEAN LOCAL CheckSystemIOAddressValidity( BOOLEAN fRead,
|
|
ULONG dwAddr,
|
|
ULONG dwSize,
|
|
PULONG pdwData
|
|
)
|
|
{
|
|
TRACENAME("CHECKSYSTEMIOADDRESSVALIDITY")
|
|
ULONG i = 0;
|
|
BOOLEAN bRet = TRUE;
|
|
|
|
ENTER(3, ("CheckSystemIOAddressValidity(fRead=%s, dwAddr=%x, dwSize=%x, pdwData=%x)\n", (fRead?"TRUE":"FALSE"),dwAddr, dwSize, pdwData));
|
|
|
|
//
|
|
// check if list exists on this platform.
|
|
//
|
|
if(gpBadIOAddressList)
|
|
{
|
|
//
|
|
// Walk the list till we hit the end.
|
|
//
|
|
for(i=0; gpBadIOAddressList[i].BadAddrSize != 0 ; i++)
|
|
{
|
|
//
|
|
// Check if the incoming address is in the range
|
|
//
|
|
if((dwAddr >= (gpBadIOAddressList[i].BadAddrBegin)) && (dwAddr < ((gpBadIOAddressList[i].BadAddrBegin) + (gpBadIOAddressList[i].BadAddrSize))))
|
|
{
|
|
|
|
//
|
|
// Check if we need to ignore this address for legacy reasons.
|
|
//
|
|
if(gpBadIOAddressList[i].OSVersionTrigger <= gdwHighestOSVerQueried)
|
|
{
|
|
bRet = FALSE;
|
|
PRINTF("CheckSystemIOAddressValidity: failing illegal IO address (0x%x).\n", dwAddr);
|
|
}
|
|
else
|
|
{
|
|
PRINTF("CheckSystemIOAddressValidity: Passing for compatibility reasons on illegal IO address (0x%x).\n", dwAddr);
|
|
|
|
if(gpBadIOAddressList[i].IOHandler)
|
|
{
|
|
//
|
|
// Since we are handeling this here we can return FALSE. This way the
|
|
// calling function will not process this request.
|
|
//
|
|
bRet = FALSE;
|
|
|
|
//
|
|
// Call HAL and let it handle this IO request
|
|
//
|
|
(gpBadIOAddressList[i].IOHandler)(fRead, dwAddr, dwSize, pdwData);
|
|
|
|
PRINTF("CheckSystemIOAddressValidity: HAL IO handler called to %s address (0x%x). %s 0x%8lx\n",
|
|
fRead ? "read" : "write",
|
|
dwAddr,
|
|
fRead ? "Read" : "Wrote",
|
|
*pdwData
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Log the illegal access to the event log.
|
|
//
|
|
if (KeGetCurrentIrql() < DISPATCH_LEVEL)
|
|
{
|
|
|
|
LogInErrorLog(fRead,
|
|
dwAddr,
|
|
i
|
|
);
|
|
}
|
|
else
|
|
{
|
|
PIO_WORKITEM Log_WorkItem = NULL;
|
|
PDEVICE_OBJECT pACPIDeviceObject = ACPIGetRootDeviceObject();
|
|
|
|
if(pACPIDeviceObject)
|
|
{
|
|
Log_WorkItem = IoAllocateWorkItem(pACPIDeviceObject);
|
|
|
|
if(Log_WorkItem)
|
|
{
|
|
PAMLI_LOG_WORKITEM_CONTEXT pWorkItemContext = NULL;
|
|
|
|
|
|
pWorkItemContext = (PAMLI_LOG_WORKITEM_CONTEXT) ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(AMLI_LOG_WORKITEM_CONTEXT),
|
|
PRIV_TAG
|
|
);
|
|
if(pWorkItemContext)
|
|
{
|
|
pWorkItemContext->fRead = fRead;
|
|
pWorkItemContext->Address = dwAddr;
|
|
pWorkItemContext->Index = i;
|
|
pWorkItemContext->pIOWorkItem = Log_WorkItem;
|
|
|
|
IoQueueWorkItem(
|
|
Log_WorkItem,
|
|
DelayedLogInErrorLog,
|
|
DelayedWorkQueue,
|
|
(VOID*)pWorkItemContext
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// not enough free pool exists to satisfy the request.
|
|
//
|
|
PRINTF("CheckSystemIOAddressValidity: Failed to allocate contxt block from pool to spin off a logging work item.\n");
|
|
IoFreeWorkItem(Log_WorkItem);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// insufficient resources
|
|
//
|
|
PRINTF("CheckSystemIOAddressValidity: Failed to allocate a workitem to spin off delayed logging.\n");
|
|
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Failed to get ACPI root DeviceObject
|
|
//
|
|
PRINTF("CheckSystemIOAddressValidity: Failed to get ACPI root DeviceObject.\n");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("CheckSystemIOAddressValidity!\n"));
|
|
|
|
return bRet;
|
|
}
|
|
|
|
/***LP DelayedLogInErrorLog - Call LogInErrorLog
|
|
*
|
|
* ENTRY
|
|
* PDEVICE_OBJECT DeviceObject - Device Object.
|
|
* PVOID Context - Context pointer with data to call LogInErrorLog with.
|
|
*
|
|
* EXIT
|
|
* VOID
|
|
*/
|
|
VOID DelayedLogInErrorLog(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
|
|
LogInErrorLog(((PAMLI_LOG_WORKITEM_CONTEXT)Context)->fRead,
|
|
((PAMLI_LOG_WORKITEM_CONTEXT)Context)->Address,
|
|
((PAMLI_LOG_WORKITEM_CONTEXT)Context)->Index
|
|
);
|
|
|
|
|
|
IoFreeWorkItem((PIO_WORKITEM)((PAMLI_LOG_WORKITEM_CONTEXT)Context)->pIOWorkItem);
|
|
ExFreePool(Context);
|
|
}
|
|
|
|
|
|
/***LP LogInErrorLog - Log illegal IO access to event log
|
|
*
|
|
* ENTRY
|
|
* fRead - TRUE iff access is a read. FALSE on write
|
|
* dwAddr - Memory address
|
|
* ArrayIndex - Index into BadIOAddressList array.
|
|
*
|
|
* EXIT
|
|
* None.
|
|
*/
|
|
VOID LOCAL LogInErrorLog(BOOLEAN fRead, ULONG dwAddr, ULONG ArrayIndex)
|
|
{
|
|
TRACENAME("LOGERROR")
|
|
PWCHAR illegalIOPortAddress[3];
|
|
WCHAR AMLIName[6];
|
|
WCHAR addressBuffer[13];
|
|
WCHAR addressRangeBuffer[16];
|
|
|
|
ENTER(3, ("LogInErrorLog(fRead=%s, Addr=%x, ArrayIndex=%x)\n", (fRead?"TRUE":"FALSE"),dwAddr, ArrayIndex));
|
|
|
|
//
|
|
// Check to see if we need to log this address.
|
|
//
|
|
if(gpBadIOErrorLogDoneList)
|
|
{
|
|
//
|
|
// Check to see if we need to log this address.
|
|
//
|
|
if (!(gpBadIOErrorLogDoneList[ArrayIndex] & (fRead?READ_ERROR_NOTED:WRITE_ERROR_NOTED)))
|
|
{
|
|
gpBadIOErrorLogDoneList[ArrayIndex] |= (fRead?READ_ERROR_NOTED:WRITE_ERROR_NOTED);
|
|
|
|
//
|
|
// Turn the address into a string
|
|
//
|
|
swprintf( AMLIName, L"AMLI");
|
|
swprintf( addressBuffer, L"0x%x", dwAddr );
|
|
swprintf( addressRangeBuffer, L"0x%x - 0x%x",
|
|
gpBadIOAddressList[ArrayIndex].BadAddrBegin,
|
|
(gpBadIOAddressList[ArrayIndex].BadAddrBegin + (gpBadIOAddressList[ArrayIndex].BadAddrSize - 1)));
|
|
|
|
//
|
|
// Build the list of arguments to pass to the function that will write the
|
|
// error log to the registry
|
|
//
|
|
illegalIOPortAddress[0] = AMLIName;
|
|
illegalIOPortAddress[1] = addressBuffer;
|
|
illegalIOPortAddress[2] = addressRangeBuffer;
|
|
|
|
//
|
|
// Log error to event log
|
|
//
|
|
ACPIWriteEventLogEntry((fRead ? ACPI_ERR_AMLI_ILLEGAL_IO_READ_FATAL : ACPI_ERR_AMLI_ILLEGAL_IO_WRITE_FATAL),
|
|
illegalIOPortAddress,
|
|
3,
|
|
NULL,
|
|
0);
|
|
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("LogInErrorLog!\n"));
|
|
|
|
return;
|
|
}
|
|
|
|
/***LP InitIllegalIOAddressListFromHAL - Initialize the Illegal IO
|
|
* address List from the HAL.
|
|
*
|
|
* ENTRY
|
|
* None.
|
|
*
|
|
* EXIT
|
|
* None.
|
|
*/
|
|
VOID LOCAL InitIllegalIOAddressListFromHAL(VOID)
|
|
{
|
|
TRACENAME("InitIllegalIOAddressListFromHAL")
|
|
ULONG Length = 0;
|
|
NTSTATUS status;
|
|
|
|
ENTER(3, ("InitIllegalIOAddressListFromHAL\n"));
|
|
|
|
if(!gpBadIOAddressList)
|
|
{
|
|
//
|
|
// Query HAL to get the amount of memory to allocate
|
|
//
|
|
status = HalQuerySystemInformation (
|
|
HalQueryAMLIIllegalIOPortAddresses,
|
|
0,
|
|
NULL,
|
|
&Length
|
|
);
|
|
|
|
if(status == STATUS_INFO_LENGTH_MISMATCH)
|
|
{
|
|
if(Length)
|
|
{
|
|
//
|
|
// Allocate memory.
|
|
//
|
|
if ((gpBadIOAddressList = (PHAL_AMLI_BAD_IO_ADDRESS_LIST) MALLOC(Length, PRIV_TAG)) == NULL)
|
|
{
|
|
AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("InitIllegalIOAddressListFromHAL: failed to allocate Bad IO address list."));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Get bad IO address list from HAL.
|
|
//
|
|
status = HalQuerySystemInformation(
|
|
HalQueryAMLIIllegalIOPortAddresses,
|
|
Length,
|
|
gpBadIOAddressList,
|
|
&Length
|
|
);
|
|
//
|
|
// Cleanup on failure.
|
|
//
|
|
if(status != STATUS_SUCCESS)
|
|
{
|
|
PRINTF("InitIllegalIOAddressListFromHAL: HalQuerySystemInformation failed to get list from HAL. Returned(%x).\n", status);
|
|
FreellegalIOAddressList();
|
|
}
|
|
|
|
// Allocate the errorlogdone list. this helps us track if we have logged
|
|
// a certain address.
|
|
//
|
|
else
|
|
{
|
|
//
|
|
// Calculate array length
|
|
//
|
|
ULONG ArrayLength = (Length / sizeof(HAL_AMLI_BAD_IO_ADDRESS_LIST)) - 1;
|
|
|
|
if(ArrayLength >= 1)
|
|
{
|
|
if ((gpBadIOErrorLogDoneList = (PULONG) MALLOC((ArrayLength * sizeof(ULONG)), PRIV_TAG)) == NULL)
|
|
{
|
|
AMLI_LOGERR(AMLIERR_OUT_OF_MEM,
|
|
("InitIllegalIOAddressListFromHAL: failed to allocate ErrorLogDone list."));
|
|
}
|
|
else
|
|
{
|
|
RtlZeroMemory(gpBadIOErrorLogDoneList, (ArrayLength * sizeof(ULONG)));
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
PRINTF("InitIllegalIOAddressListFromHAL: HalQuerySystemInformation (HalQueryIllegalIOPortAddresses) returned 0 Length.\n");
|
|
}
|
|
}
|
|
else if(status == STATUS_INVALID_LEVEL)
|
|
{
|
|
PRINTF("InitIllegalIOAddressListFromHAL: HalQuerySystemInformation does not support HalQueryIllegalIOPortAddresses returned (STATUS_INVALID_LEVEL).\n");
|
|
}
|
|
else
|
|
{
|
|
PRINTF("InitIllegalIOAddressListFromHAL: failed. Returned(0x%08lx).\n", status);
|
|
}
|
|
}
|
|
|
|
EXIT(3, ("InitIllegalIOAddressListFromHAL!\n"));
|
|
return;
|
|
}
|
|
|
|
/***LP FreellegalIOAddressList - Free the Illegal IO
|
|
* address List.
|
|
*
|
|
* ENTRY
|
|
* None.
|
|
*
|
|
* EXIT
|
|
* None.
|
|
*/
|
|
VOID LOCAL FreellegalIOAddressList(VOID)
|
|
{
|
|
TRACENAME("FreellegalIOAddressList")
|
|
ENTER(3, ("FreellegalIOAddressList\n"));
|
|
|
|
if(gpBadIOAddressList)
|
|
{
|
|
MFREE(gpBadIOAddressList);
|
|
gpBadIOAddressList = NULL;
|
|
}
|
|
|
|
if(gpBadIOErrorLogDoneList)
|
|
{
|
|
MFREE(gpBadIOErrorLogDoneList);
|
|
gpBadIOErrorLogDoneList = NULL;
|
|
}
|
|
|
|
EXIT(3, ("FreellegalIOAddressList!\n"));
|
|
|
|
return;
|
|
}
|
|
|