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

📄 fault.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 5 页
字号:
//
// 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.
//

/*+
    fault.c - iX86 fault handlers
 */
#include "kernel.h"

// disable short jump warning.
#pragma warning(disable:4414)

///#define LIGHTS(n)   mov dword ptr ss:[0AA001010h], ~(n)&0xFF

extern RETADDR ServerCallReturn(PSVRRTNSTRUCT psrs);
extern RETADDR CallbackReturn (LPDWORD pLinkage);
extern RETADDR ObjectCall (POBJCALLSTRUCT pobs);
extern RETADDR MapArgs(const CINFO *pci, int iMethod, void *args);
extern BOOL HandleException(PTHREAD pth, int id, ulong addr);
extern void NextThread(void);
extern void KCNextThread(void);
extern void OEMIdle(void);
extern KTSS MainTSS;
extern void Reschedule(void);
extern void RunThread(void);
extern void DumpTctx(PTHREAD pth, int id, ulong addr, int level);

extern DWORD (*pfnOEMIntrOccurs) (DWORD dwSysIntr);

RETADDR PerformCallBackExt (POBJCALLSTRUCT pobs);

extern unsigned __int64 g_aGlobalDescriptorTable[];
extern CRITICAL_SECTION VAcs;

#ifdef NKPROF
extern void ProfilerHit(unsigned long ra);
extern void CeLogInterrupt(DWORD dwLogValue);
#endif
void CeLogThreadMigrate(HANDLE hProcess, DWORD dwReserved);

#define LOAD_SEGS    0

#define ADDR_SLOT_SIZE  0x02000000
#define PDES_PER_SLOT   (ADDR_SLOT_SIZE / 1024 / PAGE_SIZE)

#define NUM_SLOTS        32
#define PID_TO_PT_INDEX(pid) ((pid+1) * PDES_PER_SLOT)


#define BLOCKS_PER_PAGE_TABLE (1024 / PAGES_PER_BLOCK)
#define BLOCK_SIZE (PAGES_PER_BLOCK * PAGE_SIZE)

#define SYSCALL_INT         0x20
#define KCALL_INT           0x22

#define PT_PTR_TO_INDEX(pp) ((pp) - g_pptbl)

extern PPAGETABLE g_pPageDir;
extern DWORD ProcessorFeatures;

FXSAVE_AREA g_InitialFPUState;
PTHREAD g_CurFPUOwner;

DWORD  MD_CBRtn;
#ifdef NKPROF
PTHREAD pthFakeStruct;
#endif

//
//  CR0 bit definitions for numeric coprocessor
//
#define MP_MASK     0x00000002
#define EM_MASK     0x00000004
#define TS_MASK     0x00000008
#define NE_MASK     0x00000020

#define NPX_CW_PRECISION_MASK   0x300
#define NPX_CW_PRECISION_24     0x000
#define NPX_CW_PRECISION_53     0x200
#define NPX_CW_PRECISION_64     0x300


#define VA_TO_PD_IDX(va)        ((DWORD) (va) >> 22)        // (va)/4M == PDE idx
#define PD_IDX_TO_VA(idx)       ((DWORD) (idx) << 22)      // PDE idx * 4M == va base


#define PERFORMCALLBACK     -113    // MUST be -PerformCallback Win32Methods in kwin32.c 
                                    // 113 == -(APISet 0, method 113)
#define RAISEEXCEPTION      -114    // MUST be -RaiseException Win32Methods in kwin32.c
#define hCurThd  [KData].ahSys[SH_CURTHREAD*4]
#define PtrCurThd  [KData].pCurThd
#define PtrCurProc  [KData].pCurPrc

#define THREAD_CTX_ES  (THREAD_CONTEXT_OFFSET+8)
ERRFALSE(8 == offsetof(CPUCONTEXT, TcxEs));
#define THREAD_CTX_EDI  (THREAD_CONTEXT_OFFSET+16)
ERRFALSE(16 == offsetof(CPUCONTEXT, TcxEdi));

#define Naked void __declspec(naked)

// #define ONE_ENTRY

#pragma warning(disable:4035)               // Disable warning about no return value

//
// The Physical to Virtual mapping table is supplied by OEM.
//
extern PPTE g_pOEMAddressTable;

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;
            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;
}


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;

