⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 virtual.c

📁 深圳市微逻辑电子有限公司 巨果&#8226 Kingmos&reg 系统核心
💻 C
📖 第 1 页 / 共 5 页
字号:
/******************************************************
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 + -