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

📄 physmem.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
#include "kernel.h"

//#define PHYSPAGESTOLEDS 1

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

#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;
LPBYTE pDirtyList;

// the maximum (lowest) priority to keep a thread's stack from being scavanged
// any thread of this priority or higher will never have its stack scvanaged.
// stack scavanging will never occur if set to 255
DWORD dwNKMaxPrioNoScav = 247;  // default to lowest RT priority

extern void FreeSpareBytes(LPBYTE lpb, uint size);

extern CRITICAL_SECTION PhysCS;
extern CRITICAL_SECTION DirtyPageCS;
extern PTHREAD pCleanupThread;
extern DWORD dwOEMCleanPages;

// 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.

static DWORD PFNReserveStart;   // starting PFN of the reserved memory
static DWORD PFNReserveEnd;     // ending PFN of the reserved memory

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PFREEINFO GetRegionFromAddr(PHYSICAL_ADDRESS addr)
{
    // don't free the reserved area
    if ((addr >= PFNReserveEnd) || (addr < PFNReserveStart)) {
        PFREEINFO pfi, pfiEnd;
        pfi = MemoryInfo.pFi;
        pfiEnd = pfi + MemoryInfo.cFi;
        for ( ; pfi < pfiEnd ; pfi++) {
            if (addr >= pfi->paStart && addr < pfi->paEnd)
                return pfi;
        }
    }
    return NULL;
}

void SetOOMEvt (void)
{
    ACCESSKEY oldKey;
    SWITCHKEY (oldKey, 0xffffffff);
    SetEvent(GwesOOMEvent);
    SETCURKEY (oldKey);
}

//------------------------------------------------------------------------------
//  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
    ) 
{
    TRUSTED_API_VOID (L"SC_SetGwesOOMEvent");
    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"));
}




//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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);
}




//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void 
LinkPhysPageOnly(
    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;
    KCALLPROFOFF(32);
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
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);
}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void 
LinkPhysPageList(
    LPBYTE pListStart,
    LPBYTE pListEnd,
    DWORD cPages
    ) 
{
    PFREEINFO pfi, pfiEnd;

    KCALLPROFON(32);
    *(LPBYTE *)((DWORD)pListEnd + 0x20000000) = LogPtr->pKList;
    if (LogPtr->pKList)
        *(LPBYTE *)((DWORD)LogPtr->pKList + 0x20000004) = pListEnd;
    LogPtr->pKList = pListStart;
    PageFreeCount += cPages;
    LogPhysicalPages(PageFreeCount);
    // restore end address of each memory section, loop less than MAX_MEMORY_SECTIONS times
    for (pfi = &MemoryInfo.pFi[0], pfiEnd = pfi+MemoryInfo.cFi ; pfi < pfiEnd ; ++pfi) {
        pfi->paEnd = pfi->paRealEnd;
    }
    KCALLPROFOFF(32);
}



//------------------------------------------------------------------------------
//
// GrabFirstPhysPage gets the next available physical page from the kernel's
// linked list of free pages (LogPtr->pKList).
//
//------------------------------------------------------------------------------
LPBYTE 
GrabFirstPhysPage(
    DWORD dwCount
    ) 
{
    PFREEINFO pfi;
    uint ix;
    PHYSICAL_ADDRESS paRet;
    LPBYTE pMem = NULL;
    
    KCALLPROFON(33);

    // need to check PageFreecount instead of LogPtr->pKList or we might end up
    // with PageFreeCount < 0, and DEBUGCHK'd
    if (PageFreeCount) {
        
        pMem = LogPtr->pKList;
        paRet = GetPFN(pMem);
        pfi = GetRegionFromAddr(paRet);
        
        if (pfi) {
            //
            // Unlink the first page (first two DWORD's are link pointers).
            // Accesses are uncached.
            //
            if (LogPtr->pKList = *(LPBYTE *)((DWORD)pMem + 0x20000000)) {
                *(LPBYTE *)((DWORD)LogPtr->pKList + 0x20000004) = 0;
            }
            //
            // Clear out the link info so we have a clean page.
            //
            *(LPDWORD)(pMem + 0x20000000) = 0;
            *(LPDWORD)(pMem + 0x20000004) = 0;
            
            ix = (paRet - pfi->paStart) / PFN_INCR;
            DEBUGCHK(pfi->pUseMap[ix] == 0);
            DEBUGCHK(dwCount && (dwCount <= 0xff));
            pfi->pUseMap[ix] = (BYTE)dwCount;
            if (-- PageFreeCount < (long) KInfoTable[KINX_MINPAGEFREE]) {
                KInfoTable[KINX_MINPAGEFREE] = PageFreeCount;
            }
            LogPhysicalPages(PageFreeCount);
            DEBUGCHK(PageFreeCount >= 0);
        } else {
            ERRORMSG(1, (TEXT("GrabFirstPhysPage : invalid address 0x%08x (PFN 0x%08x)\r\n"), pMem, paRet));
            DEBUGCHK(0);
            pMem = NULL;
        }
    }
    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);
    
    if (pfi) {
        ix = (pfn - pfi->paStart) / PFN_INCR;
        pfi->pUseMap[ix] = 0xff;
    } else {
        ERRORMSG(1, (TEXT("RemovePage : removing invalid address 0x%08x (PFN 0x%08x)\r\n"), dwAddr, pfn));
        DEBUGCHK(0);
    }
}


_inline BOOL ValidateStack (PTHREAD pth, DWORD dwCurSP)
{
    DWORD lb, ub;

    NKGetStackLimits (pth, &lb, &ub);

    return (dwCurSP > lb) && (dwCurSP < ub);
}

//------------------------------------------------------------------------------
//
// DemandCommit is used to automatically commit stack pages. It is called 
// at the start of the exception handling code since the exception handlers
// need to use the stack. 
//
//------------------------------------------------------------------------------
DWORD 
DemandCommit(
    ulong addr,
    PTHREAD pth
    ) 
{
    DWORD dwRet = DCMT_NEW;
    extern void (*lpNKHaltSystem)(void);

    if (pth != pCurThread) {
        // this can only happen when we created a faked thread structure on KStack. Always return success.
        return DCMT_OLD;
    }

    if (IsKernelVa (addr)) {
        // only kernel thread can have a stack with kernel address
        dwRet = (ProcArray == pth->pOwnerProc)? DCMT_OLD : DCMT_FAILED;
        // but because IPSM changes sp to kernel address, we can't do the strict check...
        // dwRet = (KERN_TRUST_FULL == pth->pProc->bTrustLevel)? DCMT_OLD : DCMT_FAILED;

    // TLSPTR and stack must be in the same slot        
    } else if (((addr ^ (DWORD) pth->tlsPtr) & 0xFE000000) || !ValidateStack (pth, addr)) {
        dwRet = DCMT_FAILED;

    } else {
        MEMBLOCK *pmb;
        LPDWORD pPage;
        PFREEINFO pfi;
        uint ix;
        PHYSICAL_ADDRESS paRet;
        LPBYTE pMem;
        PSECTION pscn = (addr & 0x80000000)? &NKSection : SectionTable[addr>>VA_SECTION];

        // valid memblock?
        if (!(pmb = (*pscn)[(addr>>VA_BLOCK) & BLOCK_MASK])
            || (RESERVED_BLOCK == pmb)) {
            dwRet = DCMT_FAILED;

        // page already commited?
        } else if (*(pPage = &pmb->aPages[(addr>>VA_PAGE) & PAGE_MASK])) {
            dwRet = (*pPage & PG_VALID_MASK)? DCMT_OLD : DCMT_FAILED;

        } else {
            // commit a new page
            pMem = LogPtr->pKList;

            if (GwesOOMEvent && (PageFreeCount < GwesCriticalThreshold)) {
                SetOOMEvt ();
            }
            
            if (!PageFreeCount || !pMem) {
                RETAILMSG(1,(L"--->>> DemandCommit: FATAL ERROR!  COMPLETELY OUT OF MEMORY (%8.8lx %8.8lx)!\r\n",pMem,PageFreeCount));
                lpNKHaltSystem ();
                INTERRUPTS_OFF();
                while (1) {
                    // we don't recover if there's no memory, so better off to just stop
                }
            }
            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);
            if (pfi) {
                ix = (paRet - pfi->paStart) / PFN_INCR;
                DEBUGCHK(!pfi->pUseMap[ix]);
                pfi->pUseMap[ix] = 1;
#ifdef ARM
                *pPage = paRet | ((pscn == &NKSection)? PG_KRN_READ_WRITE : PG_READ_WRITE);
#else
                *pPage = paRet | PG_READ_WRITE;
#endif
                if (-- PageFreeCount < (long) KInfoTable[KINX_MINPAGEFREE]) {
                    KInfoTable[KINX_MINPAGEFREE] = PageFreeCount;
                }
                LogPhysicalPages(PageFreeCount);
                DEBUGCHK(PageFreeCount >= 0);
                return DCMT_NEW;
            }
            ERRORMSG(1, (TEXT("DemandCommit : invalid address 0x%08x (PFN 0x%08x)\r\n"), pMem, paRet));
            DEBUGCHK(0);
            dwRet = DCMT_FAILED;
        }
    }

        
    if (DCMT_FAILED == dwRet) {
        // make sure TLS is okay
        KSTKBASE(pth) = pth->dwOrigBase;
        KSTKBOUND(pth) = (DWORD) pth->tlsPtr & -PAGE_SIZE;
        KPROCSTKSIZE(pth) = pth->dwOrigStkSize;
        KTHRDINFO(pth) = pth->tlsPtr[PRETLS_CURFIBER] = 0;
        pth->tlsPtr[TLSSLOT_KERNEL] = 0;
    }
    
    return dwRet;

}



//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void 
EnterPhysCS(void) 
{
    LPVOID pMem;
    EnterCriticalSection(&PhysCS);
    DEBUGCHK(PhysCS.OwnerThread == hCurThread);

⌨️ 快捷键说明

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