#define MAPPER_SLOT_TO_PTBL(slot)   (gHwPTBL2G + HARDWARE_PT_PER_PROC * ((slot) - 32))

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 and setup top-level page table
        DWORD dwVA = (DWORD) KCall((PKFN)GrabFirstPhysPage,1);
        if (!dwVA) {
            // 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] = LIN_TO_PHYS (dwVA) | ((SECURE_VMBASE == dwBase)? PG_KRN_READ_WRITE : PG_READ_WRITE);

        DEBUGMSG (ZONE_VIRTMEM, (L"MDAllocMemBlock: Allocated a new page for Page Table va = %8.8lx, entry = %8.8lx\r\n",
            dwVA, 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) (PHYS_TO_LIN (pPtbls[ixTbl] & -PAGE_SIZE) + ((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;
    // can not 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 (&g_pPageDir->PTE[(dwVMBase >> 22)], 0, HARDWARE_PT_PER_PROC * 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 (pPtbls[i] & -PAGE_SIZE);
            pPtbls[i] = 0;
        }
    }
    KCall ((FARPROC) 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);
}

//------------------------------------------------------------------------------
// LoadPageTable: handle Page Fault exception
//      addr: address that causes the fault
//      dwErrCode: the error code. (reference: x86 spec)
//                  bit 0 (P): if page mapping is present
//                  bit 1 (R/W): Read or write access 
//                  bit 2 (U/S): user or supervisor mode
//------------------------------------------------------------------------------
#define PFCODE_PRESENT      0x01        // present
#define PFCODE_WRITE        0x02        // trying to write
#define PFCODE_USER_MODE    0x04        // in user mode

BOOL LoadPageTable (DWORD addr, DWORD dwErrCode)
{
    DWORD   dwSlot = addr >> VA_SECTION, aky = 0;
    DWORD   bitClear = 0;

    //DEBUGMSG (ZONE_VIRTMEM, (L"LoadPageTable: addr = %8.8lx\r\n", addr));
    if (!IsKernelVa(addr)       // not kernel address
        && (((dwSlot = addr >> VA_SECTION) <= 1)                    // current process or slot 1
            || (dwSlot > MAX_PROCESSES)                             // memmap area
            || ((aky = 1 << (dwSlot-1)) & CurAKey))) {              // slotted process address, have access to the slot

        LPDWORD pPtbls;
        DWORD   ix4M = (addr >> 22);

        switch (dwSlot) {
        case SECURE_SECTION:
            // secure slot, use NK's page table
            pPtbls = ProcArray[0].pPTBL;
            break;
        case 0:
            pPtbls = pCurProc->pPTBL;
            break;
            
        case MODULE_SECTION:
            // module section (slot 1), use 1st 8 entries of gHwPTBL2G
            pPtbls = gHwPTBL2G;
            break;
            
        case SHARED_SECTION:
            // write access requires kernel mode
            if ((dwErrCode & (PFCODE_WRITE|PFCODE_USER_MODE)) == (PFCODE_WRITE|PFCODE_USER_MODE)) {
                return FALSE;
            }

            // user mode read-only
            if (dwErrCode & PFCODE_USER_MODE) {
                bitClear = PG_WRITE_MASK;
                
            } else if (dwErrCode & PFCODE_PRESENT) {
                // kernel mode trying to write, while page directory still marked R/O
                // just clear the page directory and we'll fill in the right access
                // DEBUGCHK (dwErrCode & PFCODE_WRITE)
                g_pPageDir->PTE[ix4M] = 0;
            }

            // fall through
        default:
            // either a sloted process address or 2nd gig
            if (dwSlot <= MAX_PROCESSES) {
                DEBUGCHK (dwSlot > 1);
                // process address
                pPtbls = ProcArray[dwSlot-1].pPTBL;
                gdwSlotTouched |= aky;
            } else {
                // in the 2nd gig
                pPtbls = MAPPER_SLOT_TO_PTBL(dwSlot);

                // check object store
                if (IsSlotInObjStore (dwSlot)) {
                    if (!(CurAKey & pFileSysProc->aky))
                        return FALSE;           // don't have access

                    gfObjStoreTouched = TRUE;
                }
            }
            break;
        }

        if (pPtbls[ix4M & 7] && !g_pPageDir->PTE[ix4M]) {
            
            // we have an entry on the per-slot page table, but not on HW PageTable
            g_pPageDir->PTE[ix4M] = pPtbls[ix4M & 7] & ~bitClear;
            
            return TRUE;
        }
    }
    DEBUGMSG (ZONE_VIRTMEM, (L"LoadPageTable failed, addr = %8.8lx, dwSlot = %8.8lx, aky = %8.8lx, CurAKey = %8.8lx\r\n", addr, dwSlot, aky, CurAKey));
    return FALSE;
}




//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
PVOID 
Phys2Virt(
    DWORD pfn
    ) 
{
    PPTE ppte;

    for (ppte = g_pOEMAddressTable; ppte->dwSize; ppte ++) {
        if ((pfn >= ppte->dwPA) && (pfn < ppte->dwPA + ppte->dwSize))
            return (LPVOID) (pfn - ppte->dwPA + ppte->dwVA);
    }

    DEBUGMSG(ZONE_PHYSMEM, (TEXT("Phys2Virt() : PFN (0x%08X) not found!\r\n"), pfn));
    return NULL;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -