📄 mdsh3.c
字号:
DWORD linkage;
ULONG oldFir;
UINT oldMode0;
UCHAR exc;
UCHAR lowSp;
UCHAR pad[2];
ULONG info;
} EXCINFO, *PEXCINFO;
ERRFALSE(sizeof(EXCINFO) <= sizeof(CALLSTACK));
ERRFALSE(offsetof(EXCINFO,linkage) == offsetof(CALLSTACK,pcstkNext));
ERRFALSE(offsetof(EXCINFO,oldFir) == offsetof(CALLSTACK,retAddr));
//ERRFALSE(offsetof(EXCINFO,oldMode) == offsetof(CALLSTACK,pprcLast));
ERRFALSE(64 >= sizeof(CALLSTACK));
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
BOOL
HandleException(
PTHREAD pth,
DWORD dwExc,
DWORD info
)
{
PEXCINFO pexi;
DWORD stackaddr;
KCALLPROFON(0);
#if 0
NKDbgPrintfW(L"Exception %03x Thread=%8.8lx(%8.8lx) PC=%8.8lx TEA=%8.8lx AKY=%8.8lx\r\n",
dwExc, pCurThread, pth, pth->ctx.Fir, info, CurAKey);
#endif
if (dwExc == 0x160) pth->ctx.Fir -= 2; // TRAPA instruction was completed
pexi = (struct ExcInfo *)((pth->ctx.R15 & ~63) - sizeof(CALLSTACK));
// before we touch pexi, we need to commit stack or we'll fault while
// accessing it.
switch (DemandCommit ((DWORD) pexi, pth)) {
case DCMT_FAILED:
// fatal stack error
NKDbgPrintfW (L"Fatal Stack Error, Terminating thread %8.8lx\r\n", pth);
DumpFrame(pth, (PCONTEXT)&pth->ctx, dwExc, info);
pth->ctx.R4 = STATUS_STACK_OVERFLOW;
pth->ctx.R5 = pth->ctx.Fir;
pth->ctx.R15 = (DWORD) pth->tlsPtr - SIZE_PRETLS - 512; // arbitrary safe address
pth->ctx.Fir = (DWORD) pExcpExitThread;
KCALLPROFOFF(0);
return TRUE;
case DCMT_NEW:
// commited a new page. check if we hit the last page.
// generate stack overflow exception if yes.
stackaddr = (DWORD)pexi & ~(PAGE_SIZE-1);
if ((stackaddr >= KSTKBOUND(pth))
|| ((KSTKBOUND(pth) = stackaddr) >= (KSTKBASE(pth) + MIN_STACK_RESERVE))
|| TEST_STACKFAULT(pth)) {
KCALLPROFOFF(0);
return TRUE; // restart instruction
}
SET_STACKFAULT(pth);
dwExc = 0x1fe0; // stack fault exception code
info = (DWORD)pexi;
break;
case DCMT_OLD:
// already commited. do nothing
break;
default:
DEBUGCHK (0);
}
// Setup to capture the exception context in kernel mode but
// running in thread context to allow preemption and stack growth.
if (pth->ctx.Fir != (ulong)CaptureContext+4) {
pexi->exc = (UCHAR)(dwExc >> 5);
pexi->lowSp = (UCHAR)(pth->ctx.R15 & 63);
pexi->oldFir = pth->ctx.Fir;
// pexi->oldMode = GetThreadMode(pth);
((PCALLSTACK) pexi)->dwPrcInfo = CST_IN_KERNEL | ((KERNEL_MODE == GetThreadMode(pth))? 0 : CST_MODE_FROM_USER);
pexi->info = info;
pexi->linkage = (DWORD)pCurThread->pcstkTop | 1;
pCurThread->pcstkTop = (PCALLSTACK)pexi;
pth->ctx.R15 = (DWORD)pexi;
pth->ctx.Psr |= 0x40000000; // Kernel mode
pth->ctx.Fir = (ulong)CaptureContext;
KCALLPROFOFF(0);
return TRUE; // continue execution
}
DumpFrame(pth, (PCONTEXT)&pth->ctx, dwExc, info);
RETAILMSG(1, (TEXT("Halting thread %8.8lx\r\n"), pCurThread));
SurrenderCritSecs();
DEBUGCHK(!((pCurThread->wInfo >> DEBUG_LOOPCNT_SHIFT) & 1));
SET_RUNSTATE(pCurThread,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, *PEXCARGS;
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
ExceptionDispatch(
PCONTEXT pctx
)
{
EXCEPTION_RECORD er;
int exc;
ULONG info;
PEXCARGS pea;
PTHREAD pth;
PEXCINFO pexi;
DWORD dwThrdInfo = KTHRDINFO (pCurThread); // need to save it since it might get changed during exception handling
pth = pCurThread;
pexi = (PEXCINFO)pth->pcstkTop;
DEBUGMSG(ZONE_SEH, (TEXT("ExceptionDispatch: pexi=%8.8lx Fir=%8.8lx RA=%8.8lx exc=%x\r\n"),
pexi, pexi->oldFir, pctx->PR, pexi->exc << 5));
// Update CONTEXT with infomation saved in the EXCINFO structure
pctx->Fir = pexi->oldFir;
// if (pexi->oldMode != KERNEL_MODE)
if (((PCALLSTACK)pexi)->dwPrcInfo & CST_MODE_FROM_USER) {
pctx->Psr &= ~0x40000000;
}
pctx->R15 = (ULONG)pctx + sizeof(CONTEXT);
memset(&er, 0, sizeof(er));
er.ExceptionAddress = (PVOID)pctx->Fir;
// 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)) {
pea = (PEXCARGS)pctx->R15;
exc = -1;
pctx->Fir -= 2; // to avoid boundary problems at the end of a try block.
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.
pctx->R15 += pexi->lowSp + sizeof(CALLSTACK);
exc = pexi->exc;
info = pexi->info;
// Construct an EXCEPTION_RECORD from the EXCINFO structure
er.ExceptionInformation[1] = info;
// TLB Miss on load or store. Attempt to auto-commit the page. If that fails,
// fall through into general exception processing.
if (((exc == 0x3) || (exc == 2)) && AutoCommit(info)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
switch (exc) {
case 8: // Address error (store)
er.ExceptionInformation[0] = 1;
case 7: // Address error (load or instruction fetch)
if (GetContextMode(pctx) != USER_MODE || !(info&0x80000000)) {
er.ExceptionCode = STATUS_DATATYPE_MISALIGNMENT;
break;
}
#if defined(SH3)
// (SH3DSP only)
// Check for the exceptions caused by accessing XY memory in the range
// between 0xA5000000 to 0xA5FFFFFF. Please note that "info" is actually
// the value of TEA which is the virtual address caused the exception.
//
// Please also note that this does not work exactly as it states in 7729
// HW manaul. According to the manual, accessing XY memory in the user
// mode when DSP is disabled should cause an address error. Hitashi
// made a request to change this behavior. The change is similar to the
// way we handle the excecution caused by the first DSP instruction when
// DSP is not enabled. We simply turn on DSP to enable user to access
// the XY memory then continue the execution from the faulting
// instruction without passing the exception to the user app.
//
// XY memory is in the range not mapped by TLB so we don't have worry
// about any TLB related exceptions. Please note we only handle it
// when DSP is disabled. Treat it as a normal address error if DSP
// is already onp
if ( SH3DSP && info <= XYMEMORY_END && info >= XYMEMORY_BEGIN
&& ( ( pctx->Psr & SR_DSP_ENABLED ) == 0 )){
// If DSP processor and DSP not enabled, enable the DSP. Thus user
// can access the XY memory without causing any exceptions
KCall((PKFN)SwitchDSPOwner,pctx);
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
// Continue the exception: we don't want to pass this exception to
// the user app which trying to access the XY memory
goto continueExecution;
}
#endif
goto accessError;
case 3: // TLB Miss (store)
case 4: // TLB modification
case 6: // TLB protection violation (store)
er.ExceptionInformation[0] = 1;
case 2: // TLB miss (load or instruction fetch)
case 5: // TLB protection violation (load)
if (!InSysCall ()) {
BOOL fSuccess;
//
// since we might be calling out of kernel to perform paging and there's
// no gurantee that the driver underneath won't touch FPU, we need to save
// the floating point context and restoring it after paging.
//
#ifdef SH4
// get the contents of the floating point registers
FPUFlushContext ();
// save FPU context in exception context
memcpy (pctx->FRegs, pCurThread->ctx.FRegs, sizeof(pctx->FRegs));
memcpy (pctx->xFRegs, pCurThread->ctx.xFRegs, sizeof(pctx->xFRegs));
pctx->Fpscr = pCurThread->ctx.Fpscr;
pctx->Fpul = pCurThread->ctx.Fpul;
#endif
fSuccess = ProcessPageFault ((exc==3)||(exc==4)||(exc==6), info);
#ifdef SH4
// throw away what's in the floating point registers by flushing it.
FPUFlushContext ();
// restore FPU context from excepiton context
memcpy (pCurThread->ctx.FRegs, pctx->FRegs, sizeof(pctx->FRegs));
memcpy (pCurThread->ctx.xFRegs, pctx->xFRegs, sizeof(pctx->xFRegs));
pCurThread->ctx.Fpscr = pctx->Fpscr;
pCurThread->ctx.Fpul = pctx->Fpul;
#endif
if (fSuccess) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
}
accessError:
er.ExceptionCode = STATUS_ACCESS_VIOLATION;
er.NumberParameters = 2;
break;
#ifdef SH4
case 0x40:
case 0x41:
KCall((PKFN)SwitchFPUOwner,pctx);
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
case 9: { // floating point exception
DWORD code;
code = GetCauseFloatCode();
#if 0
NKDbgPrintfW(L"ExceptionAddress 0x%x\r\n", er.ExceptionAddress);
NKDbgPrintfW(L"code 0x%x, exc 0x%x\r\n",code,exc);
#endif
if (code & 0x10)
er.ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
else if (code & 0x8)
er.ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
else if (code & 0x4)
er.ExceptionCode = STATUS_FLOAT_OVERFLOW;
else if (code & 0x2)
er.ExceptionCode = STATUS_FLOAT_UNDERFLOW;
else if (code & 0x1)
er.ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
else
{
//
// Reach here
// --if code is 0x20 (FPU error)
// --if code is 0x0 (processor thinks an ieee
// exception is possible)
//
// both cases require that fp operation be emulated
// for correct ieee result.
//
// save the fpscr before FPUFlushContext will flush it
// to zero.
//
// FPUFlushContext clears fpscr
//
FPUFlushContext();
//
// Copy current thread fregs and xfreg to user context
//
memcpy(&pctx->FRegs[0],&pCurThread->ctx.FRegs[0],sizeof(DWORD)*16);
memcpy(&pctx->xFRegs[0],&pCurThread->ctx.xFRegs[0],sizeof(DWORD)*16);
pctx->Fpscr = pCurThread->ctx.Fpscr;
pctx->Fpul = pCurThread->ctx.Fpul;
if (HandleHWFloatException(&er,pctx))
{
// flush float context back to thread context after exception was handled
FPUFlushContext();
//
// update current thread context with user context
//
memcpy(&pCurThread->ctx.FRegs[0],&pctx->FRegs[0],sizeof(DWORD)*16);
memcpy(&pCurThread->ctx.xFRegs[0],&pctx->xFRegs[0],sizeof(DWORD)*16);
pCurThread->ctx.Fpul = pctx->Fpul;
pCurThread->ctx.Fpscr = pctx->Fpscr;
pCurThread->ctx.Psr = pctx->Psr;
pctx->Fir+=2; // +2: return control to instruction successor
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
}
//
// Update user context fpscr and fpul
//
pCurThread->ctx.Fpscr = pctx->Fpscr;
pCurThread->ctx.Fpul = pctx->Fpul;
pCurThread->ctx.Psr = pctx->Psr;
break;
}
#endif
case 11: // Breakpoint
er.ExceptionInformation[0] = info;
er.ExceptionCode = STATUS_BREAKPOINT;
break;
case 12: // Reserved instruction
case 13: // Illegal slot instruction
#ifdef SH3
//
// Assume DSP instruction.
// If DSP processor and DSP not enabled, enable the DSP.
//
if ( SH3DSP && ((pctx->Psr & SR_DSP_ENABLED) == 0) ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -