⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fault.c

📁 可用于嵌入式编程学习
💻 C
📖 第 1 页 / 共 4 页
字号:
            // 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 + -