?? mem.cpp
字號:
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CPhysMem::~CPhysMem()
{
DeleteCriticalSection(&m_csLock);
CloseHandle(m_hFreeMemEvent);
FreeList(&m_pInUseListHead);
FreeList(&m_pFreeListHead);
FreePhysicalMemory(m_pPhysicalBufferAddr, m_dwTotalPhysMemSize);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
EError CPhysMem::FreeList(PMEMLIST *ppHead)
{
PMEMLIST pCurrent = *ppHead;
PMEMLIST pNext;
while (pCurrent != NULL)
{
pNext = pCurrent->next;
OHCD_Free(pCurrent);
pCurrent = pNext;
}
*ppHead = NULL;
return(successful);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
EError
CPhysMem::AllocateMemory(
UINT size,
PUCHAR* pVirtAddr,
ULONG* pPhysAddr,
DWORD dwFlags,
BOOL* pfRequestingAbort
)
{
//
// 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 8 bytes). Then re-sort the remaining free chunk back into the
// free list and place the newly allocated chunk on the IN USE list.
//
PMEMLIST pNode;
PMEMLIST pNodeNew;
BOOL fHighPri = ((dwFlags & USBALLOCF_HIGHPRIORITY) == USBALLOCF_HIGHPRIORITY);
if (dwFlags & USBALLOCF_SPECIAL) {
ASSERT(!m_bSpecialTaken);
*pVirtAddr = (PUCHAR) m_dwSpecialVA;
*pPhysAddr = (ULONG) m_dwSpecialPA;
m_bSpecialTaken = TRUE;
DEBUGMSG(ZONE_FUNCTION,(TEXT("OHCD : AllocateMemory : bSpecial allocated\r\n")));
return(successful);
}
//
// We keep our block sizes in multiples of 8. Round up to next 8.
//
if (size != 0) {
DWORD dwOldSize = size;
size = ((size-1) & ~(8-1)) + 8;
DEBUGMSG((dwOldSize != size) && ZONE_VERBOSE && ZONE_FUNCTION,
(TEXT("AllocateMemory: (roundup %d->%d)\r\n"), dwOldSize, size));
}
EnterCriticalSection(&m_csLock);
VALIDATE_HEAPS(fHighPri);
ASSERT(size <= USBPAGESIZE && TEXT("Nonsupported memory size"));
pNode = FindFreeBlock(size, fHighPri);
if ( pNode == NULL ) {
if ( fHighPri ) {
//
// Not available from High Priority region, try allocating from Normal region.
//
LeaveCriticalSection(&m_csLock);
return (AllocateMemory(size, pVirtAddr, pPhysAddr, USBALLOCF_NOBLOCK, NULL));
} else if ( !(dwFlags & USBALLOCF_NOBLOCK) ) {
//
// There are no free blocks available. Wait until there are.
//
DEBUGMSG(ZONE_ALLOC | ZONE_WARNING, (TEXT("OHCD : No memory block available for allocation... waiting\r\n")));
#ifdef DEBUG
const DWORD dwTickCountStart = GetTickCount();
#endif // DEBUG
BOOL fRequestingAbort = FALSE;
if (pfRequestingAbort == NULL) {
DEBUGMSG( ZONE_WARNING, (TEXT("OHCD: Warning - Block for memory requested with no method for aborting!\n")) );
//
// The default is to pass in a NULL pointer, so let's use our
// own local BOOLEAN.
//
pfRequestingAbort = &fRequestingAbort;
}
do {
LeaveCriticalSection(&m_csLock);
if (*pfRequestingAbort == FALSE) {
//
// We start operating in "slow mode". See the class defn.
//
m_fHaveWaited = TRUE;
//
// Event will be signaled whenever memory is freed
//
WaitForSingleObject(m_hFreeMemEvent, 60000);
//
// Has this request been cancelled? Get out now.
//
if (*pfRequestingAbort) {
return(aborted);
}
}
//
// Shouldn't have been waiting for memory this long
//
DEBUGCHK( GetTickCount() - dwTickCountStart < 10000 );
EnterCriticalSection(&m_csLock);
pNode = FindFreeBlock(size, fHighPri);
} while ( pNode == NULL );
} else {
//
// No mem available, Fail
//
LeaveCriticalSection(&m_csLock);
*pVirtAddr = NULL;
return outOfMemory;
}
}
// pNode == NULL should have been handled above
DEBUGCHK( pNode != NULL );
if ((pNode->dwSize - size) >= 8) {
//
// There's enough left over to create a new block.
//
DWORD dwNewSize = pNode->dwSize - size;
pNodeNew = CreateNewNode(dwNewSize, pNode->dwVirtAddr + size,
pNode->dwPhysAddr + size);
AddNodeToFreeList(pNodeNew, fHighPri);
pNode->dwSize = size;
}
InsertNodeBefore(pNode, FirstNode(INUSELIST(fHighPri)));
*pVirtAddr = (PUCHAR) pNode->dwVirtAddr;
*pPhysAddr = (ULONG) pNode->dwPhysAddr;
DEBUGMSG(ZONE_FUNCTION, (TEXT("OHCD : AllocateMemory : VA = 0x%08X, PA = 0x%08X, size = %d\r\n"),
*pVirtAddr, *pPhysAddr, size));
VALIDATE_HEAPS(fHighPri);
LeaveCriticalSection(&m_csLock);
return(successful);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
EError
CPhysMem::FreeMemory(
PUCHAR virtAddr,
ULONG physAddr,
DWORD dwFlags
)
{
BOOL fRemoved = FALSE;
BOOL fHighPri = ((dwFlags & USBALLOCF_HIGHPRIORITY) == USBALLOCF_HIGHPRIORITY);
//
// take it out of the IN USE list and sort it (coalesce) in the free list.
//
if (dwFlags & USBALLOCF_SPECIAL) {
m_bSpecialTaken = FALSE;
return(successful);
}
if (virtAddr == NULL && physAddr == 0)
{
return(error);
}
if (physAddr == 0)
{
physAddr = VaToPa(virtAddr);
}
else if (virtAddr == NULL)
{
virtAddr = PaToVa(physAddr);
}
EnterCriticalSection(&m_csLock);
PMEMLIST pNode = FirstNode(INUSELIST(fHighPri));
VALIDATE_HEAPS(fHighPri);
//
// Walk the list looking for this block
//
while (!EndOfList(INUSELIST(fHighPri), pNode)) {
if ((pNode->dwVirtAddr == (DWORD) virtAddr) &&
(pNode->dwPhysAddr == (DWORD) physAddr)) {
RemoveNode(pNode);
AddNodeToFreeList(pNode, fHighPri);
fRemoved = TRUE;
break;
}
pNode = pNode->next;
}
if (fHighPri && !fRemoved) {
LeaveCriticalSection(&m_csLock);
//
// Try removing from normal region.
//
return(FreeMemory(virtAddr, physAddr, 0));
}
VALIDATE_HEAPS(fHighPri);
DEBUGMSG(ZONE_FUNCTION,
(TEXT("OHCD : FreeMemory : VA = 0x%08X, PA = 0x%08X, flags = 0x%08X\r\n"),
virtAddr, physAddr, dwFlags));
LeaveCriticalSection(&m_csLock);
//
// Signal everyone waiting for memory that some just became available.
//
if (m_fHaveWaited)
PulseEvent(m_hFreeMemEvent);
return(successful);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
EError
CPhysMem::ReleaseBlockedCalls()
{
//
// Signal everyone waiting for memory to check if they have been aborted.
//
if (m_fHaveWaited)
PulseEvent(m_hFreeMemEvent);
return(successful);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL FreePhysicalMemory(LPVOID lpMemory, UINT cbSize)
{
UnlockPages(lpMemory, cbSize);
VirtualFree(lpMemory,0, MEM_RELEASE);
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID AllocatePhysicalMemory(UINT cbSize, LPULONG ppaBuffer)
{
LPVOID pBuffer = NULL;
LPVOID pLastBuffer;
LPVOID pNextBuffer;
ULONG paBuffer = 0;
BOOL fDone;
BOOL fResult;
//let's first find the maximum # of pages that could be locked
UINT cPages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(NULL, cbSize);
//allocate an array for the maximum # of pages
PULONG aPages = new ULONG[cPages];
// we need to allocate at least 1 byte
if(cbSize == 0)
cbSize = 1;
do
{
fDone = TRUE;
pLastBuffer = pBuffer;
pBuffer = VirtualAlloc(NULL, cbSize,
MEM_COMMIT, PAGE_NOCACHE | PAGE_READWRITE);
// our allocated block had better be on a page boundary!
ASSERT(((DWORD)pBuffer & (PAGE_SIZE - 1)) == 0);
DEBUGMSG(ZONE_ALLOC,
(TEXT("Allocated possibly continuous memory block: %%08X\r\n"),
pBuffer));
if(pBuffer)
{
fResult = LockPages(pBuffer, cbSize, aPages, LOCKFLAG_WRITE);
if(fResult)
{
PULONG pPage;
ASSERT(cPages ==
ADDRESS_AND_SIZE_TO_SPAN_PAGES(pBuffer, cbSize));
pPage = aPages;
// We want page numbers and NK gives us the physical address
// of each page, adjust the list. Except on MIPS where NK
// gives us the physical address shifted right 6 bits.
for(UINT i = 0 ; i < cPages ; ++i)
{
#if defined(MIPS)
#if defined(R4000) | defined(R5230)
#if defined(R4100)
*pPage >>= PAGE_SHIFT - 4;
#else
*pPage >>= PAGE_SHIFT - 6;
#endif
#else
*pPage >>= PAGE_SHIFT;
#endif
#elif defined(SHx) | defined(x86) | defined(PPC) | defined(ARM)
*pPage >>= PAGE_SHIFT;
#else
#error Unsupported Processor
#endif
++pPage;
}
pPage = aPages;
ASSERT(cPages > 0);
for(i = 0 ; i < cPages - 1 && fDone ; ++i)
{
if(*pPage + 1 != *(pPage + 1))
fDone = FALSE;
++pPage;
}
if(fDone)
paBuffer = *aPages << PAGE_SHIFT;
}
if(!fDone)
*(LPLPVOID)pBuffer = pLastBuffer;
}
} while(!fDone);
while(pLastBuffer)
{
pNextBuffer = *(LPLPVOID)pLastBuffer;
UnlockPages(pLastBuffer, cbSize);
VirtualFree(pLastBuffer,0, MEM_RELEASE);
pLastBuffer = pNextBuffer;
}
// our allocated block had better be on a page boundary or we will miss
// part of the physical address and the interrupt table will not be aligned!
ASSERT(((DWORD)pBuffer & (PAGE_SIZE - 1)) == 0);
ASSERT(ppaBuffer);
*ppaBuffer = paBuffer;
ASSERT((*ppaBuffer & (PAGE_SIZE - 1)) == 0);
if(aPages)
delete[] aPages;
DEBUGMSG(ZONE_INIT|ZONE_ALLOC,
(TEXT("OHCD:AllocatePhysicalMemory Continuous memory block VA: %08X PA:%08X \r\n"), pBuffer, *ppaBuffer));
return pBuffer;
}
#ifdef DEBUG
EError CPhysMem::DebugAllocateMemory(UINT size, PUCHAR * pVirtAddr,
ULONG *pPhysAddr, DWORD dwFlags, BOOL * pfRequestingAbort,
TCHAR *szFile, DWORD dwLine)
{
EError err;
err = AllocateMemory(size, pVirtAddr, pPhysAddr, dwFlags, pfRequestingAbort);
DEBUGMSG(ZONE_ALLOC,
(TEXT("OHCD: ALLOC!!!!! Block at VA = 0x%08X, PA = 0x%08X, size = %d was allocated in File: %s, Line #: %ld \r\n"),
*pVirtAddr, *pPhysAddr, size, szFile, dwLine));
return err;
}
EError CPhysMem::DebugFreeMemory(PUCHAR virtAddr, ULONG physAddr, DWORD dwFlags,
TCHAR *szFile, DWORD dwLine)
{
EError err;
err = FreeMemory(virtAddr, physAddr, dwFlags);
if (physAddr == 0)
{
if(virtAddr)
physAddr = VaToPa(virtAddr);
}
else if (virtAddr == NULL)
{
if(physAddr)
virtAddr = PaToVa(physAddr);
}
DEBUGMSG(ZONE_ALLOC,
(TEXT("OHCD: FREE!!!!!! Block at VA = 0x%08X, PA = 0x%08X, flags = 0x%08X was freed in File: %s, Line #: %ld \r\n"),
virtAddr, physAddr, dwFlags, szFile, dwLine));
return err;
}
#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -