📄 physmem.c
字号:
/* 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 + -