📄 fault.c
字号:
// Remember the keys which have been used for SetCPUASID().
g_PageDirAccess |= ReqKey;
}
// pDirEntry points to the entry of the page directory corresponding to
// the address which faulted. Unless the fault occurred in the alias
// area, in which case pDirEntry is the real entry, we will fix up both
// regardless
pDirEntry = &g_PageDir.PTE[ulDirFaultIdx];
if ((*pDirEntry & PG_VALID_MASK) == 0)
{
DWORD dwPageTableEntry;
//
// Allocate a page to be used as the 1st level Page Table in the
// Page Directory
//
pPageTable = AllocFreePTE(ulDirFaultIdx);
#ifdef DEBUG_VMEM
{
int i;
for (i = 0; i < ARRAY_SIZE(pPageTable->PTE); i++)
{
if (pPageTable->PTE[i] != 0)
{
NKDbgPrintfW(
TEXT("LowAddrSpacePageFault: AllocFreePTE returned a PDE with nonzero entries\r\n"));
NKDbgPrintfW(
TEXT("pPageTable = 0x%8.8X, PTE index = %d\r\n"),
pPageTable, i);
DebugBreak();
}
}
}
#endif
dwPageTableEntry = LIN_TO_PHYS(pPageTable) + PG_READ_WRITE;
*pDirEntry = g_ShadowPageDir.PTE[ulDirFaultIdx] = dwPageTableEntry;
//
// If the current process owns the page, then we need to initialize
// the alias page table pointer in slot 0.
//
if ((DWORD)(pCurProc->procnum + 1) == ulDirFaultIdx / PDES_PER_SLOT)
{
g_PageDir.PTE[ulDirFaultIdx % PDES_PER_SLOT] = dwPageTableEntry;
}
}
else
{
//
// There is already a 1st level Page Table page in the
// faulting Page Directory entry
//
pPageTable = (PPAGETABLE)PHYS_TO_LIN(*pDirEntry & PG_PHYS_ADDR_MASK);
// Is this a spurious page fault?
OldPTE = pPageTable->PTE[((ULONG)pvAddr/PAGE_SIZE)&0x3ff];
}
//
// Now pPageTable points to the 2nd level Page Table page
//
ulBlockIndex = (DWORD)pvAddr / BLOCK_SIZE % BLOCKS_PER_PAGE_TABLE;
memcpy(&pPageTable->PTE[ulBlockIndex * PAGES_PER_BLOCK], pmb->aPages, sizeof(pmb->aPages));
pDirtyRange = &g_PTDirtyRegion[PT_PTR_TO_INDEX(pPageTable)];
if (pDirtyRange->ulStartBlock > ulBlockIndex)
pDirtyRange->ulStartBlock = ulBlockIndex;
ulBlockIndex++;
if (pDirtyRange->ulEndBlock < ulBlockIndex)
pDirtyRange->ulEndBlock = ulBlockIndex;
// Workaround for TLB incoherency seen in some AMD processors, specifically K6-2 400
//
if (OldPDE & OldPTE & PG_VALID_MASK)
{
// The Page Tables were valid on entry. We should not have got this fault.
//
#ifdef DEBUG_VMEM
NKDbgPrintfW(
TEXT("LowAddrSpacePageFault: spurious Page Fault @0x%8.8X, PDE = 0x%8.8X, PTE = 0x%8.8X\r\n"),
pvAddr, OldPDE, OldPTE);
#endif
PhysTLBFlush();
}
return pPageTable;
}
return NULL;
}
void _inline UpdateSlot0AccessedBits(void)
{
PDWORD pRealPD = &g_PageDir.PTE[0];
PDWORD pShadow = &g_ShadowPageDir.PTE[PID_TO_PT_INDEX(pCurProc->procnum)];
do {
DWORD dwTest = *pRealPD;
if (dwTest & PG_ACCESSED_MASK)
{
#ifdef DEBUG_VMEM
if ((*pShadow & ~PG_ACCESSED_MASK) != (dwTest & ~PG_ACCESSED_MASK))
{
NKDbgPrintfW(
TEXT("UpdateSlot0AccessedBits: Real Slot 0 PDE doesn't match Shadow Process PDE\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d\r\n"),
pCurProc->procnum + 1,
pRealPD - &g_PageDir.PTE[0]);
NKDbgPrintfW(
TEXT("Real PDE = 0x%8.8X, Shadow PDE = 0x%8.8X\r\n"),
dwTest & ~PG_ACCESSED_MASK, *pShadow & ~PG_ACCESSED_MASK);
DebugBreak();
}
#endif
*pShadow = dwTest;
*pRealPD = dwTest & (~PG_ACCESSED_MASK);
}
pShadow++;
pRealPD++;
} while (pRealPD < &g_PageDir.PTE[PDES_PER_SLOT]);
}
DWORD ResetPage(PPAGETABLE pPageTable, ULONG ulIndex)
{
ULONG ulStart = g_PTDirtyRegion[ulIndex].ulStartBlock;
ULONG ulEnd = g_PTDirtyRegion[ulIndex].ulEndBlock;
if (ulEnd)
{
g_PTDirtyRegion[ulIndex].ulEndBlock = 0;
g_PTDirtyRegion[ulIndex].ulStartBlock = BLOCKS_PER_PAGE_TABLE;
memset((PBYTE)pPageTable+(ulStart*PAGES_PER_BLOCK*sizeof(DWORD)), 0,
(ulEnd-ulStart)*PAGES_PER_BLOCK*sizeof(DWORD));
}
#ifdef DEBUG_VMEM
{
int i;
for (i = 0; i < ARRAY_SIZE(pPageTable->PTE); i++)
{
if (pPageTable->PTE[i] != 0)
{
NKDbgPrintfW(
TEXT("ResetPage: Bad dirty region, PTE not zero after reset\r\n"));
NKDbgPrintfW(
TEXT("ulStartBlock = %d, ulEndBlock = %d, PTE index = %d, PTE value = 0x%8.8X\r\n"),
ulStart, ulEnd, i, pPageTable->PTE[i]);
DebugBreak();
}
}
}
#endif
return(ulEnd);
}
PPAGETABLE AllocFreePTE(ULONG ulDirIdx)
{
PPAGETABLE pPageTable;
ULONG ulMapIdx;
//
// Copy the access bits from the alias slot entries to the corresponding
// "real" slot entries.
//
UpdateSlot0AccessedBits();
//
// Start the scan where we left off last time
//
ulMapIdx = g_AccessScanIdx;
while (TRUE)
{
ULONG ulTestPDIdx = g_PTMapIdx[ulMapIdx];
DWORD dwTestPDE = g_PageDir.PTE[ulTestPDIdx];
if ((dwTestPDE & PG_ACCESSED_MASK) == 0)
{
if ((g_ShadowPageDir.PTE[ulTestPDIdx] & PG_ACCESSED_MASK) == 0)
{
PDWORD pAlias = &g_PageDir.PTE[ulTestPDIdx % PDES_PER_SLOT];
if ((*pAlias & PG_PHYS_ADDR_MASK) ==
(dwTestPDE & PG_PHYS_ADDR_MASK))
{
*pAlias = 0;
}
#ifdef DEBUG_VMEM
else
if ((DWORD)(pCurProc->procnum + 1) == ulTestPDIdx / PDES_PER_SLOT)
{
NKDbgPrintfW(
TEXT("AllocFreePTE: Slot 0 PDE doesn't match Process Slot PDE\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d\r\n"),
ulTestPDIdx / PDES_PER_SLOT, ulTestPDIdx % PDES_PER_SLOT);
NKDbgPrintfW(
TEXT("Slot 0 PDE = 0x%8.8X, Process Slot PDE = 0x%8.8X\r\n"),
*pAlias & ~PG_ACCESSED_MASK, dwTestPDE & ~PG_ACCESSED_MASK);
DebugBreak();
}
#endif
g_ShadowPageDir.PTE[ulTestPDIdx] = 0;
g_PageDir.PTE[ulTestPDIdx] = 0;
g_AccessScanIdx = (ulMapIdx+1) % PTE_POOL_SIZE; // Set up the global for the next time
g_PTMapIdx[ulMapIdx] = ulDirIdx;
pPageTable = &g_PageTablePool[ulMapIdx];
if (ResetPage(pPageTable, ulMapIdx))
{
PhysTLBFlush();
}
return(pPageTable);
}
}
else
{
g_PageDir.PTE[ulTestPDIdx] = dwTestPDE & ~PG_ACCESSED_MASK;
}
#ifdef DEBUG_VMEM
if (dwTestPDE != 0 && (g_ShadowPageDir.PTE[ulTestPDIdx] & ~PG_ACCESSED_MASK) !=
(dwTestPDE & ~PG_ACCESSED_MASK))
{
NKDbgPrintfW(
TEXT("AllocFreePTE: Shadow PDE doesn't match Process Slot PDE\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d\r\n"),
ulTestPDIdx / PDES_PER_SLOT, ulTestPDIdx % PDES_PER_SLOT);
NKDbgPrintfW(
TEXT("Shadow PDE = 0x%8.8X, Process Slot PDE = 0x%8.8X\r\n"),
g_ShadowPageDir.PTE[ulTestPDIdx] & ~PG_ACCESSED_MASK, dwTestPDE & ~PG_ACCESSED_MASK);
DebugBreak();
}
#endif
g_ShadowPageDir.PTE[ulTestPDIdx] = dwTestPDE & ~PG_ACCESSED_MASK;
ulMapIdx = (ulMapIdx+1) % PTE_POOL_SIZE;
}
}
#ifdef DEBUG_VMEM
void ValidateVirtualMemory()
{
int iRealSlotNumber;
int iSlotIndex;
PSECTION pSection;
int i, j, k;
int iFirstPageDir;
DWORD dwPageDirEntry;
PPAGETABLE pPageTable;
int iFirstMemblock;
MEMBLOCK *pMemblock;
int iFirstPTE;
DWORD dwPageTableEntry;
//
// Find the real slot associated with the alias slot 0
//
iRealSlotNumber = pCurProc->procnum + 1;
//
// Check each process slot
// - If it is the current process ensure each entry matches the
// corresponding entry in slot 0
// - Check that each entry has a backing MEMBLOCK
// - Check that each entry matches it's corresponding MEMBLOCK entry.
//
for (iSlotIndex = 1; iSlotIndex <= 32; iSlotIndex++)
{
iFirstPageDir = iSlotIndex * PDES_PER_SLOT;
pSection = SectionTable[iSlotIndex];
for (i = 0; i < PDES_PER_SLOT; i++)
{
if (iSlotIndex == iRealSlotNumber)
{
//
// If this slot is for the active process insure the alias
// area at slot 0 matches
//
if ((g_PageDir.PTE[i] & ~PG_ACCESSED_MASK) !=
(g_PageDir.PTE[i + iFirstPageDir] & ~PG_ACCESSED_MASK))
{
if (i != 0 ||
(g_PageDir.PTE[i] & ~PG_ACCESSED_MASK) != KPAGE_PTE ||
g_PageDir.PTE[i + iFirstPageDir] != 0)
{
NKDbgPrintfW(
TEXT("ValidateVirtualMemory: Slot 0 PDE doesn't match Process slot PDE\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d\r\n"), iSlotIndex, i);
NKDbgPrintfW(
TEXT("pSection = 0x%8.8X, Slot 0 PDE = 0x%8.8X, Process Slot PDE = 0x%8.8X\r\n"),
pSection, g_PageDir.PTE[i] & ~PG_ACCESSED_MASK,
g_PageDir.PTE[i + iFirstPageDir] & ~PG_ACCESSED_MASK);
DebugBreak();
}
}
}
dwPageDirEntry = g_PageDir.PTE[iFirstPageDir + i];
if (dwPageDirEntry != 0)
{
pPageTable = (PPAGETABLE)PHYS_TO_LIN(dwPageDirEntry & PG_PHYS_ADDR_MASK);
iFirstMemblock = i * BLOCKS_PER_PAGE_TABLE;
for (j = 0; j < BLOCKS_PER_PAGE_TABLE; j++)
{
pMemblock = (*pSection)[iFirstMemblock + j];
iFirstPTE = j * PAGES_PER_BLOCK;
for (k = 0; k < PAGES_PER_BLOCK; k++)
{
dwPageTableEntry = pPageTable->PTE[iFirstPTE + k];
if (dwPageTableEntry != 0)
{
if (pMemblock != NULL && pMemblock != RESERVED_BLOCK)
{
if ((dwPageTableEntry & ~0xFFF) !=
(pMemblock->aPages[k] & ~0xFFF) && pMemblock->aPages[k])
{
NKDbgPrintfW(
TEXT("ValidateVirtualMemory: PTE doesn't match MEMBLOCK entry\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d, MemBlock index = %d, Page index = %d\r\n"),
iSlotIndex, i, j, k);
NKDbgPrintfW(
TEXT("pSection = 0x%8.8X, dwPageDirEntry = 0x%8.8X, dwPageTableEntry = 0x%8.8X, dwMemblockEntry = 0x%8.8X\r\n"),
pSection, dwPageDirEntry, dwPageTableEntry, pMemblock->aPages[k]);
DebugBreak();
}
}
else
{
//
// Special case the Kernel Data Page since it
// doesn't get unmapped when a process goes
// away.
//
if (i != 0 || j != 0 || k != 5 ||
(dwPageTableEntry & ~PG_ACCESSED_MASK) != KPAGE_PTE)
{
NKDbgPrintfW(
TEXT("ValidateVirtualMemory: PTE exists without backing MEMBLOCK\r\n"));
NKDbgPrintfW(
TEXT("Slot index = %d, PDE index = %d, MemBlock index = %d, Page index = %d\r\n"),
iSlotIndex, i, j, k);
NKDbgPrintfW(
TEXT("pSection = 0x%8.8X, dwPageDirEntry = 0x%8.8X, dwPageTableEntry = 0x%8.8X\r\n"),
pSection, dwPageDirEntry, dwPageTableEntry);
DebugBreak();
}
}
}
}
}
}
}
}
}
#endif
void InvalidatePageTables(PDWORD pDirEntry, PDWORD pLastDirEntry)
{
BOOL bFlushTLB = FALSE;
PPAGETABLE pPageTable;
int idxEntry;
KCALLPROFON(72);
do {
if (*pDirEntry & PG_VALID_MASK) {
pPageTable = (PPAGETABLE)PHYS_TO_LIN(*pDirEntry & PG_PHYS_ADDR_MASK);
idxEntry = pDirEntry - &g_ShadowPageDir.PTE[0];
if (ResetPage(pPageTable, PT_PTR_TO_INDEX(pPageTable))
&& (g_PageDir.PTE[idxEntry] & PG_VALID_MASK))
bFlushTLB = TRUE;
}
pDirEntry++;
} while (pDirEntry <= pLastDirEntry);
if (bFlushTLB)
PhysTLBFlush();
KCALLPROFOFF(72);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -