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

📄 physmem.c

📁 可用于嵌入式编程学习
💻 C
📖 第 1 页 / 共 2 页
字号:
/*		Copyright (c) 1995-2000 Microsoft Corporation.  All rights reserved. */
#include "kernel.h"

//#define PHYSPAGESTOLEDS 1

#ifdef PHYSPAGESTOLEDS
#define LogPhysicalPages(PageFreeCount) OEMWriteDebugLED(0,PageFreeCount);
#else
#define LogPhysicalPages(PageFreeCount) (0)
#endif

#define STACK_RESERVE		15
#define MIN_PROCESS_PAGES   STACK_RESERVE

#define PAGEOUT_LOW			(( 68*1024)/PAGE_SIZE)	// do pageout once below this mark, reset when above high
#define PAGEOUT_HIGH		((132*1024)/PAGE_SIZE)
#define PAGE_OUT_TRIGGER	(( 24*1024)/PAGE_SIZE)	// page out if below highwater and this much paged in recently

void ZeroPage(void *pvPage);
BOOL ScavengeStacks(int cNeed);

HANDLE GwesOOMEvent;
long GwesLowThreshold;
long GwesCriticalThreshold;
long GwesLowBlockSize;
long GwesCriticalBlockSize;
LPBYTE pFreeKStacks;

extern void FreeSpareBytes(LPBYTE lpb, uint size);

extern CRITICAL_SECTION PhysCS;
extern PTHREAD pCleanupThread;

// PageOutNeeded is set to 1 when the number of free pages drops below
// PageOutTrigger and the cleanup thread's event is signalled. When the
// cleanup thread starts performing page out, it sets the variable to 2.
// When the page free count rises above PageOutLevel, PageOutNeeded is
// reset to 0.
//
// The free page count thresholds are set based upon the Gwes OOM level.

long PageOutNeeded;
long PageOutTrigger;    // Threshold level to start page out.
long PageOutLevel;      // Threshold to stop page out.

/* GWE calls this function to register an Out Of Memory event, which
 * HoldPages sets when free physical memory drops below the given threshold.
 */
VOID SC_SetGwesOOMEvent(HANDLE hEvent, DWORD cpLow, DWORD cpCritical,
						DWORD cpLowBlockSize, DWORD cpCriticalBlockSize) {
	DEBUGMSG(ZONE_ENTRY,(L"SC_SetGwesOOMEvent entry: %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx\r\n",
		hEvent,cpLow,cpCritical,cpLowBlockSize,cpCriticalBlockSize));
	GwesOOMEvent = hEvent;
	GwesLowThreshold = cpLow;
	GwesCriticalThreshold = cpCritical;
	GwesLowBlockSize = cpLowBlockSize;
	GwesCriticalBlockSize = cpCriticalBlockSize;
	PageOutLevel = GwesLowThreshold + PAGEOUT_HIGH;
	PageOutTrigger = GwesLowThreshold + PAGEOUT_LOW;
	DEBUGMSG(ZONE_ENTRY,(L"SC_SetGwesOOMEvent exit\r\n"));
}

#if PAGE_SIZE < 2048

void UnlinkPhysPage(LPBYTE pMem) {
	KCALLPROFON(38);
	if (*(DWORD *)((DWORD)pMem + 0x20000000))
		*(LPBYTE *)(*(DWORD *)((DWORD)pMem + 0x20000000) + 0x20000004) =
			*(LPBYTE *)((DWORD)pMem + 0x20000004);
	if (*(DWORD *)((DWORD)pMem + 0x20000004))
		*(LPBYTE *)(*(DWORD *)((DWORD)pMem + 0x20000004) + 0x20000000) =
			*(LPBYTE *)((DWORD)pMem + 0x20000000);
	else
		LogPtr->pKList = *(LPBYTE *)((DWORD)pMem + 0x20000000);
	*(LPDWORD)(pMem + 0x20000000) = 0;
	*(LPDWORD)(pMem + 0x20000004) = 0;
	KCALLPROFOFF(38);
}

#endif

void LinkPhysPage(LPBYTE pMem) {
	KCALLPROFON(32);
	*(LPBYTE *)((DWORD)pMem + 0x20000000) = LogPtr->pKList;
	*(LPBYTE *)((DWORD)pMem + 0x20000004) = 0;
	if (LogPtr->pKList)
		*(LPBYTE *)((DWORD)LogPtr->pKList + 0x20000004) = pMem;
	LogPtr->pKList = pMem;
    PageFreeCount++;
	LogPhysicalPages(PageFreeCount);
	KCALLPROFOFF(32);
}

LPBYTE GrabFirstPhysPage(DWORD dwCount) {
	PFREEINFO pfi;
    uint ix;
    PHYSICAL_ADDRESS paRet;
	LPBYTE pMem;
	KCALLPROFON(33);
	if (pMem = LogPtr->pKList) {
		paRet = GetPFN(pMem);
		if (LogPtr->pKList = *(LPBYTE *)((DWORD)pMem + 0x20000000))
			*(LPBYTE *)((DWORD)LogPtr->pKList + 0x20000004) = 0;
		*(LPDWORD)(pMem + 0x20000000) = 0;
		*(LPDWORD)(pMem + 0x20000004) = 0;
		pfi = GetRegionFromAddr(paRet);
		ix = (paRet - pfi->paStart) / PFN_INCR;
	    DEBUGCHK(pfi->pUseMap[ix] == 0);
	    DEBUGCHK(dwCount && (dwCount <= 0xff));
		pfi->pUseMap[ix] = (BYTE)dwCount;
	    PageFreeCount--;
		LogPhysicalPages(PageFreeCount);
		DEBUGCHK(PageFreeCount >= 0);
	}
	DEBUGCHK(pMem);
	KCALLPROFOFF(33);
	return pMem;	
}

// called by loader.c when moving memory "slider"

void RemovePage(DWORD dwAddr) {
	DWORD pfn, ix;
	FREEINFO *pfi;
	pfn = GetPFN(dwAddr);
	pfi = GetRegionFromAddr(pfn);
	DEBUGCHK(pfi);
    ix = (pfn - pfi->paStart) / PFN_INCR;
    pfi->pUseMap[ix] = 0xff;
}


BOOL DemandCommit(ulong addr) {
	MEMBLOCK *pmb;
	LPDWORD pPage;
	PFREEINFO pfi;
   	uint ix;
	PHYSICAL_ADDRESS paRet;
	LPBYTE pMem;
	pmb = (*SectionTable[addr>>VA_SECTION])[(addr>>VA_BLOCK) & BLOCK_MASK];
		if (!*(pPage = &pmb->aPages[(addr>>VA_PAGE) & PAGE_MASK])) {
		pMem = LogPtr->pKList;

		if (GwesOOMEvent && (PageFreeCount < GwesCriticalThreshold)) {
			SetEvent(GwesOOMEvent);
		}
        
		if (!PageFreeCount || !pMem) {
			RETAILMSG(1,(L"--->>> DemandCommit: FATAL ERROR!  COMPLETELY OUT OF MEMORY (%8.8lx %8.8lx)!\r\n",pMem,PageFreeCount));
			INTERRUPTS_OFF();
            while (1) {
                // we don't recover if there's no memory, so better off to just stop
            }
			return FALSE;
		}
		paRet = GetPFN(pMem);
		pMem = (LPBYTE)((DWORD)pMem + 0x20000000);
		if (LogPtr->pKList = *(LPBYTE *)pMem)
			*(LPBYTE *)((DWORD)LogPtr->pKList + 0x20000004) = 0;
		*(LPDWORD)pMem = 0;
		*(LPDWORD)(pMem + 4) = 0;
		pfi = GetRegionFromAddr(paRet);
		ix = (paRet - pfi->paStart) / PFN_INCR;
    	DEBUGCHK(!pfi->pUseMap[ix]);
		pfi->pUseMap[ix] = 1;
		*pPage = paRet | PG_READ_WRITE;
    	PageFreeCount--;
		LogPhysicalPages(PageFreeCount);
		DEBUGCHK(PageFreeCount >= 0);
		return TRUE;
	}
	return FALSE;
}

void EnterPhysCS(void) {
    LPVOID pMem;
	EnterCriticalSection(&PhysCS);
	DEBUGCHK(PhysCS.OwnerThread == hCurThread);
	if (PhysCS.LockCount == 1)
	    while (pMem = InterlockedPopList(&pFreeKStacks))
			FreeHelperStack(pMem);
}

BOOL SC_GiveKPhys(void *ptr, ulong length) {
	BOOL bRet = FALSE;
	LPBYTE pPage;
	DWORD loop;
	PFREEINFO pfi;
	PHYSICAL_ADDRESS paPFN;
	uint ix;
	if (pCurProc->bTrustLevel != KERN_TRUST_FULL) {
	    KSetLastError(pCurThread, ERROR_ACCESS_DENIED);
    	return 0;
	}
	DEBUGMSG(ZONE_ENTRY,(L"SC_GiveKPhys entry: %8.8lx %8.8lx\r\n",ptr,length));
	SC_CacheSync(CACHE_SYNC_DISCARD);
	EnterPhysCS();
	for (loop = 0; loop < length; loop++) {
		pPage = *((LPBYTE *)ptr+loop);
		ZeroPage(pPage + 0x20000000);
		paPFN = GetPFN(pPage);
		pfi = GetRegionFromAddr(paPFN);
		DEBUGCHK(pfi);
        ix = (paPFN - pfi->paStart) / PFN_INCR;
        DEBUGCHK(pfi->pUseMap[ix] == 0xff);
        pfi->pUseMap[ix] = 0;
		KCall((PKFN)LinkPhysPage,pPage);
    }
	KInfoTable[KINX_NUMPAGES] += length;
    // If there are enough free pages, clear the PageOutNeeded flag.
    if (PageFreeCount > PageOutLevel)
        PageOutNeeded = 0;
	bRet = TRUE;
	LeaveCriticalSection(&PhysCS);
	DEBUGMSG(ZONE_ENTRY,(L"SC_GiveKPhys exit: %8.8lx\r\n",bRet));
	return bRet;
}

BOOL SC_GetKPhys(void *ptr, ulong length) {
	LPVOID *pPages;
	BOOL bRet = FALSE;
    DWORD dwCount;
    LPBYTE pMem;
	DEBUGMSG(ZONE_ENTRY,(L"SC_GetKPhys entry: %8.8lx %8.8lx\r\n",ptr,length));
	if (pCurProc->bTrustLevel != KERN_TRUST_FULL) {
	    KSetLastError(pCurThread, ERROR_ACCESS_DENIED);
    	return 0;
	}
	pPages = (LPVOID *)ptr;
	EnterPhysCS();
	ScavengeStacks(100000);     // Reclaim all extra stack pages.
	if ((length == 1) || ((DWORD)PageFreeCount > length + PageOutTrigger)) {
		for (dwCount = length; dwCount; dwCount--) {
			if (!(pMem = (LPBYTE)KCall((PKFN)GrabFirstPhysPage,0xff))) {
				LeaveCriticalSection(&PhysCS);
				SC_GiveKPhys(ptr,length - dwCount);
				DEBUGCHK(0);
				RETAILMSG(1,(L"Error getting pages!\r\n"));
				return 0;
			}
			KInfoTable[KINX_NUMPAGES]--;
			*pPages++ = pMem;
	    }
	    bRet = TRUE;
	}
	LeaveCriticalSection(&PhysCS);
	DEBUGMSG(ZONE_ENTRY,(L"SC_GetKPhys exit: %8.8lx\r\n",bRet));
	return bRet;
}
	
void InitMemoryPool() {
	PFREEINFO pfi, pfiEnd;
	DWORD loop;
	LPBYTE pPage;
	/* Fill in data fields in user visible kernel data page */
	KInfoTable[KINX_PROCARRAY] = (long)ProcArray;
	KInfoTable[KINX_PAGESIZE] = PAGE_SIZE;
#ifdef PFN_SHIFT
	KInfoTable[KINX_PFN_SHIFT] = PFN_SHIFT;
#endif
	KInfoTable[KINX_PFN_MASK] = (DWORD)PFNfromEntry(~0);
	KInfoTable[KINX_SECTIONS] = (long)SectionTable;
	KInfoTable[KINX_MEMINFO] = (long)&MemoryInfo;
	KInfoTable[KINX_KDATA_ADDR] = (long)&KData;
	SC_CacheSync(CACHE_SYNC_DISCARD);
	for (pfi = MemoryInfo.pFi, pfiEnd = pfi+MemoryInfo.cFi ; pfi < pfiEnd ; ++pfi) {
		DEBUGMSG(ZONE_MEMORY, (TEXT("InitMemoryPool: Init range: map=%8.8lx start=%8.8lx end=%8.8lx\r\n"),
				pfi->pUseMap, pfi->paStart, pfi->paEnd));
		pPage = 0;
		for (loop = pfi->paStart; loop < pfi->paEnd; loop += PFN_INCR) {
			if (!pfi->pUseMap[(loop-pfi->paStart)/PFN_INCR]) {
				pPage = Phys2Virt(loop);
				ZeroPage(pPage + 0x20000000);
				LinkPhysPage(pPage);
				LogPtr->pKList = pPage;
	    	    KInfoTable[KINX_NUMPAGES]++;
			}
		}
	}
    DEBUGMSG(ZONE_MEMORY,(TEXT("InitMemoryPool done, free=%d\r\n"),PageFreeCount));
}

PTHREAD PthScavTarget;
PPROCESS PprcScavTarget = &ProcArray[0];
int StackScavCount;

HTHREAD ScavengeOnePage(void) {
	HTHREAD ret;
	KCALLPROFON(13);
    if (!PthScavTarget) {
	    if (++PprcScavTarget >= &ProcArray[MAX_PROCESSES])
			PprcScavTarget = ProcArray;
	   	++StackScavCount;
	    if (!PprcScavTarget->dwVMBase || !(PthScavTarget = PprcScavTarget->pTh)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -