📄 pgpool.c
字号:
//
// 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.
//
//------------------------------------------------------------------------------
//
// NK Kernel loader code
//
//
// Module Name:
//
// pgpool.c
//
// Abstract:
//
// This file implements fixed-size paging pool
//
//
//------------------------------------------------------------------------------
//
// The loader is derived from the Win32 executable file format spec. The only
// interesting thing is how we load a process. When we load a process, we
// simply schedule a thread in a new process context. That thread (in coredll)
// knows how to read in an executable, and does so. Then it traps into the kernel
// and starts running in the new process. Most of the code below is simply a direct
// implimentation of the executable file format specification
//
//------------------------------------------------------------------------------
#include "kernel.h"
#define MIN_PGPOOL_SIZE (64*PAGE_SIZE) // minimum paging pool size 256K
// uncomment the following line to debug PAGING POOL
// #define DEBUG_PAGING_POOL
#ifdef DEBUG_PAGING_POOL
#undef ZONE_PAGING
#define ZONE_PAGING 1
#endif
//
// the paging pool entry
//
// NOTE: we use index instead of direct pointer becuase we want to keep the size of this entry of
// size 16 byte. Allocation and cache is better utilized this way.
//
typedef struct _PagingPoolEntry {
WORD idxPrev; // index to the previous entry
WORD idxNext; // index to the next entry
WORD idxNextInMod; // index to the next entry of the same MOD/PROC
WORD pad; // padding
DWORD va; // VA of the page
LPVOID pModProc; // pointer to MODULE/PROC that owns this page
} PAGINGPOOL, *PPAGINGPOOL;
// the size of the paging pool. Defualt 0, which uses unlimited paging pool
DWORD cbNKPagingPoolSize = (DWORD) -1;
static LPBYTE gpPagingPool; // the paging memory pool
static PPAGINGPOOL gpPoolArr; // the paging pool structure array
static LONG gnFreePages; // total number of free pages
static WORD gidxFree; // index of the head of the free list
static WORD gidxHead; // head of the used list (circular)
extern CRITICAL_SECTION PagerCS, VAcs; // the pager critical section
#define FREE_PAGE_VA 0xabababab
BOOL InitPgPool (void)
{
int i;
#ifdef DEBUG_PAGING_POOL
cbNKPagingPoolSize = MIN_PGPOOL_SIZE;
#endif
// treat -1 as 0
if ((DWORD) -1 == cbNKPagingPoolSize) {
cbNKPagingPoolSize = 0;
}
// do nothing if not using paging pool
if (!cbNKPagingPoolSize) {
return TRUE;
}
// adjust to min/max, align to page size
if (cbNKPagingPoolSize < MIN_PGPOOL_SIZE) {
cbNKPagingPoolSize = MIN_PGPOOL_SIZE;
} else {
cbNKPagingPoolSize = PAGEALIGN_UP(cbNKPagingPoolSize);
}
// initially all pages are free
gnFreePages = (cbNKPagingPoolSize / PAGE_SIZE);
// make sure we don't have too many pages that we can account for
if ((DWORD)gnFreePages >= (DWORD) INVALID_PG_INDEX) {
gnFreePages = INVALID_PG_INDEX - 1;
cbNKPagingPoolSize = gnFreePages * PAGE_SIZE;
}
// total memory needed == PAGE_ALIGN_UP(gnFreePages * sizeof (PAGINGPOOL)) + cbNKPagingPoolSize, carve it from the begining of free RAM
gpPagingPool = (LPBYTE) (pTOC->ulRAMFree + MemForPT);
MemForPT += cbNKPagingPoolSize + PAGEALIGN_UP(gnFreePages * sizeof (PAGINGPOOL));
gpPoolArr = (PPAGINGPOOL) (gpPagingPool + cbNKPagingPoolSize);
DEBUGMSG (1, (L"Using Paging Pool, size = 0x%8.8lx, Addr = 0x%8.8lx, gpPoolArr = 0x%8.8lx\r\n", cbNKPagingPoolSize, gpPagingPool, gpPoolArr));
// initialize the free list
for (i = 0; i < gnFreePages; i ++) {
gpPoolArr[i].idxNext = (WORD) (i+1);
#ifdef DEBUG
gpPoolArr[i].va = FREE_PAGE_VA;
gpPoolArr[i].pModProc = (LPVOID) 0xabababab;
gpPoolArr[i].idxPrev = INVALID_PG_INDEX;
gpPoolArr[i].idxNextInMod = INVALID_PG_INDEX;
#endif
}
// take care of 'next' of the last element
gpPoolArr[gnFreePages-1].idxNext = INVALID_PG_INDEX;
gidxHead = INVALID_PG_INDEX;
return TRUE;
}
_inline WORD pg_dequeue (PPGPOOL_Q ppq)
{
WORD idx = ppq->idxHead;
if (INVALID_PG_INDEX != idx)
ppq->idxHead = gpPoolArr[idx].idxNextInMod;
return idx;
}
_inline void pg_enqueue (PPGPOOL_Q ppq, WORD idx)
{
DEBUGCHK (INVALID_PG_INDEX != idx);
gpPoolArr[idx].idxNextInMod = INVALID_PG_INDEX;
if (INVALID_PG_INDEX == ppq->idxHead) {
// queue was empty
ppq->idxHead = idx;
} else {
DEBUGCHK (INVALID_PG_INDEX != ppq->idxTail);
gpPoolArr[ppq->idxTail].idxNextInMod = idx;
}
ppq->idxTail = idx;
}
_inline void pg_AddToUsedPage (WORD idx)
{
if (INVALID_PG_INDEX == gidxHead) {
gpPoolArr[idx].idxNext = gpPoolArr[idx].idxPrev = gidxHead = idx;
} else {
WORD idxPrev = gpPoolArr[gidxHead].idxPrev;
gpPoolArr[idx].idxNext = gidxHead;
gpPoolArr[idx].idxPrev = idxPrev;
gpPoolArr[gidxHead].idxPrev = gpPoolArr[idxPrev].idxNext = idx;
}
}
_inline void pg_RemoveFromUsedPage (WORD idx)
{
DEBUGCHK (INVALID_PG_INDEX != idx);
if (gpPoolArr[idx].idxNext == idx) {
// last page
DEBUGCHK ((idx == gidxHead) && (idx == gpPoolArr[idx].idxPrev));
gidxHead = INVALID_PG_INDEX;
} else {
WORD idxPrev = gpPoolArr[idx].idxPrev;
WORD idxNext = gpPoolArr[idx].idxNext;
gpPoolArr[idxPrev].idxNext = idxNext;
gpPoolArr[idxNext].idxPrev = idxPrev;
if (gidxHead == idx)
gidxHead = idxNext;
}
}
static BOOL TryInvalidateAddr (DWORD dwAddr, DWORD dwInUseOrig)
{
PSECTION pscn;
MEMBLOCK *pmbMaster;
DWORD dwZeroAddr = ZeroPtr(dwAddr);
int ixBlock = (dwAddr >> VA_BLOCK) & BLOCK_MASK;
int ixPage = (dwAddr >> VA_PAGE) & PAGE_MASK;
DWORD dwEntry = 0;
DEBUGCHK (!IsKernelVa (dwAddr));
EnterCriticalSection (&VAcs);
DEBUGMSG(ZONE_PAGING,(L"TryInvalidateAddr: dwAddr = %8.8lx, dwInUseOrig = %8.8lx\r\n", dwAddr, dwInUseOrig));
// find the right section based on address
if (dwZeroAddr >= (DWORD) DllLoadBase) {
// DLL's address
DEBUGCHK ((dwZeroAddr >= (DWORD) DllLoadBase) && !(dwInUseOrig & 1));
pscn = (dwZeroAddr < (1 << VA_SECTION))? &NKSection : SectionTable[dwZeroAddr >> VA_SECTION];
} else {
// Process address or memory mapped area
DEBUGCHK (!dwInUseOrig);
pscn = SectionTable[dwAddr >> VA_SECTION];
}
pmbMaster = (*pscn)[ixBlock];
if (!pmbMaster || (NULL_BLOCK == pmbMaster) || (RESERVED_BLOCK == pmbMaster) || !pmbMaster->aPages[ixPage]) {
// the page has already freed. just return TRUE
LeaveCriticalSection (&VAcs);
return TRUE;
}
// we can only page it out if it's not locked
if (!pmbMaster->cLocks) {
dwEntry = pmbMaster->aPages[ixPage];
DEBUGCHK (dwEntry);
// if it's the old style DLL, need to make sure the page is not locked in any process
if (dwInUseOrig && (dwZeroAddr < (1 << VA_SECTION))) {
int i;
MEMBLOCK *pmb;
DWORD dwInUse;
// make sure no page is locked.
for (i = 1, dwInUse = dwInUseOrig; dwInUse; i ++) {
DEBUGCHK (i < MAX_PROCESSES);
if (dwInUse & (1 << i)) {
dwInUse &= ~(1 << i);
pmb = (*(SectionTable[i+1]))[ixBlock];
DEBUGCHK (NULL_BLOCK != pmb);
if ((RESERVED_BLOCK != pmb) && pmb->cLocks) {
// page is locked, can't page this one out
dwEntry = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -