📄 virtual.c
字号:
*lpuiDstPage = dwPhy | dwProtect;
//更新页表-2005-02-03
if( bWriteToSecondPage &&
PAGE_IN_RANGE( uStartPage, uMinPage, uMaxPage) )
{
lpProcessSeg->lpdwSecondPageTable[uStartPage] = *lpuiDstPage;
}
uStartPage++;
//
// 下一页
lpuiDstPage++;
lpuiSrcPage++;
idxStartPage++;
dwCopyPages--;
}
idxStartPage = 0;
}
return dwCopyPages ? FALSE : TRUE;
}
// ********************************************************************
// 声明:static LPVOID DoVirtualAlloc(
// LPVOID lpvAddress,
// DWORD dwSize,
// DWORD dwAllocType,
// DWORD dwProtect,
// DWORD * lpdwPhycialPages )
// 参数:
// IN lpvAddress - 虚地址
// IN dwSize - 需要分配的大小(以byte为单位)
// IN uiAllocType - 分配类型,为以下值的组合:
// MEM_RESERVE - 保留虚地址
// MEM_COMMIT - 提交物理页
//
// MEM_PHYSICAL - lpdwPhycialPages 包含物理页,如果没有MEM_CONTIGUOUS属性,
// 则 lpdwPhycialPages[n] 包含第n个物理页。
// 如果没有该属性,则由该函数分配物理页
// MEM_CONTIGUOUS - 物理页是连续的,并且lpdwPhycialPages本身表示物理页地址的开始
// IN dwProtect - 保护属性
// IN lpdwPhycialPages - 指向物理页或物理页地址(依赖于uiAllocType)。
// 返回值:
// 假如成功,返回非NULL指针;否则返回NULL
// 功能描述:
// 分配用户虚地址,假如uiAllocType有MEM_COMMIT但没有MEM_RESERVE,则该地址范围必须是之前已经被保留的
// 引用:
//
// ********************************************************************
#define DEBUG_DOVIRTUALALLOC 0
static LPVOID DoVirtualAlloc(
LPVOID lpvAddress,
DWORD dwSize,
DWORD dwAllocType,
DWORD dwProtect,
DWORD * lpdwPhycialPages )
{
DWORD dwStart = (DWORD)lpvAddress;
DWORD dwEnd = dwStart + dwSize;
DWORD dwSegIndex = GET_SEGMENT_INDEX( dwStart );
LPSEGMENT lpSeg;
LPPROCESS_SEGMENTS lpProcessSeg;
DWORD dwError = 0;
DWORD dwRetv = NULL;
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtualAlloc:lpvAddress=%x,dwSize=%d.\r\n", lpvAddress,dwSize ) );
// 检查参数,check param
if( (dwAllocType & MEM_PHYSICAL) && lpdwPhycialPages == NULL )
{
KL_SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
KL_EnterCriticalSection( &csVirtualMem );
if( dwSize )
{
if( ( lpProcessSeg = Seg_FindProcessSegment( dwStart ) ) &&
( lpSeg = lpProcessSeg->lpSeg ) ) // 查找对应的段
{
int iNeedPages;
int iPages;
int idxFirst, idxCommit, idxCommitPage;
BOOL bReserved = FALSE;
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtualAlloc:lpSeg=%x.\r\n", lpSeg ) );
idxFirst = -1;
//是否需要做保留工作 ?
if( (dwAllocType & MEM_RESERVE) ||
( lpvAddress == NULL && (dwAllocType & MEM_COMMIT) )
)
{ // 需要去保留相应的页 to get enough free block( NULL_BLOCK )
// 需要的页数
iPages = iNeedPages = ( ( dwStart + dwSize + PAGE_SIZE - 1 ) / PAGE_SIZE ) - ( dwStart / PAGE_SIZE );
dwAllocType |= MEM_RESERVE;
idxFirst = 0;
if( dwSegIndex )
{
dwStart &= SEGMENT_MASK; // 32M size
}
if( dwStart ) // 用户指定地址 ?
{ // 是
dwStart &= 0xffff0000; // 下舍到64k边界 round down 64k
idxFirst = BLOCK_INDEX( dwStart );
}
else // 否,从1块开始(0块系统保留)
idxFirst = 1; // first block reserved by sys
// search enough blocks
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:idxFirst=%d,iNeedPages=%d.\r\n", idxFirst, iNeedPages ) );
//得到内存域的开始块
idxCommit = idxFirst = Seg_GetFirstBlockPos( lpSeg, idxFirst, iNeedPages, dwStart == NULL );
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:Reserve idxFirst=%d.\r\n", idxFirst ) );
// 保留需要的页
if( idxFirst &&
Seg_ReserveNeedPages( lpSeg, idxFirst, iNeedPages, (dwAllocType & MEM_AUTO_COMMIT), dwProtect ) )
{ // now to reserve
bReserved = TRUE;
dwStart = idxFirst << BLOCK_SHIFT;
}
else
{
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc: failuer to ReserveNeedPages(%d), idxFirst(%d), dwStart(0x%x).\r\n", iNeedPages, idxFirst, dwStart ) );
dwError = ERROR_NOT_ENOUGH_MEMORY;
goto _err_return;
}
}
else if( dwStart && (dwAllocType & MEM_COMMIT) )
{ // 直接提交物理页,to commit blocks which have reserved
idxCommit = idxFirst = BLOCK_INDEX( dwStart ); // 开始块
// align to page
//需要的页数
iNeedPages = ( ( dwStart + dwSize + PAGE_SIZE - 1 ) / PAGE_SIZE ) - ( dwStart / PAGE_SIZE );
dwStart &= ~PAGE_MASK;
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:dwStart=%x,idxFirst=%d.\r\n", dwStart, idxFirst ) );
//得到该域的开始块
idxFirst = Seg_SearchFirstBlock( lpSeg, idxFirst );
if( idxFirst == NOT_FIND_FIRST )
{ // 给的地址是无效的,error param
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "warn in DoVirtaulAlloc:NOT_FIND_FIRST,idxFirst=%d.\r\n", idxFirst ) );
// ASSERT( 0 );
dwError = ERROR_INVALID_PARAMETER;
goto _err_return;
}
}
//以下代码做提交物理页工作
// now to commit page if need
if( dwAllocType & MEM_COMMIT ) ////需要提交物理页吗?
{ //需要提交物理页
int iAllocPages;
idxCommitPage = PAGE_INDEX( dwStart );
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:To Commit,idxCommit=%d,idxCommitPage=%d,iNeedPages=%d.\r\n", idxCommit, idxCommitPage, iNeedPages ) );
//检视需要提交的页数并分配相应的块结构
if( ( iAllocPages = Seg_ReviewRegion( lpSeg, idxFirst, idxCommit, idxCommitPage, iNeedPages, NULL ) ) != -1 )
{ // 成功,提交物理页。ok , success to commit,now, alloc the physical pages for commit page
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc: iAllocPages=%d.\r\n", iAllocPages ) );
if( Seg_MapPhyPages( lpProcessSeg, lpSeg, idxCommit, idxCommitPage, iNeedPages, iAllocPages, dwAllocType, lpdwPhycialPages, dwProtect ) )
{
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:success to commit=%x.\r\n", dwStart ) );
dwRetv = dwStart;
FlushCacheAndClearTLB(); //刷新CACHE
goto _return;
}
else
{
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:failuer to MapPhyPages.\r\n" ) );
}
}
else
{
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:failuer to ReviewRegion.\r\n" ) );
}
// 发生了某些错误,做清除工作。some error happen, now clear reserved
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "Failuer to Commit.\r\n" ) );
if( bReserved )
{
Seg_FreeRegion( lpSeg, idxFirst );
}
}
else //不需要提交物理页,仅仅保留。no commit , only reserve
{
DEBUGMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:success to reserve=%x.\r\n", dwStart ) );
dwRetv = dwStart;
goto _return;
}
}
else
{
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc: not find the segment addr=(0x%x), index=%d, knx=%d.\r\n", dwStart, dwSegIndex, KERNEL_SEGMENT_INDEX ) );
ASSERT( 0 );
}
}
_err_return:
KL_SetLastError( dwError );
WARNMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:failure alloc address(%x).\r\n", dwStart ) );
_return:
KL_LeaveCriticalSection( &csVirtualMem );
if( dwRetv )
dwRetv = dwRetv | ( dwSegIndex << SEGMENT_SHIFT );
RETAILMSG( DEBUG_DOVIRTUALALLOC, ( "DoVirtaulAlloc:dwRetv(0x%x).\r\n", dwRetv ) );
return (LPVOID)dwRetv;
}
// ********************************************************************
// 声明:LPVOID WINAPI KL_VirtualAlloc(
// LPVOID lpvAddress,
// DWORD dwSize,
// DWORD dwAllocType,
// DWORD dwProtect )
// 参数:
// IN lpvAddress - 虚地址
// IN dwSize - 需要分配的大小(以byte为单位)
// IN dwAllocType - 分配类型,为以下值的组合:
// MEM_RESERVE - 保留虚地址
// MEM_COMMIT - 提交物理页
// IN dwProtect - 保护属性
// 返回值:
// 假如成功,返回非NULL指针;否则返回NULL
// 功能描述:
// 分配用户虚地址,假如uiAllocType有MEM_COMMIT但没有MEM_RESERVE,则该地址范围必须是之前已经被保留的
// 引用:
// 系统API
// ********************************************************************
#define DEBUG_KL_VirtualAlloc 0
LPVOID WINAPI KL_VirtualAlloc(
LPVOID lpvAddress,
DWORD dwSize,
DWORD dwAllocType,
DWORD dwProtect )
{
DEBUGMSG( DEBUG_KL_VirtualAlloc, ( "KL_VirtualAlloc entry,lpvAddress=0x%x,dwSize=%d,dwAllocType=0x%x.\r\n", lpvAddress, dwSize, dwAllocType ) );
if( (DWORD)lpvAddress < 0x80000000 )
return DoVirtualAlloc( lpvAddress, dwSize, dwAllocType, dwProtect, NULL );
else
return NULL;
}
// ********************************************************************
// 声明:LPVOID WINAPI KC_VirtualAlloc(
// LPVOID lpvAddress,
// DWORD dwSize,
// DWORD dwAllocType,
// DWORD dwProtect )
// 参数:
// IN lpvAddress - 虚地址
// IN dwSize - 需要分配的大小(以byte为单位)
// IN dwAllocType - 分配类型,为以下值的组合:
// MEM_RESERVE - 保留虚地址
// MEM_COMMIT - 提交物理页
// IN dwProtect - 保护属性
// 返回值:
// 假如成功,返回非NULL指针;否则返回NULL
// 功能描述:
// 内核版,分配用户虚地址,假如uiAllocType有MEM_COMMIT但没有MEM_RESERVE,则该地址范围必须是之前已经被保留的
// 引用:
// 内核版
// ********************************************************************
#define DEBUG_KC_VirtualAlloc 0
LPVOID WINAPI KC_VirtualAlloc(
LPVOID lpvAddress,
DWORD dwSize,
DWORD dwAllocType,
DWORD dwProtect )
{
DEBUGMSG( DEBUG_KC_VirtualAlloc, ( "KC_VirtualAlloc entry,lpvAddress=0x%x,dwSize=%d.\r\n", lpvAddress, dwSize ) );
return DoVirtualAlloc( lpvAddress, dwSize, dwAllocType, dwProtect, NULL );
}
// ********************************************************************
// 声明:BOOL DoVirtualCopy(
// DWORD dwDstAddress,
// DWORD dwSrcAddress,
// DWORD dwSize,
// DWORD dwProtect
// )
// 参数:
// IN dwDstAddress - 目标地址
// IN dwSrcAddress - 源地址
// IN dwSize - 需要拷贝的大小
// IN dwProtect - 保护属性
// 返回值:
// 假如成功,返回TRUE;否则,返回FALSE
// 功能描述:
// 将源地址的物理页映射到目标地址
// 引用:
//
// ********************************************************************
#define DEBUG_VIRTUALCOPY 0
static BOOL DoVirtualCopy(
DWORD dwDstAddress,
DWORD dwSrcAddress,
DWORD dwSize,
DWORD dwProtect
)
{
DWORD dwDstStart = dwDstAddress;
DWORD dwDstEnd = dwDstStart + dwSize;
DWORD dwSegIndex = GET_SEGMENT_INDEX( dwDstStart );
LPSEGMENT lpSegDst;
LPPROCESS_SEGMENTS lpProcessSegDst;
DWORD dwError = 0;
DWORD dwRetv = NULL;
DWORD dwPhyAdr = 0;
UINT uiNeedPages;
BOOL bVirtualAdr = FALSE;
BOOL bRetv = FALSE;
if( dwSize == 0 || dwDstStart == 0 || dwSrcAddress == 0 || dwSegIndex >= MAX_SEGMENTS )
goto _RET_INVALID;
uiNeedPages = ( ( dwDstEnd + PAGE_SIZE - 1 ) / PAGE_SIZE ) - ( dwDstStart / PAGE_SIZE );
if( dwProtect & PAGE_PHYSICAL ) // dwSrcAddress是物理地址吗 ?
{ //是
dwPhyAdr = (dwSrcAddress << 8) & ~(PAGE_SIZE-1); // align to page
if( ( dwPhyAdr & PAGE_MASK ) != ( dwDstStart & PAGE_MASK ) ) // 源与目标应该对齐页边界
goto _RET_INVALID;
dwProtect &= ~PAGE_PHYSICAL;
}
else if( IsKernelVirtualAddress( dwSrcAddress ) ) // 源是内核地址吗 ?
{ //是
dwPhyAdr = _GetPhysicalPageAdr( dwSrcAddress ); // 得到对应的物理地址
if( ( dwPhyAdr & PAGE_MASK ) != ( dwDstStart & PAGE_MASK ) ) // 源与目标应该对齐页边界
goto _RET_INVALID;
}
else
{ // 源在用户地址空间。from other virtual address
bVirtualAdr = TRUE;
}
KL_EnterCriticalSection( &csVirtualMem ); // 进入冲突段
//lpSegDst = Seg_FindSegment( dwDstStart ); // 发现目标段
lpProcessSegDst = Seg_FindProcessSegment( dwDstStart );
if( lpProcessSegDst )
lpSegDst = lpProcessSegDst->lpSeg;
else
lpSegDst = NULL;
if( lpSegDst )
{ //
UINT idxDstStartBlk;
UINT idxDstStartPage;
UINT idxFirstBlk;
UINT uiNeedAllocPages;
idxDstStartBlk = BLOCK_INDEX( dwDstAddress );
idxDstStartPage = PAGE_INDEX( dwDstAddress );
idxFirstBlk = Seg_SearchFirstBlock( lpSegDst, idxDstStartBlk );
if( idxFirstBlk == NOT_FIND_FIRST )
goto _RET_INVALID_LEAVE;
// 检查目标区域,保证所用需要拷贝的page已被保留。
uiNeedAllocPages = Seg_ReviewRegion( lpSegDst, idxFirstBlk, idxDstStartBlk, idxDstStartPage, uiNeedPages, NULL );
if( uiNeedAllocPages != uiNeedPages )
goto _RET_INVALID_LEAVE;
if( bVirtualAdr )
{ // 源在用户地址空间,from other virtual address
LPSEGMENT lpSegSrc;
UINT idxSrcStartBlk;
UINT idxSrcStartPage;
UINT idxFirstBlk;
UINT uiAllocPages;
UINT uiCountPages;
idxSrcStartPage = PAGE_INDEX( dwSrcAddress );
if( idxSrcStartPage != idxDstStartPage )
goto _RET_INVALID_LEAVE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -