📄 virtmem.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.
//
#include "kernel.h"
#define LOG(x) NKDbgPrintfW(L"%s == %8.8lx\n", TEXT(#x), x)
int FirstFreeSection = RESERVED_SECTIONS+1;
MEMBLOCK *PmbDecommitting;
extern CRITICAL_SECTION VAcs;
extern HANDLE GwesOOMEvent;
extern long GwesCriticalThreshold;
extern PFREEINFO GetRegionFromAddr(PHYSICAL_ADDRESS addr);
extern LPVOID PhysPageToZero (PHYSICAL_ADDRESS paPFN);
extern void ZeroAndLinkPhysPage (LPVOID pPage);
const DWORD AllocationType[MB_FLAG_PAGER_TYPE+1] = {MEM_PRIVATE, MEM_IMAGE, MEM_MAPPED};
BOOL (* pfnOEMSetMemoryAttributes) (LPVOID pVirtualAddr, LPVOID pPhysAddr, DWORD cbSize, DWORD dwAttributes);
static BOOL FakedOEMIsROM (LPVOID pvAddr, DWORD cbSize)
{
return FALSE;
}
BOOL (*pfnOEMIsRom) (LPVOID pvAddr, DWORD cbSize) = FakedOEMIsROM;
static LPVOID EntryToKVA (DWORD dwEntry)
{
LPVOID pRet = NULL;
if (dwEntry & PG_VALID_MASK) {
// check for VirtualCopy'd entries on MIPS and SHx seperately
#ifdef MIPS
if ((dwEntry & ~PG_PERMISSION_MASK) >= (DWORD)(0x20000000 >> PFN_SHIFT)) {
return NULL;
}
#elif defined (SHx)
if (dwEntry >= 0x20000000) {
return NULL;
}
#endif
pRet = Phys2Virt (PFNfromEntry (dwEntry));
if (pRet && ((dwEntry & PG_CACHE_MASK) == PG_NOCACHE))
pRet = (LPVOID) ((DWORD) pRet | 0x20000000);
}
return pRet;
}
PVOID VerifyAccess (LPVOID pvAddr, DWORD dwFlags, ACCESSKEY aky)
{
DWORD dwAddr = (DWORD) pvAddr;
extern LPVOID MDValidateKVA (DWORD);
if (!(dwFlags & VERIFY_KERNEL_OK) // "kernel ok" flag not set
&& (GetThreadMode(pCurThread) != KERNEL_MODE) // not in kernel mode
&& ((dwAddr & 0x80000000) // kmode only address
//#if defined (x86) || defined (ARM)
|| (IsInSharedSection (dwAddr) && (dwFlags & VERIFY_WRITE_FLAG)) // write to shared section
//#endif
)) {
return NULL;
}
if (IsKernelVa (dwAddr)) {
pvAddr = MDValidateKVA (dwAddr);
} else {
PSECTION pscn = (dwAddr & 0x80000000)? &NKSection : SectionTable[dwAddr>>VA_SECTION];
MEMBLOCK *pmb;
ulong entry;
if (pscn
&& (pmb = (*pscn)[(dwAddr>>VA_BLOCK)&BLOCK_MASK])
&& (pmb != RESERVED_BLOCK)
&& (pmb->alk & aky)
&& ((entry = pmb->aPages[(dwAddr>>VA_PAGE)&PAGE_MASK]) & PG_VALID_MASK)
&& (!(dwFlags & VERIFY_WRITE_FLAG) || IsPageWritable (entry))) {
if (!(pvAddr = EntryToKVA (entry))) {
// a VirtualCopy'd address that doesn't have a statically mapped kernel
// address equivalent. Just return the user mode VA.
//DEBUGMSG (1, (L"VerifyAccess (%8.8lx %8.8lx %8.8lx) return %8.8lx (entry = %8.8lx)\r\n", dwAddr, dwFlags, aky, dwAddr, entry));
return (LPVOID) dwAddr;
}
pvAddr = (LPVOID) ((DWORD)pvAddr | (dwAddr & (PAGE_SIZE-1)));
} else {
return NULL;
}
}
// DEBUGMSG (1, (L"VerifyAccess (%8.8lx %8.8lx %8.8lx) return %8.8lx\r\n", dwAddr, dwFlags, aky, pvAddr));
return pvAddr;
}
static BOOL IsROMNoCS (LPVOID pvAddr, DWORD cbSize)
{
PSECTION pscn;
MEMBLOCK *pmb;
DWORD dwAddr = (DWORD) pvAddr;
DWORD ixBlock, ixPage, cPages;
// kernel address: just pass it to OEM
if (IsKernelVa (pvAddr))
return pfnOEMIsRom (pvAddr, cbSize);
// consider kpageblock ROM
if (ZeroPtr (pvAddr) < 0x10000)
return TRUE;
// virtual address, figure out from VM structure
pscn = (dwAddr & 0x80000000)? &NKSection : SectionTable[dwAddr>>VA_SECTION];
ixBlock = (dwAddr >> VA_BLOCK) & BLOCK_MASK;
ixPage = (dwAddr >> VA_PAGE) & PAGE_MASK;
cPages = ((dwAddr + cbSize + PAGE_SIZE-1) / PAGE_SIZE) - (dwAddr / PAGE_SIZE);
while (cPages) {
if ((pmb = (*pscn)[ixBlock ++]) == NULL_BLOCK)
// not reserved, cannot be written to -- consider it ROM
return TRUE;
if (RESERVED_BLOCK == pmb) {
// reseved, but not commited, cannot be ROM
if ((int) (cPages -= (PAGES_PER_BLOCK - ixPage)) <= 0)
return FALSE;
} else {
// examine all pages in the memblock
for ( ; cPages && (ixPage < PAGES_PER_BLOCK); cPages --, ixPage ++ ) {
DWORD dwEntry = pmb->aPages[ixPage];
if (BAD_PAGE == dwEntry)
return TRUE;
if ((pvAddr = EntryToKVA(dwEntry))
&& pfnOEMIsRom (pvAddr, 1))
return TRUE;
}
}
ixPage = 0;
}
return FALSE;
}
BOOL IsROM (LPVOID pvAddr, DWORD cbSize)
{
BOOL fRet;
EnterCriticalSection (&VAcs);
fRet = IsROMNoCS (pvAddr, cbSize);
LeaveCriticalSection (&VAcs);
return fRet;
}
BOOL IsStackVA (DWORD dwAddr, DWORD dwLen)
{
DWORD dwStkEnd, dwStkBeg = KSTKBASE(pCurThread);
if (pCurThread->tlsPtr != pCurThread->tlsNonSecure) {
// non-trusted app
dwStkEnd = dwStkBeg + CNP_STACK_SIZE; // fix size for secure stack
} else {
dwStkEnd = dwStkBeg + (KCURFIBER(pCurThread)? KPROCSTKSIZE(pCurThread) : pCurThread->dwOrigStkSize);
}
if (!(dwAddr >> VA_SECTION)) {
dwAddr |= pCurThread->pProc->dwVMBase; // will return FALSE if dwAddr is VA of other process
}
if ((dwStkBeg < (dwAddr + dwLen)) && (dwStkEnd > dwAddr)) {
NKDbgPrintfW (L"KPROCSTKSIZE = %8.8lx (tls = %8.8lx, tlsNonSec = %8.8lx)\n", KPROCSTKSIZE(pCurThread), pCurThread->tlsPtr, pCurThread->tlsNonSecure);
NKDbgPrintfW (L"dwAddr = 0x%x, dwLen = 0x%x, dwStkBeg = 0x%x, dwStkEnd = 0x%x\n", dwAddr, dwLen, KSTKBASE(pCurThread), dwStkEnd);
DEBUGCHK (0);
return TRUE;
}
return FALSE;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
ulong
MakePagePerms(
DWORD fdwProtect, DWORD dwAddr
)
{
ulong ulMask;
ulong uWriteProt = PG_PROT_WRITE;
if (IsInSharedSection (dwAddr)
&& (PAGE_READWRITE != fdwProtect)) {
// protection at shared section must be READWRITE
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return 0;
}
#ifdef ARM
if ((dwAddr & 0x80000000)
|| ((dwAddr < (1 << VA_SECTION)) && (ProcArray == pCurProc))) {
// secure section - kmode access only
uWriteProt = PG_PROT_UNO_KRW;
} else if (IsInSharedSection (dwAddr)) {
// shared section - user R/O, kernel R/W
uWriteProt = PG_PROT_URO_KRW;
}
#endif
switch (fdwProtect & ~(PAGE_GUARD | PAGE_NOCACHE
#ifdef ARM
| PAGE_ARM_MINICACHE
#endif
#ifdef x86
| PAGE_x86_WRITETHRU
#endif
)) {
case PAGE_READONLY:
ulMask = PG_VALID_MASK | PG_PROT_READ;
break;
case PAGE_EXECUTE:
case PAGE_EXECUTE_READ:
ulMask = PG_VALID_MASK | PG_PROT_READ | PG_EXECUTE_MASK;
break;
case PAGE_EXECUTE_READWRITE:
ulMask = PG_VALID_MASK | PG_DIRTY_MASK | PG_EXECUTE_MASK | uWriteProt;
break;
case PAGE_READWRITE:
ulMask = PG_VALID_MASK | PG_DIRTY_MASK | uWriteProt;
break;
case PAGE_WRITECOPY:
case PAGE_EXECUTE_WRITECOPY:
KSetLastError(pCurThread, ERROR_NOT_SUPPORTED);
return 0;
case PAGE_NOACCESS:
if (fdwProtect != PAGE_NOACCESS) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return 0;
}
ulMask = PG_GUARD; /* dummy return value */
break;
default:
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return 0;
}
DEBUGCHK(ulMask);
if (fdwProtect & PAGE_GUARD)
ulMask = (ulMask & ~PG_VALID_MASK) | PG_GUARD;
#ifdef ARM
ulMask |= (fdwProtect & PAGE_NOCACHE) ? PG_NOCACHE : (fdwProtect & PAGE_ARM_MINICACHE) ? PG_MINICACHE : PG_CACHE;
#elif defined(x86)
ulMask |= (fdwProtect & PAGE_NOCACHE) ? PG_NOCACHE : (fdwProtect & PAGE_x86_WRITETHRU) ? PG_WRITE_THRU_MASK : PG_CACHE;
#else
ulMask |= (fdwProtect & PAGE_NOCACHE) ? PG_NOCACHE : PG_CACHE;
#endif
ulMask |= PG_SIZE_MASK;
DEBUGMSG(ZONE_VIRTMEM, (TEXT("MakePagePerms: %8.8lx returns %8.8lx\r\n"), fdwProtect, ulMask));
return ulMask;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
DWORD
ProtectFromPerms (ulong ulPage, DWORD dwAddr)
{
DWORD fdwProt;
DWORD dwWriteProt = PAGE_READWRITE;
if (IsInSharedSection (dwAddr) && !(pCurThread->tlsPtr[PRETLS_THRDINFO] & UTLS_INKMODE)) {
dwWriteProt = PAGE_READONLY;
}
switch (ulPage & (PG_PROTECTION|PG_EXECUTE_MASK)) {
case PG_PROT_READ:
fdwProt = PAGE_READONLY;
break;
case PG_PROT_WRITE:
#ifdef ARM
case PG_PROT_UNO_KRW: // secure section
case PG_PROT_URO_KRW: // shared section
#endif
fdwProt = dwWriteProt;
break;
#if PG_EXECUTE_MASK
case PG_EXECUTE_MASK|PG_PROT_READ:
fdwProt = PAGE_EXECUTE_READ;
break;
case PG_EXECUTE_MASK|PG_PROT_READ|PG_PROT_WRITE:
fdwProt = PAGE_EXECUTE_READWRITE;
break;
#endif
default: // invalid combinations get mapped to PAGE_NOACCESS
return PAGE_NOACCESS;
}
if ((ulPage & (PG_VALID_MASK|PG_GUARD)) == PG_GUARD)
fdwProt |= PAGE_GUARD;
if ((ulPage & PG_CACHE_MASK) == PG_NOCACHE)
fdwProt |= PAGE_NOCACHE;
return fdwProt;
}
BOOL NKSetMemoryAttributes (LPVOID pVirtualAddr, LPVOID pShiftedPhysAddr, DWORD cbSize, DWORD dwAttributes)
{
DWORD dwPhysAddr = (PHYSICAL_ADDRESS_UNKNOWN == pShiftedPhysAddr)? 0 : ((DWORD) pShiftedPhysAddr << 8);
BOOL fRet;
// validate parameter
if (!pfnOEMSetMemoryAttributes
|| !cbSize
|| !pVirtualAddr
|| ((DWORD) pVirtualAddr & (PAGE_SIZE-1))
|| (dwPhysAddr & (PAGE_SIZE-1))
|| (cbSize & (PAGE_SIZE-1))) {
KSetLastError (pCurThread, pfnOEMSetMemoryAttributes? ERROR_NOT_SUPPORTED : ERROR_INVALID_PARAMETER);
return FALSE;
}
EnterCriticalSection (&VAcs);
// call to OEM to set the memory attributes
// NOTE: we intentionally not checking dwAttributes so we don't have to change kernel
// in case we support more attributes in the future.
fRet = pfnOEMSetMemoryAttributes (pVirtualAddr, pShiftedPhysAddr, cbSize, dwAttributes);
LeaveCriticalSection (&VAcs);
if (!fRet) {
KSetLastError (pCurThread, ERROR_NOT_SUPPORTED);
}
return fRet;
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -