📄 cphysmem.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Module Name:
// CPhysMem.cpp
//
// Abstract:
// physical memory manager
//
// Notes:
//
#include "cphysmem.hpp"
typedef LPVOID * LPLPVOID;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
CPhysMem::CPhysMem(
DWORD cbSize,
DWORD cbHighPrioritySize,
PUCHAR pVirtAddr,
PUCHAR pPhysAddr
)
{
PMEMLIST pNode;
ASSERT(cbSize > 0 && cbHighPrioritySize > 0); // must be so or the driver cannot work.
//
// The PDD can pass in a physical buffer, or we'll try to allocate one from
// system RAM.
//
if (pVirtAddr && pPhysAddr) {
DEBUGMSG(ZONE_INIT,(TEXT("DMA buffer passed in from PDD\r\n")));
m_pPhysicalBufferAddr = pVirtAddr;
m_dwNormalVA = (DWORD) pVirtAddr;
m_dwNormalPA = (DWORD) pPhysAddr;
}
else {
DEBUGMSG(ZONE_INIT,(TEXT("Allocating DMA buffer from system RAM\r\n")));
#ifdef OSV_LOCAL_MERLIN
// This is a merlin build, but merlin doesn't have AllocPhysMem or FreePhysMem
// implemented. This shouldn't be a problem since this routine is normally
// called with non-null values in pVirtAddr & pPhysAddr. But, just to be sure,
// print a message and assert if this part of the code is executed.
RETAILMSG(1,(TEXT("CPhysMem::CPhysMem: AllocPhysMem not implemented.\r\n")));
ASSERT(0);
#else
m_pPhysicalBufferAddr = (PUCHAR)AllocPhysMem(cbSize,
PAGE_READWRITE|PAGE_NOCACHE,
0, // Default alignment
0, // Reserved
&m_dwNormalPA);
#endif
m_dwNormalVA = (DWORD) m_pPhysicalBufferAddr;
}
{ // we want all blocks to have their Phys Addr divisible by
// CPHYSMEM_MEMORY_ALIGNMENT. To achieve this, we start off
// having the physical memory block aligned properly, and
// then allocate memory only in blocks divisible by
// CPHYSMEM_MEMORY_ALIGNMENT
const DWORD dwOffset = m_dwNormalPA & (CPHYSMEM_MEMORY_ALIGNMENT - 1);
DEBUGCHK( dwOffset == m_dwNormalPA % CPHYSMEM_MEMORY_ALIGNMENT );
DEBUGCHK( cbSize > CPHYSMEM_MEMORY_ALIGNMENT );
if ( dwOffset != 0 ) {
// skip over the first few bytes of memory, as it is not
// aligned properly. This shouldn't happen though, because
// the new memory should have been aligned on a page boundary
DEBUGCHK( 0 );
// we can't code -= dwOffset because then we'll enter
// memory that we don't own.
m_dwNormalVA += CPHYSMEM_MEMORY_ALIGNMENT - dwOffset;
m_dwNormalPA += CPHYSMEM_MEMORY_ALIGNMENT - dwOffset;
cbSize -= CPHYSMEM_MEMORY_ALIGNMENT - dwOffset;
}
}
m_dwTotalPhysMemSize = cbSize;
m_PaVaConversion = m_dwNormalPA - m_dwNormalVA;
DEBUGMSG(ZONE_INIT,
(TEXT("CPhysMem Total Alloc Region PhysAddr = 0x%08X, VirtAddr = 0x%08X, size = %d\r\n"),
m_dwNormalPA, m_dwNormalVA, m_dwTotalPhysMemSize));
//
// Set aside a page for the special request.
//
m_dwSpecialVA = (DWORD) m_dwNormalVA;
m_dwSpecialPA = (DWORD) m_dwNormalPA;
m_dwNormalVA += USBPAGESIZE;
m_dwNormalPA += USBPAGESIZE;
cbSize -= USBPAGESIZE;
m_bSpecialTaken = FALSE;
memset((PVOID) m_dwSpecialVA, 0x00, USBPAGESIZE);
DEBUGMSG(ZONE_INIT,
(TEXT("CPhysMem Special Alloc Region PhysAddr = 0x%08X, VirtAddr = 0x%08X, size = %d\r\n"),
m_dwSpecialPA, m_dwSpecialVA, USBPAGESIZE));
//
// Set aside the High Priority region.
//
m_dwHighPriorityVA = (DWORD) m_dwNormalVA;
m_dwHighPriorityPA = (DWORD) m_dwNormalPA;
m_dwNormalVA += cbHighPrioritySize;
m_dwNormalPA += cbHighPrioritySize;
cbSize -= cbHighPrioritySize;
m_dwHighPrioritySize = cbHighPrioritySize;
memset((PVOID) m_dwHighPriorityVA, 0x00, m_dwHighPrioritySize);
DEBUGMSG(ZONE_INIT,
(TEXT("CPhysMem HighPri Alloc Region PhysAddr = 0x%08X, VirtAddr = 0x%08X, size = %d\r\n"),
m_dwHighPriorityPA, m_dwHighPriorityVA, m_dwHighPrioritySize));
//
// And the rest is for normal allocations.
//
m_dwNormalSize = cbSize;
memset((PVOID) m_dwNormalVA, 0x00, m_dwNormalSize);
DEBUGMSG(ZONE_INIT,
(TEXT("CPhysMem Normal Alloc Region PhysAddr = 0x%08X, VirtAddr = 0x%08X, size = %d\r\n"),
m_dwNormalPA, m_dwNormalVA, m_dwNormalSize));
m_hFreeMemEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_fHasBlocked = FALSE;
InitializeCriticalSection(&m_csLock);
EnterCriticalSection(&m_csLock);
//
// Create dummy entries for the list head (simpler linked list code)
//
m_pNodeFreeListHead = CreateNewNode(0, 0, 0);
InitializeListHead(m_pNodeFreeListHead);
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem Init : NodeFreeListHead = 0x%08X\r\n"),
m_pNodeFreeListHead));
m_pFreeListHead = CreateNewNode(0, 0, 0);
InitializeListHead(m_pFreeListHead);
m_pInUseListHead = CreateNewNode(0, 0, 0);
InitializeListHead(m_pInUseListHead);
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem Init : FreeListHead = 0x%08X, InUseListHead = 0x%08X\r\n"), m_pFreeListHead, m_pInUseListHead));
m_pHighPriorityFreeListHead = CreateNewNode(0, 0, 0);
InitializeListHead(m_pHighPriorityFreeListHead);
m_pHighPriorityInUseListHead = CreateNewNode(0, 0, 0);
InitializeListHead(m_pHighPriorityInUseListHead);
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem Init : HighPriFreeListHead = 0x%08X, HighPriInUseListHead = 0x%08X\r\n"),
m_pHighPriorityFreeListHead, m_pHighPriorityInUseListHead));
//
// One big chunk on the free list to start things off.
//
pNode = CreateNewNode(m_dwNormalSize, m_dwNormalVA, m_dwNormalPA);
#ifdef DEBUG
_tcscpy( pNode->szDescription, TEXT("Free Low Pri Mem") );
#endif // DEBUG
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem Init : Main Free Heap Node = 0x%08X\r\n"),
pNode));
InsertNodeBefore(pNode, FirstNode(m_pFreeListHead));
VALIDATE_HEAPS(FALSE);
//
// Same thing for High Priority Region
//
pNode = CreateNewNode(m_dwHighPrioritySize, m_dwHighPriorityVA, m_dwHighPriorityPA);
#ifdef DEBUG
_tcscpy( pNode->szDescription, TEXT("Free High Pri Mem") );
#endif // DEBUG
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem Init : HighPri Free Heap Node = 0x%08X\r\n"),
pNode));
InsertNodeBefore(pNode, FirstNode(m_pHighPriorityFreeListHead));
VALIDATE_HEAPS(TRUE);
LeaveCriticalSection(&m_csLock);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
#ifdef DEBUG
BOOL
CPhysMem::ValidateHeaps(BOOL fHighPri)
{
PMEMLIST pNode = FirstNode(FREELIST(fHighPri));
DWORD dwSizeTotal = 0;
DWORD dwSizePrev = 0;
DWORD dwSizeFree = 0;
DWORD dwNodesFree = 0;
while (!EndOfList(FREELIST(fHighPri), pNode)) {
DEBUGMSG(ZONE_VERBOSE && ZONE_CPHYSMEM, (TEXT("FreeList(pri = %d) : pNode size = %4d, PA = 0x%08x, VA = 0x%08X, Desc = %s\r\n"),
fHighPri, pNode->dwSize, pNode->dwPhysAddr, pNode->dwVirtAddr, pNode->szDescription ));
if ( pNode->dwSize == 0 ) {
DEBUGCHK( pNode->dwVirtAddr == 0 &&
pNode->dwPhysAddr == 0 );
} else {
DEBUGCHK( pNode->dwSize % CPHYSMEM_MEMORY_ALIGNMENT == 0 &&
pNode->dwPhysAddr % CPHYSMEM_MEMORY_ALIGNMENT == 0 &&
PUCHAR(pNode->dwVirtAddr) == PaToVa( pNode->dwPhysAddr ) );
}
dwSizeTotal += pNode->dwSize;
dwSizeFree += pNode->dwSize;
if (dwSizePrev > pNode->dwSize) {
DEBUGMSG(ZONE_ERROR, (TEXT("CPhysMem ValidateHeaps : Free List not sorted (%d > %d)\r\n"),
dwSizePrev, pNode->dwSize));
DEBUGCHK(0);
return(FALSE);
}
if ((pNode->next->prev != pNode) || (pNode->prev->next != pNode)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CPhysMem ValidateHeaps : Invalid linked list (free)\r\n")));
DEBUGCHK(0);
return(FALSE);
}
dwSizePrev = pNode->dwSize;
pNode = pNode->next;
}
pNode = FirstNode(INUSELIST(fHighPri));
while (!EndOfList(INUSELIST(fHighPri), pNode)) {
DEBUGMSG(ZONE_VERBOSE && ZONE_CPHYSMEM, (TEXT("InUseList(pri = %d) : pNode size = %4d, PA = 0x%08x, VA = 0x%08X, Desc = %s\r\n"),
fHighPri, pNode->dwSize, pNode->dwPhysAddr, pNode->dwVirtAddr, pNode->szDescription ));
if ( pNode->dwSize == 0 ) {
DEBUGCHK( pNode->dwVirtAddr == 0 &&
pNode->dwPhysAddr == 0 );
} else {
DEBUGCHK( pNode->dwSize % CPHYSMEM_MEMORY_ALIGNMENT == 0 &&
pNode->dwPhysAddr % CPHYSMEM_MEMORY_ALIGNMENT == 0 &&
PUCHAR(pNode->dwVirtAddr) == PaToVa( pNode->dwPhysAddr ) );
}
dwSizeTotal += pNode->dwSize;
if ((pNode->next->prev != pNode) || (pNode->prev->next != pNode)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CPhysMem ValidateHeaps : Invalid linked list (inuse)\r\n")));
DEBUGCHK(0);
return(FALSE);
}
pNode = pNode->next;
}
DEBUGMSG(ZONE_CPHYSMEM && ZONE_VERBOSE, (TEXT("CPhysMem ValidateHeaps : FreeSize = %d bytes; TotalSize = %d bytes\r\n"),
dwSizeFree, dwSizeTotal));
if (dwSizeTotal != (fHighPri ? m_dwHighPrioritySize : m_dwNormalSize)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CPhysMem ValidateHeaps : We've lost some memory somewhere\r\n")));
DEBUGCHK(0);
return(FALSE);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -