📄 fault.c
字号:
DWORD dwSize
)
{
LPVOID pvRet = NULL;
DWORD dw4MBase; // 4M aligned address
dwPhysBase <<= 8; // Only supports 32-bit physical address.
dw4MBase = dwPhysBase & -dw4M; // 4M alignment
if (!dwSize || (dwPhysBase & (PAGE_SIZE-1))) {
KSetLastError(pCurThread, ERROR_INVALID_PARAMETER);
return NULL;
}
if (IsSystemStarted ())
EnterCriticalSection(&VAcs);
if (dwPhysBase < 0x20000000 && ((dwPhysBase + dwSize) < 0x20000000)) {
pvRet = Phys2VirtUC(dwPhysBase);
} else {
DWORD dwPDENeeded;
DWORD pdeStart, pdeWalk;
dwPDENeeded = ((dwPhysBase + dwSize - dw4MBase - 1) / dw4M) + 1;
DEBUGCHK (dwPDENeeded);
if (pdeStart = FindExistingMapping (dw4MBase, dwPDENeeded)) {
dwPDENeeded = 0; // indicate success
} else if (pdeStart = FindFreePDE (dwPDENeeded)) {
if (LARGE_PAGE_SUPPORT_DETECTED) {
//
// Supports 4MB page mappings.
//
for (pdeWalk = pdeStart; dwPDENeeded; pdeWalk ++, dw4MBase += dw4M, dwPDENeeded --) {
g_pPageDir->PTE[pdeWalk] = dw4MBase | PG_KERNEL_RW | PG_LARGE_PAGE_MASK | PG_NOCACHE | PG_WRITE_THRU_MASK;
}
} else if ((((DWORD)PageFreeCount > dwPDENeeded + MIN_PROCESS_PAGES) || !IsSystemStarted())
&& AllocPagesForPT (dwPDENeeded)) {
//
// Use 4k page tables to map.
//
// We've at least got enough pages available and that many have been set
// aside for us (though not yet assigned).
//
PAGETABLE* pPageTable;
DWORD pfnAddr;
int i;
for (pdeWalk = pdeStart; dwPDENeeded; pdeWalk ++, dwPDENeeded --) {
pfnAddr = GetNextPageForPT ();
pPageTable = (PAGETABLE*) Phys2Virt(pfnAddr);
DEBUGCHK(pPageTable);
g_pPageDir->PTE[pdeWalk] = pfnAddr | PG_KERNEL_RW;
for (i = 0; i < 1024; i++, dw4MBase += PFN_INCR) {
pPageTable->PTE[i] = dw4MBase | PG_KERNEL_RW | PG_NOCACHE | PG_WRITE_THRU_MASK;
}
DEBUGCHK (!(dw4MBase & (dw4M -1)));
}
}
}
// dwPDENeeded will be zero if success
if (dwPDENeeded == 0) {
pvRet = (LPVOID) ((pdeStart << 22) + (dwPhysBase & (dw4M - 1))); // create a virtual address from PD index
}
}
if (IsSystemStarted ())
LeaveCriticalSection(&VAcs);
return (pvRet);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
LPVOID
SC_CreateStaticMapping(
DWORD dwPhysBase,
DWORD dwSize
)
{
TRUSTED_API (L"SC_CreateStaticMapping", NULL);
return NKCreateStaticMapping(dwPhysBase, dwSize);
}
#pragma warning(disable:4035 4733)
//------------------------------------------------------------------------------
//
// System call trap handler.
//
// Pop the iret frame from the stack, switch back to the caller's stack, enable interrupts,
// and dispatch the system call.
//
// CPU State: ring1 stack & CS, interrupts disabled.
// edx:eax == rtn value if PSL return
//
//------------------------------------------------------------------------------
PVOID __declspec(naked) Int20SyscallHandler (void)
{
__asm {
// The following three instructions are only executed once on Init time.
// It sets up the KData PSL return function pointer and returns the
// the 'real' address of the Int20 handler (sc00 in this case).
mov [KData.pAPIReturn], offset APICallReturn
mov dword ptr [MD_CBRtn], offset CBRtnCommon
mov eax, offset sc00
ret
sc00: pop ecx // (ecx) = EIP of "int SYSCALL"
sub ecx, FIRST_METHOD+2 // (ecx) = iMethod * APICALL_SCALE
cmp ecx, -APICALL_SCALE // check callback return
je short CallbackRtn // returning from callback
sar ecx, 1 // (ecx) == iMethod
pop eax // (eax) == caller's CS
and al, 0FCh
cmp al, KGDT_R1_CODE
je short KPSLCall // caller was in kernel mode
// caller was in user mode
// special casing RaiseException
cmp ecx, RAISEEXCEPTION
je short UPSLCallTrusted // do not switch stack for RaiseException
// PerformCallBack MUST BE CALLED IN KMODE (From PSL)
// cmp ecx, PERFORMCALLBACK
// je short DoPerformCallback
// check if the caller is trusted
mov eax, PtrCurProc // (eax) == pCurProc
cmp byte ptr [eax+OFFSET_TRUSTLVL], KERN_TRUST_FULL // is it fully trusted?
je short UPSLCallTrusted // do fully trusted if yes
// not trusted, switch to secure stack (need to update TLSPTR too)
mov eax, PtrCurThd // (eax) == pCurThread
mov edx, [eax].tlsSecure // (eax) == TLSPTR of the secure stack
mov [eax].tlsPtr, edx // update thread's tlsPtr
mov [KData].lpvTls, edx // set KData's TLS pointer
// find the 'real' callstack if there is one(SEH might create a faked one)
mov edx, [eax].pcstkTop // (edx) == pCurThread->pcstkTop
UPSLNextSTK:
test edx, edx
je short UPSLCallFirstTrip // 0 if first trip
cmp dword ptr [edx].akyLast, 0 // akyLast == 0 if faked
jne short UPSLFoundStkTop // found the real ccallstack
mov edx, [edx].pcstkNext
jmp short UPSLNextSTK
UPSLFoundStkTop:
// (not trusted) in callback function, calling into PSL again
// (edx) = 'real' pcstk
mov edx, [edx].dwPrevSP // (edx) == pcstk->dwPrevSP
jmp short UPSLCallNonTrusted
UPSLCallFirstTrip:
// (non-trusted) first trip into PSL, use tlsPtr to figure out where SP should be
// (eax) == PthCurThd
mov edx, [eax].tlsSecure // (eax) == TLSPTR of the secure stack
sub edx, SECURESTK_RESERVE // (edx) == new stack
UPSLCallNonTrusted:
// (edx) == new SP
mov esp, [esp+4] // (esp) == caller's SP
xchg esp, edx // switch stack
// make roon for arguments on the new stack
sub esp, MAX_PSL_ARGS // save space for MAX # of PSL arguments + return address
mov eax, USER_MODE // calling from user mode
jmp short PSLCallCommon
UPSLCallTrusted:
// caller is fully trusted, use current stack
mov esp, [esp+4] // get the user stack
mov edx, 0 // prevSP set to 0 when no stack swtich
mov eax, USER_MODE // calling from user mode
jmp short PSLCallCommon
KPSLCall:
// caller was in kernel mode
// is this a callback?
cmp ecx, PERFORMCALLBACK
je short DoPerformCallback
// caller was in kernel mode
add esp, 4 // discard the EFLAGS
mov edx, 0 // prevSP set to 0 when no stack swtich
mov eax, KERNEL_MODE // we're in kernel mode
PSLCallCommon:
// (eax) == caller's mode
// (ecx) == iMethod
// (edx) == caller's stack
// (esp) == secure stack if not trusted, caller stack if trusted/kmode
push fs:dword ptr [0] // save exception chain linkage
sti // interrupt ok now
cmp edx, 0 // are we using the same stack?
je short DoObjectCall
// stack changed, need to copy argument from one to the other
push ecx
push esi
push edi
mov esi, edx
lea edi, [esp+16] // +16 == fs:0 and ecx, esi, edi we just pushed
mov ecx, MAX_PSL_ARGS/4
rep movsd
// update fs
mov ecx, PtrCurThd
mov ecx, [ecx].tlsPtr
mov edi, offset g_aGlobalDescriptorTable+KGDT_PCR
sub ecx, FS_LIMIT+1 // (ecx) = ptr to NK_PCR base
mov word ptr [edi+2], cx // set low word of FS base
shr ecx, 16
mov byte ptr [edi+4], cl // set third byte of FS base
mov byte ptr [edi+7], ch // set high byte of FS base
push fs
pop fs // cause fs to reload
pop edi
pop esi
pop ecx
pop fs:dword ptr [0] // make sure the new fs:[0] is consistent with the old one
push fs:dword ptr [0] // save exception chain linkage
DoObjectCall:
// PSL Call, setup OBJCALLSTRUCT on stack (linkage already pushed)
push eax // mode
push edx // previous ESP
push ecx // iMethod
push esp // arg0 == pointer to OBJCALLSTRUCT
call ObjectCall // (eax) = api function address (0 if completed)
add esp, 20 // clear ObjectCall args off the stack
mov fs:dword ptr [0], -2 // mark PSL boundary in exception chain
mov ecx, PtrCurThd // (ecx) = ptr to THREAD struct
mov ecx, [ecx].pcstkTop // (ecx) = ptr to CALLSTACK struct
mov [ecx].ExEsp, esp // .\ v
mov [ecx].ExEbp, ebp // ..\ v
mov [ecx].ExEbx, ebx // ...> save registers for possible exception recovery
mov [ecx].ExEsi, esi // ../
mov [ecx].ExEdi, edi // ./
pop edx // get rid of return address
call eax // & call the api function in KMODE (all PSL calls in KMODE now)
APICallReturn:
push 0 // space for exception chain linkage
push KERNEL_MODE // current thread mode
// Retrieve return address, mode, and exception linkage from the
// thread's call stack.
//
// (eax:edx) = function return value
// (TOS) = thread's execution mode
// (TOS+4) = space to receive previous exception chain linkage
sub esp, 4 // room for dwPrevSP (must be at esp+8 when returned from ServerCallReturn)
push eax // save return value
push edx // ...
lea eax, [esp+8] // (eax) = ptr to SVRRTNSTRUCT
push eax // arg0 - ptr to SVRRTNSTRUCT
call ServerCallReturn // (eax) = api return address
add esp, 4 // get rid of arg 0
mov edx, [esp] // restore edx
mov [esp], eax // save return address
mov eax, [esp+4] // restore eax
mov ecx, [esp+16] // (ecx) = saved exception linkage
cmp dword ptr [esp+12], KERNEL_MODE
mov fs:[0], ecx // restore exception linkage
jne short UPSLRtn // dispatch thread in kernel mode
// returning to KMode caller, just pop working data and return
ret 16
UPSLRtn:
// returning to user mode process
// check if stack switch is needed
cmp dword ptr [esp+8], 0 // need stack switch?
je short UPSLRtnNoStkSwitch
// not trusted, dwPrevSP has the right value
add dword ptr [esp+8], 4 // [esp+8] is already dwPrevSP, add 4 to remove the return address
// update TLS
push edx
mov edx, PtrCurThd // (edx) == pCurThread
mov ecx, [edx].tlsNonSecure // (ecx) == TLSPTR of the non-secure stack
mov [edx].tlsPtr, ecx // update thread's tlsPtr
mov [KData].lpvTls, ecx // set KData's TLS pointer
// need to update fs
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
push fs
pop fs // cause fs to reload
pop edx
// restore fs:[0] on new stack
mov ecx, [esp+16]
mov fs:[0], ecx
jmp short UPSLRtnToCaller
UPSLRtnNoStkSwitch:
// pCurProc is fully trusted, no stack switch required
lea ecx, [esp+20]
mov [esp+8], ecx // ESP restore value
UPSLRtnToCaller:
// [esp] == return address, [esp+8] == stack, both must have already been setup correctly
mov dword ptr [esp+4], KGDT_R3_CODE | 3
mov dword ptr [esp+12], KGDT_R3_DATA | 3
retf // return to ring3 & restore stack pointer
////////////////////////////////////////////////////////////////////////////////////////
// callback returns from user mode process
//
CallbackRtn:
pop ecx // (eax) == caller's CS
and cl, 0FCh
cmp cl, KGDT_R1_CODE
je short CBRtnKMode // Are we in kmode? (User called SetKMode in the callback function)
// we're in user mode
mov esp, [esp+4] // edx == stack of returning thread
jmp short CBRtnChkTrust
CBRtnKMode:
// in KMODE
add esp, 4 // skip the EFLAGS
CBRtnChkTrust:
sti // interrupt okay now
// do we need to switch stack?
mov edx, PtrCurThd // (edx) == pCurThread
mov ecx, [edx].pcstkTop // (ecx) == pCurThread->pcstkTop
cmp dword ptr [ecx].dwPrevSP, 0 // need stack change?
je short CBRtnCommon
// the stack needs to be changed
// get the new SP
mov esp, [ecx].dwPrevSP
add esp, 4 // less retrun address
// update TLS (edx == pCurThread on entrance)
mov ecx, [edx].tlsSecure // (ecx) == TLSPTR of the secure stack
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -