📄 mdarm.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"
#ifdef THUMBSUPPORT
#define THUMB_SUPPORT_STR TEXT("(Thumb Enabled)")
#else
#define THUMB_SUPPORT_STR TEXT(" ")
#endif
#ifdef THUMB
const wchar_t NKCpuType [] = TEXT("THUMB");
const wchar_t NKSignon[] = TEXT("Windows CE Kernel for THUMB ") THUMB_SUPPORT_STR TEXT(" Built on ") TEXT(__DATE__) TEXT(" at ") TEXT(__TIME__) TEXT("\r\n");
#else
const wchar_t NKCpuType [] = TEXT("ARM");
const wchar_t NKSignon[] = TEXT("Windows CE Kernel for ARM ") THUMB_SUPPORT_STR TEXT(" Built on ") TEXT(__DATE__) TEXT(" at ") TEXT(__TIME__) TEXT("\r\n");
#endif
extern void (*lpNKHaltSystem)(void);
extern void FakeNKHaltSystem (void);
DWORD CEProcessorType;
WORD ProcessorLevel = 4;
WORD ProcessorRevision;
#if defined(ARMV4T)
DWORD CEInstructionSet = PROCESSOR_ARM_V4T_INSTRUCTION;
#elif defined(ARMV4I)
DWORD CEInstructionSet = PROCESSOR_ARM_V4I_INSTRUCTION;
#elif defined(ARMV4)
DWORD CEInstructionSet = PROCESSOR_ARM_V4_INSTRUCTION;
#endif
DWORD CurMSec;
// Fault Status register fields:
#define FSR_DOMAIN 0xF0
#define FSR_STATUS 0x0D
#define FSR_PAGE_ERROR 0x02
#define FSR_ALIGNMENT 0x01
#define FSR_TRANSLATION 0x05
#define FSR_DOMAIN_ERROR 0x09
#define FSR_PERMISSION 0x0D
#define BREAKPOINT 0x06000010 // special undefined instruction
#define THM_BREAKPOINT 0xDEFE // Thumb equivalent
const LPCSTR IdStrings[] = {
"RaiseException", "Reschedule", "Undefined Instruction", "SWI",
"Prefetch Abort", "Data Abort", "IRQ", "<Invalid>", "<Invalid>", "[Stack fault]", "[HW Break]",
};
#define VFP_ENABLE_BIT 0x40000000
#define VFP_EX_BIT 0x80000000
DWORD vfpStat = VFP_NOT_EXIST;
extern BOOL TestVFP (void);
extern DWORD ReadAndSetFpexc (DWORD dwNewFpExc);
// NOTE: Save/Restore FloatContext do not Save/Restore fpexc
// it needs to be handled differently
extern void SaveFloatContext(PTHREAD);
extern void RestoreFloatContext(PTHREAD);
// OEM defined VFP save/restore for implementation defined control registers
typedef void (* PFN_OEMSaveRestoreVFPCtrlRegs) (LPDWORD lpExtra, int nMaxRegs);
typedef BOOL (* PFN_OEMHandleVFPException) (EXCEPTION_RECORD *er, PCONTEXT pctx);
static void FakedSaveVFPExtra (LPDWORD lpExtra, int nMaxRegs)
{
}
static void FakedRestoreVFPExtra (LPDWORD lpExtra, int nMaxRegs)
{
}
// this is a stub for now
static BOOL FakedHandleVFPException (EXCEPTION_RECORD *er, PCONTEXT pctx)
{
return FALSE;
}
PFN_OEMSaveRestoreVFPCtrlRegs pOEMSaveVFPCtrlRegs = FakedSaveVFPExtra;
PFN_OEMSaveRestoreVFPCtrlRegs pOEMRestoreVFPCtrlRegs = FakedRestoreVFPExtra;
PFN_OEMHandleVFPException pOEMHandleVFPException = FakedHandleVFPException;
// flag to indicate if VFP is touched. NOTE: Flushing VFP is NOT considered
// touching VFP
BOOL g_fVFPTouched;
#define PG_COARSE_TBL_BIT 0x01
extern CRITICAL_SECTION VAcs;
LPBYTE GrabFirstPhysPage(DWORD dwCount);
// hardware pagetable for the 2nd gig address and secure section
ulong gHwPTBL2G[32*HARDWARE_PT_PER_PROC]; // 32 == shared section + mapping address from 0x42000000 -> 0x7fffffff
DWORD gdwSlotTouched, gfObjStoreTouched;
PPTE g_pOEMAddressTable;
extern void _SetCPUASID (PTHREAD);
#define MAPPER_SLOT_TO_PTBL(slot) (gHwPTBL2G + HARDWARE_PT_PER_PROC * ((slot) - 32))
BOOL MDValidateRomChain (ROMChain_t *pROMChain)
{
PPTE ppte;
DWORD dwEnd;
for ( ; pROMChain; pROMChain = pROMChain->pNext) {
for (ppte = g_pOEMAddressTable; ppte->dwSize; ppte ++) {
dwEnd = ppte->dwVA + (ppte->dwSize << 20);
if (IsInRange (pROMChain->pTOC->physfirst, ppte->dwVA, dwEnd)) {
if (IsInRange (pROMChain->pTOC->physlast, ppte->dwVA, dwEnd)) {
// good XIP, break inner loop and go on to the next region
break;
}
// bad
NKDbgPrintfW (L"MDValidateRomChain: XIP (%8.8lx -> %8.8lx) span accross multiple memory region\r\n",
pROMChain->pTOC->physfirst, pROMChain->pTOC->physlast);
return FALSE;
}
}
if (!ppte->dwSize) {
NKDbgPrintfW (L"MDValidateRomChain: XIP (%8.8lx -> %8.8lx) doesn't exist in OEMAddressTable \r\n",
pROMChain->pTOC->physfirst, pROMChain->pTOC->physlast);
return FALSE;
}
}
return TRUE;
}
MEMBLOCK *MDAllocMemBlock (DWORD dwBase, DWORD ixBlock)
{
LPDWORD pPtbls; // which hardware PT to use
DWORD ixTbl = ixBlock >> 6; // ixTbl == which 4M block
MEMBLOCK *pmb;
DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: dwBase = %8.8lx, ixBlock = %8.8lx\r\n", dwBase, ixBlock));
DEBUGCHK (!IsKernelVa (dwBase));
DEBUGCHK (!VAcs.hCrit || (VAcs.OwnerThread == hCurThread));
switch (dwBase) {
case SECURE_VMBASE:
// secure section, use NK's page table
pPtbls = ProcArray[0].pPTBL;
break;
case MODULE_BASE_ADDRESS:
// module section (slot 1), use 1st 8 entries of gHwPTBL2G
pPtbls = gHwPTBL2G;
break;
case 0:
// current process
pPtbls = pCurProc->pPTBL;
break;
default:
// either a sloted process address or 2nd gig
if (dwBase < FIRST_MAPPER_ADDRESS) {
// process address
pPtbls = ProcArray[(dwBase >> VA_SECTION) - 1].pPTBL;
} else {
// in the 2nd gig
pPtbls = MAPPER_SLOT_TO_PTBL (dwBase >> VA_SECTION);
}
break;
}
//
// allocate a page if not allocate yet
//
if (!pPtbls[ixTbl]) {
// allocate a new page for page table
DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: pPtbls = %8.8lx ixTbl = %8.8lx\r\n", pPtbls, ixTbl));
if (!(pPtbls[ixTbl] = (DWORD) KCall((PKFN)GrabFirstPhysPage,1))) {
// Out of memory
return NULL;
}
// we're relying on the fact that the page we just got has already been zero'd
// or we need to memset it to 0 here.
pPtbls[ixTbl] |= 0x20000000; // uncached access only
DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: Allocated a new page for Page Table va = %8.8lx\r\n",
pPtbls[ixTbl]));
}
DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: Allocating MemBlock\r\n"));
// allocate MEM_BLOCK
if (pmb = AllocMem (HEAP_MEMBLOCK)) {
// initialize memblock
memset (pmb, 0, sizeof(MEMBLOCK));
// pagetable access needs to be uncached.
pmb->aPages = (LPDWORD) (pPtbls[ixTbl] + ((ixBlock << 6) & (PAGE_SIZE-1)));
}
DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: returning %8.8lx, aPages = %8.8lx\r\n", pmb, pmb->aPages));
return pmb;
}
void FreeHardwarePT (DWORD dwVMBase)
{
LPDWORD pPtbls; // which hardware PT to use
int i;
// cannot free current process, shared section, or secure section
DEBUGCHK ((dwVMBase != pCurProc->dwVMBase) && ((int) dwVMBase >= (2 << VA_SECTION)));
DEBUGCHK (!VAcs.hCrit || (VAcs.OwnerThread == hCurThread));
// clear first-level page table
memset (&FirstPT[(dwVMBase >> 20)], 0, HARDWARE_PT_PER_PROC * 4 * sizeof (ULONG));
if (dwVMBase < FIRST_MAPPER_ADDRESS) {
pPtbls = ProcArray [(dwVMBase >> VA_SECTION) - 1].pPTBL;
// per process
} else {
// 2nd gig
DEBUGCHK ((dwVMBase >= FIRST_MAPPER_ADDRESS) && (dwVMBase < LAST_MAPPER_ADDRESS));
pPtbls = MAPPER_SLOT_TO_PTBL (dwVMBase >> VA_SECTION);
}
for (i = 0; i < HARDWARE_PT_PER_PROC; i ++) {
if (pPtbls[i]) {
FreePhysPage (GetPFN (pPtbls[i]));
pPtbls[i] = 0;
}
}
OEMCacheRangeFlush (0, 0, CACHE_SYNC_FLUSH_TLB);
}
void MDFreeMemBlock (MEMBLOCK *pmb)
{
DEBUGCHK ((NULL_BLOCK != pmb) && (RESERVED_BLOCK != pmb));
DEBUGCHK (!VAcs.hCrit || (VAcs.OwnerThread == hCurThread));
#ifdef DEBUG
{
int i;
for (i = 0; i < PAGES_PER_BLOCK; i ++) {
DEBUGCHK (!pmb->aPages[i] || (pmb->aPages[i] == BAD_PAGE));
}
}
#endif
// need to zero it out incase there're bad pages.
memset (pmb->aPages, 0, PAGES_PER_BLOCK * sizeof (ulong));
FreeMem (pmb, HEAP_MEMBLOCK);
}
_inline void ClearOneSlot (DWORD dwVMBase)
{
//DEBUGMSG (ZONE_VIRTMEM, (L"ClearProcessSlot: dwVMBase = %8.8lx, PT entry = %8.8lx\r\n", dwVMBase, FirstPT + (dwVMBase >> 20)));
memset (FirstPT + (dwVMBase >> 20), 0, 32 * sizeof (DWORD));
}
void ClearSlots (void)
{
DWORD dwSlotRst;
BOOL fCleared = FALSE;
KCALLPROFON (0);
if (dwSlotRst = gdwSlotTouched & ~CurAKey) {
int i;
for (i = 1; dwSlotRst; i ++) {
if (dwSlotRst & (1 << i)) {
dwSlotRst &= ~(1 << i);
ClearOneSlot (ProcArray[i].dwVMBase);
}
}
fCleared = TRUE;
gdwSlotTouched &= CurAKey;
}
if (gfObjStoreTouched && !(pFileSysProc->aky & CurAKey)) {
DWORD dwBits = g_ObjStoreSlotBits;
int i;
for (i = 0; dwBits; i ++) {
if (dwBits & (1 << i)) {
dwBits &= ~(1 << i);
ClearOneSlot ((FIRST_MAPPER_SLOT + i) << VA_SECTION);
}
}
fCleared = TRUE;
gfObjStoreTouched = FALSE;
}
if (fCleared) {
OEMCacheRangeFlush (0, 0, CACHE_SYNC_FLUSH_TLB);
}
KCALLPROFOFF (0);
}
void SetCPUASID (PTHREAD pth)
{
_SetCPUASID (pth);
KCall ((FARPROC) ClearSlots);
}
void DetectVFP (void)
{
DEBUGMSG (1, (L"Detecting VFP..."));
vfpStat = VFP_TESTING | VFP_EXIST;
TestVFP (); // would generate an undefined-instruction exception if FPU not exist
// and ExceptionDispatch will unset the VFP_EXIST bit
vfpStat &= ~VFP_TESTING;
if (vfpStat)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -