📄 fault.c
字号:
jne short rsd20
jmp RunThread // redispatch the same thread
// Switch to a new thread's process context.
// Switching to a new thread. Update current process and address space
// information. Edit the ring0 stack pointer in the TSS to point to the
// new thread's register save area.
//
// (eax) = ptr to thread structure
rsd20: mov edi, eax // Save thread pointer
mov esi, (THREAD)[eax].hTh // (esi) = thread handle
push edi
call SetCPUASID // Sets hCurProc for us!
pop ecx // Clean up stack
mov hCurThd, esi // set the current thread handle
mov PtrCurThd, edi // and the current thread pointer
mov ecx, [edi].tlsPtr // (ecx) = thread local storage ptr
mov [KData].lpvTls, ecx // set TLS pointer
cmp edi, g_CurFPUOwner
jne SetTSBit
clts
jmp MuckWithFSBase
SetTSBit:
mov eax, CR0
test eax, TS_MASK
jnz MuckWithFSBase
or eax, TS_MASK
mov CR0, eax
MuckWithFSBase:
mov edx, offset g_aGlobalDescriptorTable+KGDT_PCR
sub ecx, FS_LIMIT+1 // (ecx) = ptr to NK_PCR base
mov word ptr [edx+2], cx // set low word of FS base
shr ecx, 16
mov byte ptr [edx+4], cl // set third byte of FS base
mov byte ptr [edx+7], ch // set high byte of FS base
lea ecx, [edi].ctx.TcxSs+4 // (ecx) = ptr to end of context save area
mov [MainTSS].Esp0, ecx
jmp RunThread // Run thread pointed to by edi
// No threads ready to run. Call OEMIdle to shutdown the cpu.
rsd50: cli
cmp ticksleft, 0
je short skip_force_reched
mov byte ptr ([KData].bResched), 1
skip_force_reched:
cmp word ptr ([KData].bResched), 1
je short DoReschedule
call OEMIdle
mov byte ptr ([KData].bResched), 1
jmp Reschedule
DoReschedule:
sti
jmp Reschedule
}
}
Naked CommonIntDispatch()
{
_asm {
cld
mov eax, KGDT_R3_DATA
mov ds, ax
mov es, ax
dec [KData].cNest
jnz short cid20 // nested fault
mov esp, offset KData-4
mov edi, PtrCurThd
cid10:
#ifdef CELOG
push esi // save ESI
mov eax, 80000000h // mark as ISR entry
push eax // Arg 0, cNest + SYSINTR_xxx
call CeLogInterrupt
pop eax // cleanup the stack from the call
pop esi // restore ESI
#endif
sti
call esi
cli
#ifdef CELOG
push eax // Save original SYSINTR return value.
bswap eax // Reverse endian
mov ah, [KData].cNest // Nesting level (0 = no nesting, -1 = nested once)
neg ah // Nesting level (0 = no nesting, 1 = nested once)
bswap eax // Reverse endian
push eax // Arg 0, cNest + SYSINTR_xxx
call CeLogInterrupt
pop eax // cleanup the stack from the call
pop eax // restore original SYSINTR value
#endif
test eax, eax
jz short cid17 // SYSINTR_NOP: nothing more to do
#ifdef NKPROF
cmp eax, SYSINTR_PROFILE
jne short cid13
call ProfilerHit
jmp cid17 // Continue on our merry way...
cid13:
#endif
cmp eax, SYSINTR_RESCHED
je short cid15
lea ecx, [eax-SYSINTR_DEVICES]
cmp ecx, SYSINTR_MAX_DEVICES
jae short cid15 // force a reschedule for good measure
// A device interrupt has been signaled. Set the appropriate bit in the pending
// events mask and set the reschedule flag. The device event will be signaled
// by the scheduler.
mov eax, 1
shl eax, cl
or [KData].aInfo[KINX_PENDEVENTS*4], eax
cid15: or [KData].bResched, 1 // must reschedule
cid17: jmp RunThread
// Nested exception. Create a fake thread structure on the stack
cid20: push ds
push es
push fs
push gs
sub esp, THREAD_CONTEXT_OFFSET
mov edi, esp // (edi) = ptr to fake thread struct
jmp short cid10
}
}
// Continue thread execution.
//
// (edi) = ptr to Thread structure
Naked RunThread()
{
_asm {
cli
cmp word ptr ([KData].bResched), 1
jne short NotReschedule
jmp Reschedule
NotReschedule:
inc [KData].cNest
lea esp, [edi].ctx.TcxGs
pop gs
pop fs
pop es
pop ds
popad
add esp, 4
iretd
cli
hlt
}
}
Naked PageFault()
{
_asm {
pushad
mov ebx, OFFSET KData
mov edi, cr2
test edi, edi
js short pf50 // Address > 2GB, get out now
dec [ebx].cNest // count kernel reentrancy level
mov esi, esp // (esi) = original stack pointer
jnz short pf10
lea esp, [ebx-4] // switch to kernel stack (&KData-4)
// Process a page fault for the "user" address space (0 to 0x7FFFFFFF)
//
// (edi) = Faulting address
// (ebx) = ptr to KData
// (esi) = Original ESP
pf10: cld // Need to do this since the page fault could have come from anywhere!
cmp dword ptr ([KData].dwInDebugger), 0 // see if debugger active
jne short pf20 // if so, skip turning on of interrupts
sti // enable interrupts
pf20: push [esi+32]
push edi
call LowAddrSpacePageFault
cli
test eax, eax
jz short pf40 // page not found in the Virtual memory tree
cmp word ptr ([KData].bResched), 1
je short pf60 // must reschedule now
inc [ebx].cNest // back out of kernel one level
mov esp, esi // restore stack pointer
popad
add esp, 4
iretd
// This one was not a good one! Jump to common fault handler
//
// (edi) = faulting address
pf40: inc [ebx].cNest // back out of kernel one level
mov esp, esi // restore stack pointer
pf50: mov ecx, edi // (ecx) = fault effective address
mov esi, 0Eh
jmp CommonFault
// The reschedule flag was set and we are at the first nest level into the kernel
// so we must reschedule now.
pf60: mov edi, PtrCurThd // (edi) = ptr to current THREAD
jmp Reschedule
}
}
Naked GeneralFault()
{
_asm {
pushad
xor ecx, ecx // (ecx) = 0 (fault effective address)
mov esi, 13
jmp CommonFault
}
}
Naked InvalidOpcode(void)
{
__asm {
push eax
pushad
mov esi, 6
xor ecx, ecx // (ecx) = 0 (fault effective address)
jmp CommonFault
}
}
Naked ZeroDivide(void)
{
__asm {
push eax
pushad
xor esi, esi // (esi) = 0 (divide by zero fault)
xor ecx, ecx // (ecx) = 0 (fault effective address)
jmp CommonFault
}
}
const BYTE PosTable[256] = {
0,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
8,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
7,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,
6,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5,1,2,1,3,1,2,1,4,1,2,1,3,1,2,1
};
void __declspec(naked) GetHighPos(DWORD foo) {
_asm {
mov ecx, dword ptr [esp + 4]
push ebx
lea ebx, PosTable
mov dl, 0xff
xor eax, eax
mov al, cl
xlatb
test al, al
jne res
shr ecx, 8
add dl, 8
mov al, cl
xlatb
test al, al
jne res
shr ecx, 8
add dl, 8
mov al, cl
xlatb
test al, al
jne res
shr ecx, 8
add dl, 8
mov al, cl
xlatb
test al, al
jne res
mov al, 9
res:
add al, dl
pop ebx
ret
}
}
Naked Int1Fault(void)
{
__asm {
push eax // Save orig EAX as fake error code
cmp word ptr [esp + 6], 0FFFFh // Is it an API call fault?
je skip_debug // Yes - handle page fault first
mov eax, [esp + 4] // (eax) = faulting EIP
and dword ptr [esp + 12], not 0100h // Clear TF if set
test byte ptr [esp + 8], 3 // Are we trying to SS ring 0?
jz skip_debug // Yes - get out quick
mov eax, dword ptr [esp] // Restore original EAX
pushad
mov esi, 1
xor ecx, ecx // (ecx) = 0 (fault effective address)
jmp CommonFault
skip_debug:
pop eax
iretd
}
}
Naked Int2Fault(void)
{
__asm {
push eax // Fake error code
pushad
mov esi, 2
xor ecx, ecx // (ecx) = 0 (fault effective address)
jmp CommonFault
}
}
Naked Int3Fault(void)
{
__asm {
dec dword ptr [esp] // Back up EIP
push eax // Fake error code
pushad
mov esi, 3
xor ecx, ecx // (ecx) = 0 (fault effective address)
jmp CommonFault
}
}
PPAGETABLE LowAddrSpacePageFault(LPVOID pvAddr, DWORD flags)
{
PSECTION pscn;
MEMBLOCK *pmb;
ULONG entry;
ACCESSKEY ReqKey;
DWORD OldPTE = 0;
DWORD OldPDE = 0;
if (((pscn = SectionTable[(ulong)pvAddr >> VA_SECTION]) != 0) &&
((pmb = (*pscn)[((ulong)pvAddr >> VA_BLOCK)&BLOCK_MASK]) != 0) &&
(pmb != RESERVED_BLOCK && (ReqKey = TestAccess(&pmb->alk, &CurAKey)) != 0) &&
((entry = pmb->aPages[((ulong)pvAddr >> VA_PAGE) & PAGE_MASK]) & PG_VALID_MASK) &&
(!(flags&2) || (entry & (PG_WRITE_MASK | PG_WRITE_THRU_MASK)))) {
PPAGETABLE pPageTable;
ULONG ulDirFaultIdx;
PDIRTYRANGE pDirtyRange;
ULONG ulBlockIndex;
PDWORD pDirEntry;
//
// ulDirFaultIdx is the index of the page directory corresponding to
// the address which faulted.
//
ulDirFaultIdx = (ULONG)pvAddr / (ARRAY_SIZE(g_PageDir.PTE) * PAGE_SIZE);
OldPDE = g_PageDir.PTE[ulDirFaultIdx];
if (ulDirFaultIdx < PDES_PER_SLOT) {
// The fault occurred in the alias area, update the index to the
// appropriate "real" entry.
ulDirFaultIdx += PID_TO_PT_INDEX(pCurProc->procnum);
} else {
if (g_PageDir.PTE[ulDirFaultIdx] == 0
&& g_ShadowPageDir.PTE[ulDirFaultIdx] != 0)
g_PageDir.PTE[ulDirFaultIdx] = g_ShadowPageDir.PTE[ulDirFaultIdx];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -