📄 iorm.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include <windows.h>
#include "iormif.h"
#include "devzones.h"
#ifdef _PREFAST_
#ifdef DEBUGCHK
#undef DEBUGCHK
#endif // DEBUGCHK
#define DEBUGCHK(exp) PREFAST_ASSUME(exp)
#endif // _PREFAST_
// More than this many distinct resources of a given type need to be represented by a
// sparse table; less than (or equal to) this many can be represented by a bit vector.
// This type of resource is typically used to represent IRQs -- a fixed table size of
// 64 should be sufficient since CE currently limits the number of SysIntrs.
#define DEF_TABLE_THRESHOLD 64
typedef struct {
DWORD id;
DWORD len;
} ResourceRange;
typedef struct SparseTableNode {
ResourceRange res;
struct SparseTableNode *pNext;
} SparseTableNode;
typedef struct {
SparseTableNode *pFirst;
} SparseTable;
typedef struct {
DWORD dwResMax; // max resource index
PDWORD prvValid; // even dense resource lists can have holes
PDWORD prvShareable; // indicates which resources are shareable
PDWORD prvExclusive; // indicates resources that are requested for exclusive access
PUSHORT pUseCount; // records the number of resource users
} DenseTable;
typedef struct {
DWORD dwSize;
union {
SparseTable st;
DenseTable dt;
};
} ResourceTable;
typedef struct ResourceDomain {
DWORD dwResId; // identifies the resource type
DWORD dwOffset; // minimum value for dwId
ResourceTable table;
struct ResourceDomain *pNext;
} ResourceDomain;
// -- forward declarations --
#ifdef DEBUG
void ResourceDump (ResourceDomain *);
void ResourceDumpAll (void);
#endif
// A list of available resource domains from which resources can be allocated,
// and a way to protect it for thread-safety.
static ResourceDomain *g_DomainList;
static CRITICAL_SECTION gcsIORM;
static DWORD gdwMaxDenseResources;
// This routine initializes an array of resource bitmasks. The bitmask vector
// is an array of 32-bit DWORDs. The max value is 0-relative and inclusive, so
// we add one to get the number of elements.
static void
RBMInit(DWORD dwResMax, PDWORD pdwMask, BOOL fSet)
{
DWORD dwSize;
DEBUGCHK(pdwMask != NULL);
// convert to byte count
dwSize = (dwResMax + 1) / 8;
// set or clear bits in the vector
memset(pdwMask, fSet ? 0xFF : 0x00, dwSize);
}
// This routine tests whether a particular bit is set in a resource bitmask vector
// and returns TRUE if it is.
static BOOL
RBMIsSet(DWORD dwResMax, DWORD dwElement, PDWORD pdwMask)
{
DWORD dwIndex;
BOOL fIsSet;
DEBUGCHK(dwElement <= dwResMax);
DEBUGCHK(pdwMask != NULL);
// convert the element into a bit and an offset
dwIndex = dwElement / 32;
dwElement %= 32;
// is the bit set in the mask?
if((pdwMask[dwIndex] & (1 << dwElement)) != 0) {
fIsSet = TRUE;
} else {
fIsSet = FALSE;
}
return fIsSet;
}
// this routine sets a bit in a resource bitmask vector
static void
RBMSet(DWORD dwResMax, DWORD dwElement, PDWORD pdwMask)
{
DWORD dwIndex;
DEBUGCHK(dwElement <= dwResMax);
DEBUGCHK(pdwMask != NULL);
// convert the element into a bit and an offset
dwIndex = dwElement / 32;
dwElement %= 32;
// is the bit set in the mask?
pdwMask[dwIndex] |= (1 << dwElement);
}
// this routine clears a bit in a resource bitmask vector
static void
RBMClear(DWORD dwResMax, DWORD dwElement, PDWORD pdwMask)
{
DWORD dwIndex;
DEBUGCHK(dwElement <= dwResMax);
DEBUGCHK(pdwMask != 0);
// convert the element into a bit and an offset
dwIndex = dwElement / 32;
dwElement %= 32;
// is the bit set in the mask?
pdwMask[dwIndex] &= ~(1 << dwElement);
}
static ResourceDomain *FindDomain (DWORD dwResId)
{
ResourceDomain *pdom;
pdom = g_DomainList;
for (; pdom; pdom = pdom->pNext)
if (pdom->dwResId == dwResId)
break;
return pdom;
}
static DWORD SetDenseResources (DenseTable *ptab, DWORD dwId, DWORD dwLen, BOOL fClaim, DWORD dwFlags)
{
DWORD dwTrav, dwCount;
DEBUGCHK(ptab);
DEBUGCHK(dwId >= 0);
DEBUGCHK(dwLen > 0);
DEBUGCHK(dwId <= ptab->dwResMax);
DEBUGCHK((dwId + (dwLen - 1)) <= ptab->dwResMax);
DEBUGCHK(dwFlags == 0 || fClaim);
if(fClaim) {
BOOL fExclusive;
// are we requesting exclusive access to a shared resource?
if((dwFlags & RREXF_REQUEST_EXCLUSIVE) != 0) {
fExclusive = TRUE;
} else {
fExclusive = FALSE;
}
// make sure that nobody has claimed any non-shareable resources
for(dwTrav = dwId, dwCount = 0; dwCount < dwLen; dwTrav++, dwCount++) {
if(! RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvValid)) {
// resource isn't valid and can't be allocated
return ERROR_INVALID_PARAMETER;
}
if(ptab->pUseCount[dwTrav] != 0) {
if(! RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvShareable)
|| fExclusive
|| RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvExclusive)) {
// the resource is in use but it's (a) not shareable, or (b) we
// want it exclusively, or (c) whoever has it wants it exclusively.
return ERROR_BUSY;
}
}
}
// now allocate the resource
for(dwTrav = dwId, dwCount = 0; dwCount < dwLen; dwTrav++, dwCount++) {
ptab->pUseCount[dwTrav]++;
if(fExclusive) {
DEBUGCHK(ptab->pUseCount[dwTrav] == 1);
RBMSet(ptab->dwResMax, dwTrav, ptab->prvExclusive);
}
}
} else {
// validate the resource or make sure it has been allocated -- do this
// in two passes so we don't get partially released resources
for(dwTrav = dwId, dwCount = 0; dwCount < dwLen; dwTrav++, dwCount++) {
if(!RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvValid)) {
DEBUGCHK(ptab->pUseCount[dwTrav] == 0xAFAF);
} else {
if(ptab->pUseCount[dwTrav] == 0) {
return ERROR_INVALID_PARAMETER;
}
}
}
// validate the resource and/or free it by reducing its reference count
for(dwTrav = dwId, dwCount = 0; dwCount < dwLen; dwTrav++, dwCount++) {
if(!RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvValid)) {
DEBUGCHK(!RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvExclusive));
RBMSet(ptab->dwResMax, dwTrav, ptab->prvValid);
ptab->pUseCount[dwTrav] = 0;
} else {
DEBUGCHK(ptab->pUseCount[dwTrav] != 0);
if(RBMIsSet(ptab->dwResMax, dwTrav, ptab->prvExclusive)) {
DEBUGCHK(ptab->pUseCount[dwTrav] == 1);
RBMClear(ptab->dwResMax, dwTrav, ptab->prvExclusive);
}
ptab->pUseCount[dwTrav]--;
}
}
}
return ERROR_SUCCESS;
}
static DWORD SetSparseResources (SparseTable *ptab, DWORD dwId, DWORD dwLen, BOOL fClaim, DWORD dwFlags)
{
SparseTableNode **ppnod, *pnod;
DEBUGCHK(dwFlags == 0 || fClaim);
if(dwFlags != 0) {
DEBUGMSG(ZONE_WARNING, (_T("SetSparseResources: flags value 0x%08x not supported\r\n"), dwFlags));
return ERROR_NOT_SUPPORTED;
}
for (pnod = *(ppnod = &ptab->pFirst); pnod != NULL; pnod = *(ppnod = &pnod->pNext))
if (fClaim) {
if (pnod->res.id <= dwId && pnod->res.id + pnod->res.len - 1 >= dwId)
break;
}
else {
if (pnod->res.id + pnod->res.len > dwId && pnod->res.id < dwId + dwLen)
return ERROR_INVALID_PARAMETER; // requested range includes available resources! (serious caller error)
if (pnod->res.id >= dwId + dwLen || pnod->res.id + pnod->res.len == dwId)
break;
}
if (fClaim) {
// make sure the resources are free so we can claim them
if (pnod == NULL)
return ERROR_INVALID_PARAMETER; // dwId is unavailable
if (dwId + dwLen > pnod->res.id + pnod->res.len)
return ERROR_BUSY; // some subset of the range is unavailable
// OK, we can claim. Now adjust the list. There are several cases.
ASSERT(pnod->res.len >= dwLen);
if (pnod->res.len == dwLen) {
// delete the entire current range
ASSERT(pnod->res.id == dwId);
*ppnod = pnod->pNext;
LocalFree(pnod);
}
else if (pnod->res.id == dwId) {
pnod->res.id += dwLen;
pnod->res.len -= dwLen;
}
else if (pnod->res.id + pnod->res.len == dwId + dwLen) {
pnod->res.len -= dwLen;
}
else {
// we have to split the current resource range
SparseTableNode *newnod = LocalAlloc(0, sizeof(*newnod));
if (newnod == NULL)
return ERROR_NOT_ENOUGH_MEMORY; // OOM!
newnod->res.id = dwId + dwLen;
newnod->res.len = pnod->res.id + pnod->res.len - newnod->res.id;
newnod->pNext = pnod->pNext;
pnod->pNext = newnod;
pnod->res.len -= dwLen + newnod->res.len;
}
}
else {
// make sure the resources are claimed so we can free them
if (pnod == NULL) {
// case 6 or 7 (same as case 1 or 3)
mknew: {
SparseTableNode *newnod = LocalAlloc(0, sizeof(*newnod));
if (newnod == NULL)
return ERROR_NOT_ENOUGH_MEMORY; // OOM!
newnod->res.id = dwId;
newnod->res.len = dwLen;
newnod->pNext = pnod;
*ppnod = newnod;
}}
else if (pnod->res.id + pnod->res.len == dwId) {
// case 2 or 5
SparseTableNode *pnxt = pnod->pNext;
if (pnxt && pnxt->res.id < dwId + dwLen)
return ERROR_INVALID_PARAMETER; // cannot free resources already available!
pnod->res.len += dwLen;
if (pnxt && pnxt->res.id == dwId + dwLen) {
// case 5
pnod->res.len += pnxt->res.len;
pnod->pNext = pnxt->pNext;
LocalFree(pnxt);
}
}
else if (pnod->res.id == dwId + dwLen) {
// case 4
pnod->res.id -= dwLen;
pnod->res.len += dwLen;
}
else {
ASSERT(dwId + dwLen < pnod->res.id);
// case 1 or 3
goto mknew; // see case 6 or 7
}
}
return ERROR_SUCCESS;
}
BOOL IORM_ResourceMarkAsShareable(DWORD dwResId, DWORD dwId, DWORD dwLen, BOOL fShareable)
{
ResourceDomain *pdom;
DWORD size, min;
DWORD dwTrav, dwCount;
DWORD dwError = ERROR_INVALID_PARAMETER;
BOOL fOk;
DEBUGMSG(ZONE_RESMGR, (_T("IORM: marking 0x%x resources at 0x%08x as %s in list 0x%08x\r\n"),
dwLen, dwId, fShareable ? _T("shareable") : _T("unshareable"), dwResId));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -