📄 cphysmem.cpp
字号:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
CPhysMem::AllocateSpecialMemory(
IN const DWORD DEBUG_ONLY( dwSize ), // dwSize ignored in retail
OUT PUCHAR* const pVirtAddr )
{
DEBUGCHK( dwSize <= USBPAGESIZE );
DEBUGCHK( pVirtAddr != NULL );
// during suspend/resume this routine will be called again; we can safely
// leave the special memory set aside since we will always need the same amount.
if(!m_bSpecialTaken) {
m_bSpecialTaken = TRUE;
DEBUGCHK( m_dwSpecialPA == VaToPa( PUCHAR(m_dwSpecialVA) ) );
DEBUGCHK( m_dwSpecialPA % CPHYSMEM_MEMORY_ALIGNMENT == 0 );
}
*pVirtAddr = (PUCHAR) m_dwSpecialVA;
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE,(TEXT("CPhysMem AllocateMemory : bSpecial allocated\r\n")));
return(TRUE);
}
void
CPhysMem::FreeSpecialMemory(
IN const PUCHAR DEBUG_ONLY( virtAddr ) ) // virtAddr ignored in retail
{
DEBUGCHK( m_dwSpecialVA == (DWORD) virtAddr );
DEBUGCHK( m_bSpecialTaken );
m_bSpecialTaken = FALSE;
}
BOOL
CPhysMem::AllocateMemory(
DEBUG_PARAM( IN const TCHAR* pszMemDescription, ) // description of memory being alloc'd
IN const DWORD dwPassedInSize,
OUT PUCHAR* const pVirtAddr,
IN const DWORD dwFlags,
IN BOOL* pfRequestingAbort // = NULL
)
{
#ifdef DEBUG
DEBUGCHK( pszMemDescription != NULL );
DEBUGCHK( dwPassedInSize > 0 );
DEBUGCHK( pVirtAddr != NULL );
// for now, only the following sets of flags should be passed in
DEBUGCHK( dwFlags == 0 || // low priority, allow blocking
dwFlags == CPHYSMEM_FLAG_NOBLOCK || // low priority, no blocking
dwFlags == (CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK) ); // high pri, no blocking
if ( dwFlags & CPHYSMEM_FLAG_NOBLOCK ) {
// pfRequestingAbort will be ignored for NO_BLOCK transfers,
// so why is caller passing it in? Note that nothing
// bad will happen if pfRequestingAbort != NULL, so
// this check can be removed in the future if need be.
DEBUGCHK( pfRequestingAbort == NULL );
} else {
// blocking transfers must pass in a pointer
// for allowing the transfer to abort, and
// the original state of this abort request
// should be FALSE. If not, the blocking
// request is ignored.
DEBUGCHK( pfRequestingAbort != NULL &&
*pfRequestingAbort == FALSE );
}
#endif // DEBUG
PMEMLIST pNode = NULL;
const BOOL fHighPri = !!(dwFlags & CPHYSMEM_FLAG_HIGHPRIORITY);
const BOOL fNoBlock = !!(dwFlags & CPHYSMEM_FLAG_NOBLOCK);
// We keep our block sizes in multiples of CPHYSMEM_MEMORY_ALIGNMENT
DWORD dwSize = ( (dwPassedInSize - 1) & ~(CPHYSMEM_MEMORY_ALIGNMENT - 1) )
+ CPHYSMEM_MEMORY_ALIGNMENT;
DEBUGCHK( dwSize % CPHYSMEM_MEMORY_ALIGNMENT == 0 );
DEBUGCHK( dwSize - dwPassedInSize < CPHYSMEM_MEMORY_ALIGNMENT );
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE && (dwSize != dwPassedInSize),
(TEXT("AllocateMemory Desc = %s: (roundup %d->%d)\r\n"), pszMemDescription, dwPassedInSize, dwSize ));
EnterCriticalSection( &m_csLock );
DEBUGMSG( ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem: Heap pri = %d before allocation of %d bytes:\n"), fHighPri, dwSize ) );
VALIDATE_HEAPS(fHighPri);
//
// Scan the free list for the first chunk that's just big enough to satisfy
// this request. Remove from the free list. Chop it up (unless the result
// is less than CPHYSMEM_MEMORY_ALIGNMENT bytes). Then re-sort the remaining
// free chunk back into the free list and place the newly allocated chunk on
// the IN USE list.
//
pNode = FindFreeBlock(dwSize, fHighPri);
if ( pNode == NULL ) {
if ( fHighPri ) {
//
// Not available from High Priority region, try allocating from Normal region.
//
LeaveCriticalSection(&m_csLock);
DEBUGCHK( dwFlags == (CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK) );
return AllocateMemory( DEBUG_PARAM( pszMemDescription, )
dwPassedInSize,
pVirtAddr,
CPHYSMEM_FLAG_NOBLOCK, // dwFlags & ~CPHYSMEM_FLAG_HIGHPRIORITY,
pfRequestingAbort );
} else if ( !fNoBlock &&
pfRequestingAbort != NULL ) {
//
// Caller requested block for memory
//
#ifdef DEBUG
DWORD dwStartBlockTickCount = GetTickCount();
#endif // DEBUG
do {
LeaveCriticalSection(&m_csLock);
if ( *pfRequestingAbort == FALSE ) {
m_fHasBlocked = TRUE;
WaitForSingleObject(m_hFreeMemEvent, CPHYSMEM_BLOCK_FOR_MEM_INTERVAL );
if ( *pfRequestingAbort ) {
*pVirtAddr = NULL;
return FALSE;
}
// if this fails, we've been waiting for memory too long
DEBUGCHK( GetTickCount() - dwStartBlockTickCount < CPHYSMEM_DEBUG_MAXIMUM_BLOCK_TIME );
}
EnterCriticalSection(&m_csLock);
pNode = FindFreeBlock(dwSize, fHighPri);
} while ( pNode == NULL );
// rest of processing done below
} else {
DEBUGMSG( ZONE_WARNING, (TEXT("CPhysMem AllocateMemory : No memory available") ));
LeaveCriticalSection(&m_csLock);
*pVirtAddr = NULL;
return FALSE;
}
}
// case pNode == NULL should have been handled above
if ( pNode->dwSize - dwSize >= CPHYSMEM_MEMORY_ALIGNMENT) {
// There's enough left over to create a new block.
PMEMLIST pNodeNew = CreateNewNode(pNode->dwSize - dwSize,
pNode->dwVirtAddr + dwSize,
pNode->dwPhysAddr + dwSize);
#ifdef DEBUG
_tcscpy( pNodeNew->szDescription, pNode->szDescription );
#endif // DEBUG
AddNodeToFreeList(pNodeNew, fHighPri);
pNode->dwSize = dwSize; // remember to resize old block
}
#ifdef DEBUG
// add description to block
DEBUGCHK( _tcslen( pszMemDescription ) < CPHYSMEM_MAX_DEBUG_NODE_DESCRIPTION_LENGTH );
_tcscpy( pNode->szDescription, pszMemDescription );
// trash the memory before we return it to caller
memset( PUCHAR( pNode->dwVirtAddr ), GARBAGE, pNode->dwSize );
#endif // DEBUG
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem AllocateMemory : PA = 0x%08X, VA = 0x%08X, Size = %d, Desc = %s\r\n"),
pNode->dwPhysAddr, pNode->dwVirtAddr, pNode->dwSize, pNode->szDescription ) );
// mark this node used
InsertNodeBefore(pNode, FirstNode(INUSELIST(fHighPri)));
VALIDATE_HEAPS(fHighPri);
LeaveCriticalSection(&m_csLock);
DEBUGCHK( pNode->dwPhysAddr % CPHYSMEM_MEMORY_ALIGNMENT == 0 );
*pVirtAddr = PUCHAR( pNode->dwVirtAddr );
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
CPhysMem::FreeMemory(
IN const PUCHAR virtAddr,
IN const ULONG physAddr,
IN const DWORD dwFlags
)
{
// for now, only the following sets of flags should be passed in
DEBUGCHK( dwFlags == 0 || // low priority, allow blocking
dwFlags == CPHYSMEM_FLAG_NOBLOCK || // low priority, no blocking
dwFlags == (CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK) ); // high pri, no blocking
BOOL fRemoved = FALSE;
BOOL fHighPri = !!(dwFlags & CPHYSMEM_FLAG_HIGHPRIORITY);
// caller of FreeMemory is capable of calling
// PaToVa or VaToPa if they need to. Also,
// we shouldn't be called to free NULL memory.
DEBUGCHK( virtAddr != NULL && physAddr != 0 );
DEBUGCHK( virtAddr == PaToVa( physAddr ) );
DEBUGCHK( physAddr % CPHYSMEM_MEMORY_ALIGNMENT == 0 );
EnterCriticalSection(&m_csLock);
PMEMLIST pNode = FirstNode(INUSELIST(fHighPri));
DEBUGMSG( ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem: Heap pri = %d before free VA = 0x%08x:\n"), fHighPri, virtAddr ) );
VALIDATE_HEAPS(fHighPri);
//
// Walk the list looking for this block
//
while (!EndOfList(INUSELIST(fHighPri), pNode)) {
if ((pNode->dwVirtAddr == (DWORD) virtAddr) &&
(pNode->dwPhysAddr == (DWORD) physAddr)) {
#ifdef DEBUG
// trash this memory
DEBUGCHK( pNode->dwSize > 0 ); // otherwise, why are we calling FreeMemory??
memset( PUCHAR( pNode->dwVirtAddr ), GARBAGE, pNode->dwSize );
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE,
(TEXT("CPhysMem FreeMemory : PA = 0x%08X, VA = 0x%08X, Size = %d, Desc = %s\r\n"),
pNode->dwPhysAddr, pNode->dwVirtAddr, pNode->dwSize, pNode->szDescription ));
// change description
_tcscpy( pNode->szDescription, TEXT("Freed Memory") );
#endif // DEBUG
RemoveNode(pNode);
AddNodeToFreeList(pNode, fHighPri);
fRemoved = TRUE;
break;
}
pNode = pNode->next;
}
if (fHighPri && !fRemoved) {
LeaveCriticalSection(&m_csLock);
//
// Try removing from normal region.
//
DEBUGCHK( dwFlags == ( CPHYSMEM_FLAG_HIGHPRIORITY | CPHYSMEM_FLAG_NOBLOCK ) );
FreeMemory( virtAddr,
physAddr,
CPHYSMEM_FLAG_NOBLOCK ); // dwFlags & ~CPHYSMEM_FLAG_HIGHPRIORITY
return;
}
DEBUGCHK( fRemoved );
DEBUGMSG( ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem: Heap pri = %d after free VA = 0x%08x:\n"), fHighPri, virtAddr ) );
VALIDATE_HEAPS(fHighPri);
LeaveCriticalSection(&m_csLock);
//
// Signal everyone waiting for memory that some just became available.
//
if (m_fHasBlocked)
PulseEvent(m_hFreeMemEvent);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
CPhysMem::ReleaseBlockedCalls()
{
//
// Signal everyone waiting for memory to check if they have been aborted.
//
if (m_fHasBlocked)
PulseEvent(m_hFreeMemEvent);
return(TRUE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -