📄 mdx86.c
字号:
/* Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved. */
#include "kernel.h"
#define Naked void __declspec(naked)
extern FXSAVE_AREA g_InitialFPUState;
extern KIDTENTRY g_aIntDescTable[];
// Default processor type & revision level information.
DWORD CEProcessorType = PROCESSOR_INTEL_486;
WORD ProcessorLevel = 0;
WORD ProcessorRevision = 0;
DWORD ProcessorFeatures = 0;
#define FN_BITS_PER_TAGWORD 16
#define FN_TAG_EMPTY 0x3
#define FN_TAG_MASK 0x3
#define FX_TAG_VALID 0x1
#define NUMBER_OF_FP_REGISTERS 8
#define BYTES_PER_FP_REGISTER 10
#define BYTES_PER_FX_REGISTER 16
#define TS_MASK 0x00000008
#define FPTYPE_HARDWARE 1
#define FPTYPE_SOFTWARE 2
DWORD dwFPType;
void DumpDwords(PDWORD pdw, int len) {
int lc;
lc = 0;
NKDbgPrintfW(L"Dumping %d dwords", len);
for (lc = 0 ; len ; ++pdw, ++lc, --len) {
if (!(lc & 3))
NKDbgPrintfW(L"\r\n%8.8lx -", pdw);
NKDbgPrintfW(L" %8.8lx", *pdw);
}
NKDbgPrintfW(L"\r\n");
}
void DumpFrame(PTHREAD pth, PCONTEXT pctx, int id, int level) {
NKDbgPrintfW(L"Exception %02x Thread=%8.8lx AKY=%8.8lx EIP=%8.8lx\r\n",
id, pth, pCurThread->aky, pctx->Eip);
NKDbgPrintfW(L"Eax=%8.8lx Ebx=%8.8lx Ecx=%8.8lx Edx=%8.8lx\r\n",
pctx->Eax, pctx->Ebx, pctx->Ecx, pctx->Edx);
NKDbgPrintfW(L"Esi=%8.8lx Edi=%8.8lx Ebp=%8.8lx Esp=%8.8lx\r\n",
pctx->Esi, pctx->Edi, pctx->Ebp, pctx->Esp);
NKDbgPrintfW(L"CS=%4.4lx DS=%4.4lx ES=%4.4lx SS=%4.4lx FS=%4.4lx GS=%4.4lx\r\n",
pctx->SegCs, pctx->SegDs, pctx->SegEs, pctx->SegSs, pctx->SegFs, pctx->SegGs);
NKDbgPrintfW(L"Flags=%8.8lx\r\n",
pctx->EFlags);
}
void DumpTctx(PTHREAD pth, int id, ulong addr, int level) {
ulong espValue, ssValue;
if ((pth->ctx.TcxCs&0xFFFF) == KGDT_R0_CODE) {
espValue = pth->ctx.TcxNotEsp+16;
ssValue = KGDT_R0_DATA;
} else {
espValue = pth->ctx.TcxEsp;
ssValue = pth->ctx.TcxSs;
}
NKDbgPrintfW(L"Exception %02x Thread=%8.8lx Proc=%8.8lx '%s'\r\n",
id, pth, hCurProc, pCurProc->lpszProcName ? pCurProc->lpszProcName : L"");
NKDbgPrintfW(L"EIP=%8.8lx AKY=%8.8lx Flags=%8.8lx EA=%8.8lx\r\n",
pth->ctx.TcxEip, pCurThread->aky, pth->ctx.TcxEFlags, addr);
NKDbgPrintfW(L"Eax=%8.8lx Ebx=%8.8lx Ecx=%8.8lx Edx=%8.8lx\r\n",
pth->ctx.TcxEax, pth->ctx.TcxEbx, pth->ctx.TcxEcx, pth->ctx.TcxEdx);
NKDbgPrintfW(L"Esi=%8.8lx Edi=%8.8lx Ebp=%8.8lx Esp=%8.8lx\r\n",
pth->ctx.TcxEsi, pth->ctx.TcxEdi, pth->ctx.TcxEbp, espValue);
NKDbgPrintfW(L"CS=%4.4lx DS=%4.4lx ES=%4.4lx SS=%4.4lx FS=%4.4lx GS=%4.4lx\r\n",
pth->ctx.TcxCs, pth->ctx.TcxDs, pth->ctx.TcxEs, ssValue,
pth->ctx.TcxFs, pth->ctx.TcxGs);
if (level > 1) {
DWORD addr;
PDWORD pdw;
int count = 16;
addr = espValue;
if (pth->ctx.TcxEbp >= espValue)
count = (pth->ctx.TcxEbp+16 - espValue) / 4;
pdw = VerifyAccess((PVOID)addr, VERIFY_KERNEL_OK, CurAKey);
if (pdw)
DumpDwords((PDWORD)addr, count);
}
}
typedef struct ExcInfo {
DWORD linkage;
ULONG oldEip;
UINT oldMode;
UCHAR id;
UCHAR oldTFlag;
USHORT error;
ULONG info;
UCHAR lowSp;
UCHAR pad[3];
} EXCINFO;
typedef EXCINFO *PEXCINFO;
ERRFALSE(sizeof(EXCINFO) <= sizeof(CALLSTACK));
ERRFALSE(offsetof(EXCINFO,linkage) == offsetof(CALLSTACK,pcstkNext));
ERRFALSE(offsetof(EXCINFO,oldEip) == offsetof(CALLSTACK,retAddr));
ERRFALSE(offsetof(EXCINFO,oldMode) == offsetof(CALLSTACK,pprcLast));
ERRFALSE(64 >= sizeof(CALLSTACK));
Naked CpuIdTrap6Handler(void)
{
__asm {
// Illegal opcode handler when executing cpuid instruction
add dword ptr [esp], 2 // skip the cpuid instr by incrementing eip
xor eax, eax // simulate an unsupported cpuid instruction
xor ebx, ebx // by returning 0 for return values
xor ecx, ecx
xor edx, edx
iretd
}
}
void IdentifyCpu(void)
{
__asm {
pushfd
cli
mov ecx, offset g_aIntDescTable
push dword ptr [ecx+30h] // Save Trap06 handler in case
push dword ptr [ecx+34h] // the CPUID instruction faults
mov eax, offset CpuIdTrap6Handler
mov word ptr [ecx+30h], ax // Set LowWord
shr eax, 16
mov word ptr [ecx+36h], ax // Set HighWord
xor eax, eax // argument to CPUID
_emit 0fh // cpuid instruction
_emit 0a2h // sets eax, ebx, ecx, edx
cmp ebx, 756e6547h // check for "Genu" string
jne short cpuid_trap // not an Intel processor
cmp edx, 49656e69h // check for "ineI" string
jne short cpuid_trap // not an Intel processor
cmp ecx, 6c65746eh // check for "ntel" string
jne short cpuid_trap // not an Intel processor
cmp eax, 1 // make sure level 1 is supported
jc short cpuid_trap // no, then keep defaults
mov eax, 1 // get the family and stepping
_emit 0fh // cpuid instruction
_emit 0a2h
mov ebx, eax
mov ecx, eax
shr ebx, 4
and ebx, 0Fh // (ebx) = model
and ecx, 0Fh // (ecx) = stepping
shr eax, 8
and eax, 0Fh // (eax) = family
cmp eax, 4
jne cpu_not_p4
mov eax, PROCESSOR_INTEL_486
jmp short cpuid_store
cpu_not_p4:
cmp eax, 5
jne short cpu_not_p5
mov eax, PROCESSOR_INTEL_PENTIUM
jmp short cpuid_store
cpu_not_p5:
mov eax, PROCESSOR_INTEL_PENTIUMII
cpuid_store:
mov CEProcessorType, eax
mov ProcessorLevel, bx
mov ProcessorRevision, cx
mov ProcessorFeatures, edx
cpuid_trap:
mov ecx, offset g_aIntDescTable
pop dword ptr [ecx+34h] // restore trap6 handler
pop dword ptr [ecx+30h]
popfd
}
}
BOOL HandleException(PTHREAD pth, int id, ulong addr) {
PEXCINFO pexi;
DWORD stackaddr;
KCALLPROFON(0);
#if 0
NKDbgPrintfW(L"Exception %02x Thread=%8.8lx(%8.8lx) IP=%8.8lx EA=%8.8lx Err=%4.4x\r\n",
id, pCurThread,pth, pth->ctx.TcxEip, addr, pth->ctx.TcxError & 0xFFFF);
#endif
pexi = (struct ExcInfo *)((pth->ctx.TcxEsp & ~63) - sizeof(CALLSTACK));
if (!((DWORD)pexi & 0x80000000) && DemandCommit((DWORD)pexi)) {
stackaddr = (DWORD)pexi & ~(PAGE_SIZE-1);
if ((stackaddr >= pth->dwStackBound) || (stackaddr < pth->dwStackBase) ||
((pth->dwStackBound = stackaddr) >= (pth->dwStackBase + MIN_STACK_RESERVE)) ||
TEST_STACKFAULT(pth)) {
KCALLPROFOFF(0);
return 1; // restart instruction
}
SET_STACKFAULT(pth);
id = 0xFF; // stack fault exception code
addr = (DWORD)pexi;
}
// Setup to capture the exception context in kernel mode but
// running in thread context to allow preemption and stack growth.
if (pth->ctx.TcxEip != (ulong)CaptureContext) {
pexi->id = id;
pexi->lowSp = (CHAR)(pth->ctx.TcxEsp & 63);
pexi->oldEip = pth->ctx.TcxEip;
pexi->oldMode = GetThreadMode(pth);
pexi->info = addr;
if (id != 16)
pexi->error = (USHORT)pth->ctx.TcxError;
else {
WORD status;
_asm fnstsw status;
pexi->error = status;
_asm fnclex;
}
pexi->oldTFlag = (UCHAR)(pth->ctx.TcxEFlags >> 8) & 1;
pexi->linkage = (DWORD)pCurThread->pcstkTop | 1;
pCurThread->pcstkTop = (PCALLSTACK)pexi;
pth->ctx.TcxEsp = (DWORD)pexi;
pth->ctx.TcxEFlags &= ~0x0100; // Unset TF while in the debugger
pth->ctx.TcxEip = (ulong)CaptureContext;
if (pexi->oldMode != KERNEL_MODE)
SetThreadMode(pth, KERNEL_MODE);
KCALLPROFOFF(0);
return TRUE; // continue execution
}
DumpTctx(pth, id, addr, 10);
RETAILMSG(1, (TEXT("Halting thread %8.8lx\r\n"), pCurThread));
SurrenderCritSecs();
SET_RUNSTATE(pth,RUNSTATE_BLOCKED);
RunList.pth = 0;
SetReschedule();
KCALLPROFOFF(0);
return 0;
}
typedef struct _EXCARGS {
DWORD dwExceptionCode; /* exception code */
DWORD dwExceptionFlags; /* continuable exception flag */
DWORD cArguments; /* number of arguments in array */
DWORD *lpArguments; /* address of array of arguments */
} EXCARGS;
typedef EXCARGS *PEXCARGS;
BOOL SetCPUHardwareWatch(LPVOID lpv, DWORD dwFlags) {
static PPROCESS pOwnerProc;
if (!InSysCall())
return KCall((PKFN)SetCPUHardwareWatch, lpv, dwFlags);
KCALLPROFON(73);
if (lpv == 0) {
// dwFlags=0 means check to see if we want to take this breakpoint
if (dwFlags == (DWORD)-1) {
// check to see which breakpoint went off and
// clear the debug register
DWORD dwReason;
DWORD dwMask=~0xf;
_asm {
mov eax, dr6
mov dwReason, eax
and eax, dwMask
mov dr6, eax
}
// was the zeroptr breakpoint hit?
if (dwReason&0x2 && pOwnerProc != pCurProc) {
OutputDebugString(L"zero mapped breakpoint hit in wrong process!\r\n");
KCALLPROFOFF(73);
return 0;
}
KCALLPROFOFF(73);
return 1;
} else {
// dwFlags=1 means disable the data watchpoint
dwFlags = ~0xf;
_asm {
mov eax, dr7
and eax, dwFlags
mov dr7, eax
}
KCALLPROFOFF(73);
return 1;
}
} else {
DWORD dwMask=~0xff000f;
LPVOID lpvZero=(LPVOID)UnMapPtr(lpv);
if (dwFlags == HARDWARE_WATCH_READ) {
dwFlags = 0xff000a;
} else {
dwFlags = 0xdd000a;
}
_asm {
mov eax, lpv
mov dr0, eax
mov eax, lpvZero
mov dr1, eax
mov eax, dr7
and eax, dwMask
or eax, dwFlags
mov dr7, eax
}
pOwnerProc = pCurProc;
KCALLPROFOFF(73);
return 1;
}
KCALLPROFOFF(73);
}
void ExceptionDispatch(PCONTEXT pctx) {
PTHREAD pth;
PEXCINFO pexi;
int id;
ULONG info;
BOOL bHandled;
PEXCARGS pea;
EXCEPTION_RECORD er;
pth = pCurThread;
pexi = (PEXCINFO)pth->pcstkTop;
DEBUGMSG(ZONE_SEH, (TEXT("ExceptionDispatch: pexi=%8.8lx Eip=%8.8lx id=%x\r\n"),
pexi, pexi->oldEip, pexi->id));
// Update CONTEXT with infomation saved in the EXCINFO structure
pctx->Eip = pexi->oldEip;
pctx->Esp = (DWORD)pctx + sizeof(CONTEXT);
SetContextMode(pctx, pexi->oldMode);
memset(&er, 0, sizeof(er));
er.ExceptionAddress = (PVOID)pctx->Eip;
// Check for RaiseException call versus a CPU detected exception.
// RaiseException just becomes a call to CaptureContext as a KPSL.
// HandleExcepion sets the LSB of the callstack linkage but ObjectCall
// does not.
if (!(pexi->linkage & 1)) {
NK_PCR *pcr = (NK_PCR *)((char *)pth->tlsPtr - offsetof(NK_PCR, tls));
// Fill in exception record information from the parameters passed to
// the RaiseException call.
// Restore exception list linkage.
DEBUGCHK(pcr->ExceptionList == -2);
pcr->ExceptionList = ((PCALLSTACK)pexi)->extra;
pea = (PEXCARGS)(pctx->Esp + 4);
id = -1;
pctx->Esp += 4; // Remove return address from the stack
DEBUGMSG(ZONE_SEH, (TEXT("Raising exception %x flags=%x args=%d pexi=%8.8lx\r\n"),
pea->dwExceptionCode, pea->dwExceptionFlags, pea->cArguments, pexi));
er.ExceptionCode = pea->dwExceptionCode;
er.ExceptionFlags = pea->dwExceptionFlags;
if (pea->lpArguments && pea->cArguments) {
if (pea->cArguments > EXCEPTION_MAXIMUM_PARAMETERS) {
er.ExceptionCode = STATUS_INVALID_PARAMETER;
er.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
} else {
memcpy(er.ExceptionInformation, pea->lpArguments,
pea->cArguments*sizeof(DWORD));
er.NumberParameters = pea->cArguments;
}
}
} else {
// CPU detected exception. Extract some additional information about
// the cause of the exception from the EXCINFO (CALLSTACK) structure.
id = pexi->id;
info = pexi->info;
pctx->EFlags |= pexi->oldTFlag << 8;
pctx->Esp += pexi->lowSp + sizeof(CALLSTACK);
if ((id == 14) && AutoCommit(info)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
// Construct an EXCEPTION_RECORD from the EXCINFO structure
er.ExceptionInformation[1] = info;
switch (id) {
case 14: // Page fault
er.ExceptionInformation[0] = (pexi->error >> 1) & 1;
goto accessError;
case 13: // General Protection Fault
er.ExceptionInformation[0] = 1; accessError:
if (ProcessPageFault(er.ExceptionInformation[0], info)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
er.ExceptionCode = STATUS_ACCESS_VIOLATION;
er.NumberParameters = 2;
break;
case 3: // Breakpoint
er.ExceptionInformation[0] = 1; // DEBUGBREAK_STOP_BREAKPOINT
er.ExceptionCode = STATUS_BREAKPOINT;
break;
case 2: // Stop thread breakpoint
er.ExceptionInformation[0] = 3; // DEBUG_THREAD_SWITCH_BREAKPOINT
er.ExceptionCode = STATUS_BREAKPOINT;
break;
case 1: // Breakpoint
er.ExceptionInformation[0] = 0;
er.ExceptionCode = STATUS_SINGLE_STEP;
// If you are using the SetCPUHardware watch function you will probably
// want to uncomment the following lines so that it will clear the register
// automatically on exception
/*
if(!SetCPUHardwareWatch(0, (DWORD)-1)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -