📄 virtual.c
字号:
/******************************************************
Copyright(c) 版权所有,1998-2005微逻辑。保留所有权利。
******************************************************/
/*****************************************************
文件说明:虚拟内存管理
版本号:2.0.0
开发时期:2002
作者:李林
修改记录:
2005-01-18 : 增加对 内核进程的虚地址段的处理,例如去掉 dwSegIndex < MAX_SEGMENTS 等
******************************************************/
#include <eframe.h>
#include <cpu.h>
#include <pagemgr.h>
#include <coresrv.h>
#include <virtual.h>
#include <epalloc.h>
#include <epcore.h>
// The user mode virtual address space is 2GB split into 64 32M sections
// of 512 64K blocks of 16 4K pages.
// 2GB的虚地址空间被划分为 64个段,每个段(32M)被划分为512个块,每个块(64K )被划分为16个页(每页4K)
// Virtual address format:
// 3322222 222221111 1111 110000000000
// 1098765 432109876 5432 109876543210
// zSSSSSS BBBBBBBBB PPPP oooooooooooo
//static LPSEGMENT KernelSegments[MAX_SEGMENTS];
#define PAGE_IN_RANGE( page, minPage, maxPage ) ( (page) >= minPage && (page) < maxPage )
static CRITICAL_SECTION csVirtualMem;
BOOL Seg_DecommitPages( LPPROCESS_SEGMENTS lpProcessSeg, LPSEGMENT lpSeg, int idxStartBlk, int idxStartPages, int iPages );
static LPPROCESS_SEGMENTS Seg_FindProcessSegment( DWORD dwAddress );
// ********************************************************************
// 声明:BOOL InitialVirtualMgr( void )
// 参数:
// 无
// 返回值:
// 假如成功,返回TRUE;否则,返回FALSE
// 功能描述:
// 初始化虚拟内存管理器
// 引用:
// system.c
// ********************************************************************
BOOL InitialVirtualMgr( void )
{
KC_InitializeCriticalSection( &csVirtualMem );
return TRUE;
}
// ********************************************************************
// 声明:BOOL GetPagesInCacheRange( LPPROCESS_SEGMENTS lpProcessSeg,
// UINT * lpuiPageIndexStart, UINT * lpuiPageIndexEnd )
// 参数:
// IN lpProcessSeg - 进程段组
// IN/OUT lpuiPageIndexStart - 页在段内的索引
// IN/OUT lpuiPageIndexStart - 页在段内的索引
// 返回值:
// 假如成功,返回TRUE;否则,返回FALSE
// 功能描述:
// 判断一个页是否在 页表内
// 引用:
// system.c
// ********************************************************************
static BOOL GetPagesInCacheRange( LPPROCESS_SEGMENTS lpProcessSeg,
UINT * lpuiPageIndexStart,
UINT * lpuiPageIndexEnd )
{
UINT uStartCachePage, uEndCachePage, minPage, maxPage;
if( lpProcessSeg ) //&& lpProcessSeg->lpdwSecondPageTable )
{
uStartCachePage = lpProcessSeg->uiPageTableStart;
uEndCachePage = uStartCachePage + lpProcessSeg->uiPageTableCount * PAGES_PER_MEGA;
//ASSERT( lpProcessSeg->lpdwSecondPageTable );
minPage = MAX( uStartCachePage, *lpuiPageIndexStart );
maxPage = MIN( uEndCachePage, *lpuiPageIndexEnd );
if( minPage < maxPage )
{
*lpuiPageIndexStart = minPage;
*lpuiPageIndexEnd = maxPage;
return TRUE;
}
}
return FALSE;
}
// ********************************************************************
// 声明:LPSEGMENT Seg_Alloc( void )
// 参数:
// 无
// 返回值:
// 段指针
// 功能描述:
// 分配一个段结构指针
// 引用:
//
// ********************************************************************
LPSEGMENT Seg_Alloc( void )
{
LPSEGMENT lpSeg = (LPSEGMENT)KHeap_Alloc( sizeof( SEGMENT ) );
if( lpSeg )
{
memset( lpSeg, 0, sizeof( SEGMENT ) );
}
return lpSeg;
}
// ********************************************************************
// 声明:void Seg_Free ( LPSEGMENT lpSeg )
// 参数:
// IN lpSeg - 段结构指针
// 返回值:
// 无
// 功能描述:
// 释放段结构指针及其所占用的物理页
// 引用:
//
// ********************************************************************
void Seg_Free ( LPSEGMENT lpSeg )
{
LPMEMBLOCK * lppBlks;
int i;
BOOL bFlush = 0;
// ASSERT( (DWORD)lpSeg != dwProcessSlots[0] );
FlushCacheAndClearTLB(); // 先刷新CACHE
lppBlks = lpSeg->lpBlks;
// 查找每一个块,如果有未释放的物理页,则释放它们
for( i = 0; i < BLOCKS_PER_SEGMENT; i++, lppBlks++ )
{
if( *lppBlks > RESERVED_BLOCK ) // 是否有块结构 ?
{ // 有
// ASSERT( i != 0 );
// 释放该段该块的物理页
bFlush |= Seg_DecommitPages( NULL, lpSeg, i, 0, PAGES_PER_BLOCK );
// 释放该块
KHeap_Free( *lppBlks, sizeof(MEMBLOCK) );
}
}
// 释放段结构
KHeap_Free( lpSeg, sizeof(SEGMENT) );
if( bFlush ) // 释放完,刷新CACHE
FlushCacheAndClearTLB();
}
// ********************************************************************
// 声明:static int Seg_SearchFirstBlock( LPSEGMENT lpSeg, int index )
// 参数:
// IN lpSeg - 段结构指针
// IN index - 连续块组内其中的一个块在段内的索引
// 返回值:
// 假如成功,返回块索引值;否则,返回NOT_FIND_FIRST
// 功能描述:
// 得到一个连续块组的第一个块
// 引用:
//
// ********************************************************************
static int Seg_SearchFirstBlock( LPSEGMENT lpSeg, int index )
{
LPMEMBLOCK * lppBlks = lpSeg->lpBlks + index;
if( *lppBlks != NULL_BLOCK && index >= 0 )
{ //
if( *lppBlks > RESERVED_BLOCK ) // 块值是第一个块索引值吗 ?
return (*lppBlks)->idxFirst; // 否,是内存块结构。成员idxFirst指向第一个块
else
return (int)*lppBlks; // 是,直接返回该值
}
return NOT_FIND_FIRST;
}
// ********************************************************************
// 声明:void Seg_GetInfo( LPSEGMENT lpSeg,
// LPDWORD lpdwAvailVirtual,
// LPDWORD lpdwReserve,
// LPDWORD lpdwCommit )
// 参数:
// IN lpSeg - 段结构指针
// OUT lpdwAvailVirtual - 用于接受可利用虚空间
// OUT lpdwReserve - 用于接受已被保留的虚空间
// OUT lpdwCommit - 用于接受已提交(分配)的空间
// 返回值:
// 无
// 功能描述:
// 得到段信息
// 引用:
//
// ********************************************************************
void Seg_GetInfo( LPSEGMENT lpSeg,
LPDWORD lpdwAvailVirtual,
LPDWORD lpdwReserve,
LPDWORD lpdwCommit )
{
LPMEMBLOCK * lppBlks = lpSeg->lpBlks+1; // 每个段的第0块是被保留的
int idxStart = 1;
DWORD dwAvailVirtual = 0;
DWORD dwReserve = 0;
DWORD dwCommit = 0;
// 搜索每一个块
for( ; idxStart < BLOCKS_PER_SEGMENT; idxStart++, lppBlks++ )
{ //
if( *lppBlks != NULL_BLOCK ) // 是否被使用(分配或保留) ?
{ // 是,has alloc
if( *lppBlks <= RESERVED_BLOCK ) // 是保留吗 ?
dwReserve += BLOCK_SIZE; // 是
else
{ // 已经提交的块
int i;
LPUINT lpuiPage = (*lppBlks)->uiPages;
// 统计每个块内的页数
for( i = 0; i < PAGES_PER_BLOCK; i++, lpuiPage++ )
{
if( *lpuiPage == 0 ) // 未提交/分配
dwReserve += PAGE_SIZE;
else if( *lpuiPage != INVALID_PAGE ) // 如果不是无效页就是被分配的页
{ // commited pages
dwCommit += PAGE_SIZE;
}
}
}
}
else
{ // 该块未使用
dwAvailVirtual += BLOCK_SIZE;
}
}
*lpdwAvailVirtual = dwAvailVirtual;
*lpdwReserve = dwReserve;
*lpdwCommit = dwCommit;
}
// ********************************************************************
// 声明:static int Seg_GetFirstBlockPos( LPSEGMENT lpSeg, int idxStart, int iNeedPages, BOOL bAutoNext )
// 参数:
// IN lpSeg - 段结构指针
// IN idxStart - 起始块
// IN iNeedPages - 需要的页数
// IN bAutoNext - 是否自动查找下一个位置
// 返回值:
// 如果成功,返回第一个块的索引值;否则,返回0
// 功能描述:
// 得到一个大小为iNeedPahes的连续的未使用的块组,并返回该组的第一个块的索引值
// 引用:
//
// ********************************************************************
static int Seg_GetFirstBlockPos( LPSEGMENT lpSeg, int idxStart, int iNeedPages, BOOL bAutoNext )
{
LPMEMBLOCK * lppBlks = lpSeg->lpBlks+idxStart;
int idxFirst = idxStart;
int iPages = iNeedPages;
//RETAILMSG( 1, ( "idxStart=%d, iNeedPages=%d, bAutoNext=%d.\r\n", idxStart, iNeedPages, bAutoNext ) );
for( ; idxStart < BLOCKS_PER_SEGMENT; idxStart++, lppBlks++ )
{
if( *lppBlks != NULL_BLOCK ) // 是否已被占用
{ // 是,该组不能用。has alloc
if( bAutoNext ) // 是否可以自动向下寻找
{ // 是,重新查找
iPages = iNeedPages;
idxFirst = idxStart + 1;
}
else
return 0; // 不要向下寻找, 返回
}
else
{ // 未占用,可以用
if( (iPages -= PAGES_PER_BLOCK) <= 0 ) // 块组全部满足需要吗 ?
return idxFirst; // 是,返回首索引。yes , i get it
}
}
//RETAILMSG( 1, ( "idxStar_end=%d.\r\n", idxStart ) );
return 0;
}
// ********************************************************************
// 声明:static int Seg_ReserveNeedPages(
// LPSEGMENT lpSeg,
// int idxStart,
// int iNeedPages,
// BOOL bAutoCommit,
// DWORD dwProtect )
// 参数:
// IN lpSeg - 段结构指针
// IN idxStart - 开始块索引
// IN iNeedPages - 需要的页数
// IN bAutoCommit - 是否自动提交
// IN dwProtect
// 返回值:
// 假如成功,返回TRUE;否则,返回FALSE
// 功能描述:
// 从开始块保留需要的页
// 引用:
//
// ********************************************************************
static int Seg_ReserveNeedPages( LPSEGMENT lpSeg, int idxStart, int iNeedPages, BOOL bAutoCommit, DWORD dwProtect )
{
LPMEMBLOCK * lppBlks = lpSeg->lpBlks+idxStart;
LPMEMBLOCK lpStartBlk, lpBlk;//, lpBlkEnd;
lpBlk = lpStartBlk = (LPMEMBLOCK)KHeap_Alloc( sizeof( MEMBLOCK ) );//分配块结构
if( lpStartBlk )
{
// 初始化第一个块
memset( lpStartBlk, 0, sizeof( MEMBLOCK ) );
lpStartBlk->idxFirst = idxStart;
lpStartBlk->uiKey = 0;
lpStartBlk->wLockCount = 0;
lpStartBlk->uiFlag = bAutoCommit ? ( MF_AUTO_COMMIT | GetAttribFromProtect( dwProtect ) ) : 0;
*lppBlks++ = lpStartBlk;
iNeedPages -= PAGES_PER_BLOCK;
//RETAILMSG( 1, ( "Seg_ReserveNeedPages: lpSeg=%x,idxStart=%d,*lppBlks=%x,iNeedPages=%d.\r\n", lpSeg, idxStart, *lppBlks, iNeedPages ) );
// 保留其它块
for( ; iNeedPages > 0; iNeedPages -= PAGES_PER_BLOCK, lppBlks++ )
{ //
if( bAutoCommit || iNeedPages < PAGES_PER_BLOCK )
{ // 如果是自动提交 或 最后一个块,则分配一个块结构
lpBlk = (LPMEMBLOCK)KHeap_Alloc( sizeof( MEMBLOCK ) );
if( lpBlk )
{ // 初始化块结构
memset( lpBlk, 0, sizeof( MEMBLOCK ) );
lpBlk->idxFirst = idxStart;//
lpBlk->uiKey = lpStartBlk->uiKey;
lpBlk->wLockCount = lpStartBlk->wLockCount;
lpBlk->uiFlag = lpStartBlk->uiFlag;
*lppBlks = lpBlk;
}
else
{ // 没有内存,释放之前分配的块结构。no enough memory, clear
LPMEMBLOCK * lppBlkStart = lpSeg->lpBlks+idxStart;
//RETAILMSG( 1, ( "Seg_ReserveNeedPages:no enough memory, clear.\r\n" ) );
while( lppBlkStart < lppBlks )
{
if( *lppBlkStart > RESERVED_BLOCK ) // 块指针是分配的,释放它
{
KHeap_Free( *lppBlkStart, sizeof( MEMBLOCK ) );
}
*lppBlkStart++ = NULL_BLOCK;
}
lpStartBlk = NULL; // use by retv
iNeedPages = 0;
}
}
else
{ // 不需要自动提交并且是中间的块。设置保留标志 set reserve flag
*lppBlks = (LPMEMBLOCK)idxStart;// 保留标志是该组的第一个块
}
}
if( iNeedPages ) // 是否块组的所有的页都被保留 ?
{ // 不是,块组的一些页是无效的。这里设置无效标志。not all pages is valid, set invalid page flag
LPUINT lpuiPage;
iNeedPages += PAGES_PER_BLOCK;
lpuiPage = &lpBlk->uiPages[iNeedPages];
for( ; iNeedPages < PAGES_PER_BLOCK; iNeedPages++ )
{
*lpuiPage++ = INVALID_PAGE; //设置无效标志
}
}
//RETAILMSG( 1, ( "Seg_ReserveNeedPages-end: lpSeg=%x,idxStart=%d,*lppBlks=%x.\r\n", lpSeg, idxStart, *(lpSeg->lpBlks+idxStart) ) );
}
return lpStartBlk ? TRUE : FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -