📄 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_VMEMvoid 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(); } } } } } } } }}#endifvoid 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 + -