📄 physmem.c
字号:
hpDone:
LeaveCriticalSection(&PhysCS);
if (fSetGweOomEvent) {
SetOOMEvt ();
}
return bRet;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
DupPhysPage(
PHYSICAL_ADDRESS paPFN
)
{
PFREEINFO pfi;
uint ix;
//NOTE: DupPhysage and FreePhysPage are only called by the virtual memory
// system with the VA critical section held so DupPhysPage does not need to
// claim the physical memory critical section because it does not change
// the page free count.
if ((pfi = GetRegionFromAddr(paPFN)) != 0) {
ix = (paPFN - pfi->paStart) / PFN_INCR;
DEBUGCHK((pfi->pUseMap[ix] != 0) && (pfi->pUseMap[ix] != 0xff));
DEBUGMSG(ZONE_PHYSMEM, (TEXT("DupPhysPage: PFN=%8.8lx ix=%x rc=%d\r\n"), paPFN,
ix, pfi->pUseMap[ix]));
++pfi->pUseMap[ix];
}
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FreePhysPage(
PHYSICAL_ADDRESS paPFN
)
{
PFREEINFO pfi;
uint ix;
if ((pfi = GetRegionFromAddr(paPFN)) != 0) {
ix = (paPFN - pfi->paStart) / PFN_INCR;
DEBUGMSG(ZONE_PHYSMEM, (TEXT("FreePhysPage: PFN=%8.8lx ix=%x rc=%d\r\n"), paPFN,
ix, pfi->pUseMap[ix]));
EnterPhysCS();
DEBUGCHK(pfi->pUseMap[ix] != 0);
if ((pfi->pUseMap[ix] != 0xff) && (!--pfi->pUseMap[ix])) {
DEBUGMSG(ZONE_PHYSMEM, (TEXT("FreePhysPage: PFN=%8.8lx\r\n"), paPFN));
ZeroPage((LPBYTE)Phys2Virt(paPFN)+0x20000000);
KCall((PKFN)LinkPhysPage,Phys2Virt(paPFN));
// If there are enough free pages, clear the PageOutNeeded flag.
if (PageFreeCount > PageOutLevel)
PageOutNeeded = 0;
}
LeaveCriticalSection(&PhysCS);
}
}
LPVOID PhysPageToZero (PHYSICAL_ADDRESS paPFN)
{
PFREEINFO pfi;
uint ix;
LPVOID pPage = NULL;
if ((pfi = GetRegionFromAddr(paPFN)) != 0) {
ix = (paPFN - pfi->paStart) / PFN_INCR;
DEBUGMSG(ZONE_PHYSMEM, (TEXT("PhysPageToZero: PFN=%8.8lx ix=%x rc=%d\r\n"), paPFN,
ix, pfi->pUseMap[ix]));
EnterPhysCS();
DEBUGCHK(pfi->pUseMap[ix] != 0);
if ((pfi->pUseMap[ix] != 0xff) && (!--pfi->pUseMap[ix])) {
DEBUGMSG(ZONE_PHYSMEM, (TEXT("PhysPageToZero: PFN=%8.8lx\r\n"), paPFN));
pPage = (LPVOID) Phys2VirtUC (paPFN);
DEBUGCHK (pPage);
// set pfi->pUseMap[ix] = 0xff to avoid being used by GetContigiousPages, which
// scans pUseMap to find pages.
pfi->pUseMap[ix] = 0xff;
// save &pfi->pUseMap[ix] on the page so we can clean it later
*(LPDWORD) ((DWORD)pPage + sizeof(LPVOID)) = (DWORD) &pfi->pUseMap[ix];
}
LeaveCriticalSection(&PhysCS);
}
return pPage;
}
void ZeroAndLinkPhysPage (LPVOID pPage)
{
LPBYTE pUseMap = (LPBYTE) (*(LPDWORD) ((DWORD)pPage + sizeof(LPVOID)));
DEBUGMSG(ZONE_PHYSMEM, (TEXT("ZeroAndLinkPhysPage: pPage=%8.8lx\r\n"), pPage));
DEBUGCHK ((DWORD)pPage & 0x20000000); // MUST BE A UNCACHED ADDRESS
ZeroPage (pPage);
EnterPhysCS ();
// reset pfi->pUseMap[ix] to 0 (set to 0xff in PhysPageToZero)
DEBUGCHK (0xff == *pUseMap);
*pUseMap = 0;
KCall((PKFN)LinkPhysPage, (LPBYTE) pPage - 0x20000000); // LinkPhysPage takes cached address as argument
// If there are enough free pages, clear the PageOutNeeded flag.
if (PageFreeCount > PageOutLevel)
PageOutNeeded = 0;
LeaveCriticalSection (&PhysCS);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
TakeSpecificPage(
PFREEINFO pfi,
uint ix,
LPBYTE pMem
)
{
KCALLPROFON(40);
if (pfi->pUseMap[ix]) {
KCALLPROFOFF(40);
return FALSE;
}
pfi->pUseMap[ix] = 1;
UnlinkPhysPage(pMem);
KCALLPROFOFF(40);
return TRUE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPBYTE
GiveSpecificPage(
PFREEINFO pfi,
uint ix,
LPBYTE pMem
)
{
KCALLPROFON(40);
if (pfi->pUseMap[ix] != 1) {
KCALLPROFOFF(40);
return 0;
}
pfi->pUseMap[ix] = 0;
LinkPhysPageOnly(pMem);
KCALLPROFOFF(40);
return pMem;
}
//------------------------------------------------------------------------------
//
// Try to grab physically contiguous pages. This routine needs to be preemptive
// as much as possible, so we may take some pages and end up giving them back if
// a full string of pages can't be found. Pages are potentially coming and
// going, but we'll only make one pass through memory.
//
//------------------------------------------------------------------------------
PHYSICAL_ADDRESS
GetContiguousPages(
DWORD dwPages,
DWORD dwAlignment,
DWORD dwFlags
)
{
PFREEINFO pfi, pfiEnd;
uint ixWalk, ixTarget, ixStart, ixTotal, ixTemp;
PHYSICAL_ADDRESS paRet = INVALID_PHYSICAL_ADDRESS;
DWORD pfc;
if (((DWORD) PageFreeCount > dwPages + MIN_PROCESS_PAGES) && HoldPages(dwPages, FALSE)) {
//
// We've at least got enough pages available and that many have been set
// aside for us (though not yet assigned).
//
pfi = &MemoryInfo.pFi[0];
pfiEnd = pfi + MemoryInfo.cFi;
for (; pfi < pfiEnd ; ++pfi) {
//
// For each memory section, scan the free pages.
//
ixTotal = (pfi->paEnd - pfi->paStart) / PFN_INCR;
//
// Find a string of free pages
//
for (ixStart = 0; ixStart <= (ixTotal - dwPages); ) {
if (pfi->pUseMap[ixStart] || (dwAlignment & PFN2PA(pfi->paStart + (ixStart * PFN_INCR))) ) {
//
// Page in use or doesn't match alignment request, skip ahead
//
ixStart++;
} else {
ixTarget = ixStart + dwPages;
for (ixWalk = ixStart; ixWalk < ixTarget; ixWalk++) {
if (pfi->pUseMap[ixWalk] ||
!KCall((PKFN)TakeSpecificPage, pfi, ixWalk, Phys2Virt(pfi->paStart + (ixWalk * PFN_INCR)))) {
//
// Page in use, free all the pages so far and reset start
//
for (ixTemp = ixStart; ixTemp < ixWalk; ixTemp++) {
KCall((PKFN)GiveSpecificPage, pfi, ixTemp, Phys2Virt(pfi->paStart + (ixTemp * PFN_INCR)));
}
ixStart = ixWalk + 1;
break;
}
}
if (ixWalk == ixTarget) {
paRet = pfi->paStart + (ixStart * PFN_INCR);
goto foundPages;
}
}
}
}
//
// We couldn't lock down a contiguous section so free up the "held"
// pages before leaving.
//
do {
pfc = PageFreeCount;
} while (InterlockedTestExchange(&PageFreeCount,pfc,pfc+dwPages) != (LONG)pfc);
}
foundPages:
DEBUGMSG(ZONE_PHYSMEM,(TEXT("GetContiguousPages: Returning %8.8lx\r\n"), paRet));
return paRet;
}
ERRFALSE(sizeof(SECTION) == 2048);
#if PAGE_SIZE == 4096
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PSECTION
GetSection(void)
{
PHYSICAL_ADDRESS pAddr;
if ((PageFreeCount > 1+MIN_PROCESS_PAGES) && HoldPages(1, FALSE)) {
if (pAddr = GetHeldPage()) {
InterlockedIncrement(&KInfoTable[KINX_SYSPAGES]);
return Phys2Virt(pAddr); // can't put GetHeldPage, since Phys2Virt's a macro!
}
InterlockedIncrement(&PageFreeCount);
}
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FreeSection(
PSECTION pscn
)
{
#if defined (MIPS) || defined (SHx)
// MIPS and SHx: flush TLB since the same ASID can be reused by new process
OEMCacheRangeFlush (0, 0, CACHE_SYNC_DISCARD | CACHE_SYNC_FLUSH_TLB);
#else
OEMCacheRangeFlush (0, 0, CACHE_SYNC_DISCARD);
#endif
FreePhysPage(GetPFN(pscn));
InterlockedDecrement(&KInfoTable[KINX_SYSPAGES]);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
GetHelperStack(void)
{
return AllocMem(HEAP_HLPRSTK);
// return GetSection();
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FreeHelperStack(
LPVOID pMem
)
{
FreeMem(pMem,HEAP_HLPRSTK);
// FreeSection(pMem);
}
#else
ERRFALSE((sizeof(SECTION)+PAGE_SIZE-1)/PAGE_SIZE == 2);
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FreeSection(
PSECTION pscn
)
{
PHYSICAL_ADDRESS paSect;
paSect = GetPFN(pscn);
OEMCacheRangeFlush (0, 0, CACHE_SYNC_DISCARD);
FreePhysPage(paSect);
FreePhysPage(NextPFN(paSect));
InterlockedDecrement(&KInfoTable[KINX_SYSPAGES]);
InterlockedDecrement(&KInfoTable[KINX_SYSPAGES]);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPBYTE
TakeTwoPages(
PFREEINFO pfi,
uint ix,
LPBYTE pMem
)
{
KCALLPROFON(40);
if (pfi->pUseMap[ix] || pfi->pUseMap[ix+1]) {
KCALLPROFOFF(40);
return 0;
}
pfi->pUseMap[ix] = 1;
pfi->pUseMap[ix+1] = 1;
UnlinkPhysPage(pMem);
UnlinkPhysPage(pMem+PAGE_SIZE);
KCALLPROFOFF(40);
return pMem;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PSECTION
GetSection(void)
{
PFREEINFO pfi, pfiEnd;
uint ix;
PHYSICAL_ADDRESS paSect;
PSECTION pscn = 0;
LPVOID pMem;
while (pMem = InterlockedPopList(&pFreeKStacks))
FreeHelperStack(pMem);
if ((PageFreeCount > 2+MIN_PROCESS_PAGES) && HoldPages(2, FALSE)) {
pfi = &MemoryInfo.pFi[0];
for (pfi = &MemoryInfo.pFi[0], pfiEnd = pfi+MemoryInfo.cFi ; pfi < pfiEnd ; ++pfi) {
paSect = pfi->paEnd - 2 * PFN_INCR;
ix = (paSect - pfi->paStart) / PFN_INCR;
while (paSect >= pfi->paStart) {
if (pscn = (PSECTION)KCall((PKFN)TakeTwoPages,pfi,ix,Phys2Virt(paSect))) {
InterlockedIncrement(&KInfoTable[KINX_SYSPAGES]);
InterlockedIncrement(&KInfoTable[KINX_SYSPAGES]);
goto foundPages;
}
ix--;
paSect -= PFN_INCR;
}
}
InterlockedIncrement(&PageFreeCount);
InterlockedIncrement(&PageFreeCount);
}
foundPages:
DEBUGMSG(ZONE_PHYSMEM,(TEXT("GetSection: Returning %8.8lx\r\n"), pscn));
return pscn;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
GetHelperStack(void)
{
PHYSICAL_ADDRESS pAddr;
if (HoldPages(1, FALSE)) {
if (pAddr = GetHeldPage()) {
InterlockedIncrement(&KInfoTable[KINX_SYSPAGES]);
return Phys2Virt(pAddr); // can't put GetHeldPage, since Phys2Virt's a macro!
}
InterlockedIncrement(&PageFreeCount);
}
return 0;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
FreeHelperStack(
LPVOID pMem
)
{
OEMCacheRangeFlush (0, 0, CACHE_SYNC_DISCARD);
FreePhysPage(GetPFN(pMem));
InterlockedDecrement(&KInfoTable[KINX_SYSPAGES]);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -