947 lines
29 KiB
C
947 lines
29 KiB
C
/*++
|
||
|
||
Module Name:
|
||
|
||
exceptn.c
|
||
|
||
Abstract:
|
||
|
||
This module implement the code necessary to dispatch expections to the
|
||
proper mode and invoke the exception dispatcher.
|
||
|
||
Author:
|
||
|
||
William K. Cheung (wcheung) 10-Nov-1995
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
#include "ntfpia64.h"
|
||
|
||
|
||
#include "fedefs.h"
|
||
#include "fetypes.h"
|
||
#include "fesupprt.h"
|
||
#include "feproto.h"
|
||
#include "floatem.h"
|
||
#include "fpswa.h"
|
||
|
||
LONG
|
||
fp_emulate (
|
||
ULONG trap_type,
|
||
PVOID pbundle,
|
||
ULONGLONG *pipsr,
|
||
ULONGLONG *pfpsr,
|
||
ULONGLONG *pisr,
|
||
ULONGLONG *ppreds,
|
||
ULONGLONG *pifs,
|
||
PVOID fp_state
|
||
);
|
||
|
||
BOOLEAN
|
||
KiEmulateFloat (
|
||
PEXCEPTION_RECORD ExceptionRecord,
|
||
PKEXCEPTION_FRAME ExceptionFrame,
|
||
PKTRAP_FRAME TrapFrame
|
||
)
|
||
{
|
||
|
||
FLOATING_POINT_STATE FpState;
|
||
USHORT ISRCode;
|
||
ULONG TrapType;
|
||
PVOID ExceptionAddress;
|
||
BUNDLE KeBundle;
|
||
|
||
LONG Status = -1;
|
||
|
||
FpState.ExceptionFrame = (PVOID)ExceptionFrame;
|
||
FpState.TrapFrame = (PVOID)TrapFrame;
|
||
|
||
if (ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) {
|
||
TrapType = 1;
|
||
ExceptionAddress = (PVOID)TrapFrame->StIIP;
|
||
} else {
|
||
TrapType = 0;
|
||
ExceptionAddress = (PVOID)TrapFrame->StIIPA;
|
||
}
|
||
|
||
try {
|
||
|
||
KeBundle.BundleLow =(ULONGLONG)(*(PULONGLONG)ExceptionAddress);
|
||
KeBundle.BundleHigh =(ULONGLONG)(*((PULONGLONG)ExceptionAddress + 1));
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
//
|
||
// if an exception (memory fault) occurs, then let hardware handle it
|
||
//
|
||
return TRUE;
|
||
}
|
||
|
||
if ((Status = fp_emulate(TrapType, &KeBundle,
|
||
&TrapFrame->StIPSR, &TrapFrame->StFPSR, &TrapFrame->StISR,
|
||
&TrapFrame->Preds, &TrapFrame->StIFS, (PVOID)&FpState)) == 0) {
|
||
|
||
//
|
||
// Exception was handled and state modified.
|
||
// Therefore the context frame does not need to
|
||
// be transfered to the trap and exception frames.
|
||
//
|
||
// Since it was fault, PC should be advanced
|
||
//
|
||
|
||
if (TrapType == 1) {
|
||
KiAdvanceInstPointer(TrapFrame);
|
||
}
|
||
|
||
if (TrapFrame->StIPSR & (1 << PSR_MFH)) {
|
||
|
||
//
|
||
// high fp set is modified; set the dfh and clear the mfh
|
||
// to force a reload on the first access to the high fp set
|
||
//
|
||
|
||
TrapFrame->StIPSR &= ~(1i64 << PSR_MFH);
|
||
TrapFrame->StIPSR |= (1i64 << PSR_DFH);
|
||
}
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
if (Status == -1) {
|
||
return FALSE;
|
||
}
|
||
|
||
ISRCode = (USHORT)TrapFrame->StISR;
|
||
|
||
if (Status & 0x1) {
|
||
|
||
ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR;
|
||
|
||
if (!(Status & 0x4)) {
|
||
if (TrapType == 1) {
|
||
|
||
//
|
||
// FP Fault
|
||
//
|
||
|
||
if (ISRCode & 0x11) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
|
||
} else if (ISRCode & 0x22) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DENORMAL_OPERAND;
|
||
} else if (ISRCode & 0x44) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// FP Trap
|
||
//
|
||
|
||
ISRCode = ISRCode >> 7;
|
||
if (ISRCode & 0x11) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
||
} else if (ISRCode & 0x22) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
||
} else if (ISRCode & 0x44) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
if (Status & 0x2) {
|
||
|
||
//
|
||
// FP Fault To Trap
|
||
//
|
||
|
||
KiAdvanceInstPointer(TrapFrame);
|
||
if (!(Status & 0x4)) {
|
||
ISRCode = ISRCode >> 7;
|
||
if (ISRCode & 0x11) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_OVERFLOW;
|
||
} else if (ISRCode & 0x22) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_UNDERFLOW;
|
||
} else if (ISRCode & 0x44) {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
|
||
}
|
||
} else {
|
||
ExceptionRecord->ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
typedef struct _BRL_INST {
|
||
union {
|
||
struct {
|
||
ULONGLONG qp: 6;
|
||
ULONGLONG b1: 3;
|
||
ULONGLONG rsv0: 3;
|
||
ULONGLONG p: 1;
|
||
ULONGLONG imm20: 20;
|
||
ULONGLONG wh: 2;
|
||
ULONGLONG d: 1;
|
||
ULONGLONG i: 1;
|
||
ULONGLONG Op: 4;
|
||
ULONGLONG rsv1: 23;
|
||
} i;
|
||
ULONGLONG Ulong64;
|
||
} u;
|
||
} BRL_INST;
|
||
|
||
typedef struct _BRL2_INST {
|
||
union {
|
||
struct {
|
||
ULONGLONG rsv0: 2;
|
||
ULONGLONG imm39: 39;
|
||
ULONGLONG rsv1: 23;
|
||
} i;
|
||
ULONGLONG Ulong64;
|
||
} u;
|
||
} BRL0_INST;
|
||
|
||
typedef struct _FRAME_MARKER {
|
||
union {
|
||
struct {
|
||
ULONGLONG sof : 7;
|
||
ULONGLONG sol : 7;
|
||
ULONGLONG sor : 4;
|
||
ULONGLONG rrbgr : 7;
|
||
ULONGLONG rrbfr : 7;
|
||
ULONGLONG rrbpr : 6;
|
||
} f;
|
||
ULONGLONG Ulong64;
|
||
} u;
|
||
} FRAME_MARKER;
|
||
|
||
|
||
BOOLEAN
|
||
KiEmulateBranchLongFault(
|
||
IN PEXCEPTION_RECORD ExceptionRecord,
|
||
IN OUT PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN OUT PKTRAP_FRAME TrapFrame
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to emulate a brl instruction.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to an exception record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
Return Value:
|
||
|
||
A value of TRUE is return if the brl is successfully emulated.
|
||
Otherwise, a value of FALSE is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PULONGLONG BundleAddress;
|
||
PVOID ExceptionAddress;
|
||
ULONGLONG BundleLow;
|
||
ULONGLONG BundleHigh;
|
||
ULONGLONG Template;
|
||
BRL_INST BrlInst;
|
||
BRL0_INST BrlInst0;
|
||
ULONGLONG NewIP;
|
||
ULONGLONG Taken;
|
||
FRAME_MARKER Cfm;
|
||
|
||
BundleAddress = (PULONGLONG)TrapFrame->StIIP;
|
||
ExceptionAddress = (PVOID) TrapFrame->StIIP;
|
||
|
||
try {
|
||
|
||
//
|
||
// get the instruction bundle
|
||
//
|
||
|
||
BundleLow = *BundleAddress;
|
||
BundleHigh = *(BundleAddress+1);
|
||
|
||
} except ((KiCopyInformation(ExceptionRecord,
|
||
(GetExceptionInformation())->ExceptionRecord))) {
|
||
//
|
||
// Preserve the original exception address.
|
||
//
|
||
|
||
ExceptionRecord->ExceptionAddress = ExceptionAddress;
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
BrlInst0.u.Ulong64 = (BundleLow >> 46) | (BundleHigh << 18);
|
||
BrlInst.u.Ulong64 = (BundleHigh >> 23);
|
||
|
||
Template = BundleLow & 0x1f;
|
||
|
||
if (!((Template == 4)||(Template == 5))) {
|
||
|
||
//
|
||
// if template does not indicate MLX, return FALSE
|
||
//
|
||
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
switch (BrlInst.u.i.Op) {
|
||
|
||
case 0xc: // brl.cond
|
||
|
||
Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
|
||
break;
|
||
|
||
case 0xd: // brl.call
|
||
|
||
Taken = TrapFrame->Preds & (1i64 << BrlInst.u.i.qp);
|
||
|
||
if (Taken) {
|
||
|
||
switch (BrlInst.u.i.b1) {
|
||
case 0: TrapFrame->BrRp = TrapFrame->StIIP + 16; break;
|
||
case 1: ExceptionFrame->BrS0 = TrapFrame->StIIP + 16; break;
|
||
case 2: ExceptionFrame->BrS1 = TrapFrame->StIIP + 16; break;
|
||
case 3: ExceptionFrame->BrS2 = TrapFrame->StIIP + 16; break;
|
||
case 4: ExceptionFrame->BrS3 = TrapFrame->StIIP + 16; break;
|
||
case 5: ExceptionFrame->BrS4 = TrapFrame->StIIP + 16; break;
|
||
case 6: TrapFrame->BrT0 = TrapFrame->StIIP + 16; break;
|
||
case 7: TrapFrame->BrT1 = TrapFrame->StIIP + 16; break;
|
||
}
|
||
|
||
TrapFrame->RsPFS = TrapFrame->StIFS & 0x3FFFFFFFFFi64;
|
||
TrapFrame->RsPFS |= (ExceptionFrame->ApEC & (0x3fi64 << 52));
|
||
TrapFrame->RsPFS |= (((TrapFrame->StIPSR >> PSR_CPL) & 0x3) << 62);
|
||
|
||
Cfm.u.Ulong64 = TrapFrame->StIFS;
|
||
|
||
Cfm.u.f.sof -= Cfm.u.f.sol;
|
||
Cfm.u.f.sol = 0;
|
||
Cfm.u.f.sor = 0;
|
||
Cfm.u.f.rrbgr = 0;
|
||
Cfm.u.f.rrbfr = 0;
|
||
Cfm.u.f.rrbpr = 0;
|
||
|
||
TrapFrame->StIFS = Cfm.u.Ulong64;
|
||
TrapFrame->StIFS |= 0x8000000000000000;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
return FALSE;
|
||
|
||
}
|
||
|
||
if (Taken) {
|
||
|
||
NewIP = TrapFrame->StIIP +
|
||
(((BrlInst.u.i.i<<59)|(BrlInst0.u.i.imm39<<20)|(BrlInst.u.i.imm20)) << 4);
|
||
|
||
TrapFrame->StIIP = NewIP;
|
||
|
||
} else {
|
||
|
||
TrapFrame->StIIP += 16;
|
||
|
||
}
|
||
|
||
TrapFrame->StIPSR &= ~(3i64 << PSR_RI);
|
||
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
VOID
|
||
KiDispatchException (
|
||
IN PEXCEPTION_RECORD ExceptionRecord,
|
||
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN KPROCESSOR_MODE PreviousMode,
|
||
IN BOOLEAN FirstChance
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to dispatch an exception to the proper mode and
|
||
to cause the exception dispatcher to be called.
|
||
|
||
If the exception is a data misalignment, this is the first chance for
|
||
handling the exception, and the current thread has enabled automatic
|
||
alignment fixup, then an attempt is made to emulate the unaligned
|
||
reference.
|
||
|
||
If the exception is a floating exception (N.B. the pseudo status
|
||
STATUS_FLOAT_STACK_CHECK is used to signify this and is converted to the
|
||
proper code by examiningg the main status field of the floating point
|
||
status register).
|
||
|
||
If the exception is neither a data misalignment nor a floating point
|
||
exception and the the previous mode is kernel, then the exception
|
||
dispatcher is called directly to process the exception. Otherwise the
|
||
exception record, exception frame, and trap frame contents are copied
|
||
to the user mode stack. The contents of the exception frame and trap
|
||
are then modified such that when control is returned, execution will
|
||
commense in user mode in a routine which will call the exception
|
||
dispatcher.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to an exception record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
PreviousMode - Supplies the previous processor mode.
|
||
|
||
FirstChance - Supplies a boolean variable that specifies whether this
|
||
is the first (TRUE) or second (FALSE) time that this exception has
|
||
been processed.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CONTEXT ContextFrame;
|
||
EXCEPTION_RECORD ExceptionRecord1;
|
||
PPLABEL_DESCRIPTOR Plabel;
|
||
BOOLEAN UserApcPending;
|
||
BOOLEAN AlignmentFaultHandled;
|
||
BOOLEAN ExceptionWasForwarded = FALSE;
|
||
ISR Isr;
|
||
PSR Psr;
|
||
|
||
//
|
||
// If the exception is a illegal instruction, check to see if it was
|
||
// trying to executing a brl instruction. If so, emulate the brl
|
||
// instruction.
|
||
//
|
||
|
||
if (ExceptionRecord->ExceptionCode == STATUS_ILLEGAL_INSTRUCTION) {
|
||
|
||
Isr.ull = TrapFrame->StISR;
|
||
Psr.ull = TrapFrame->StIPSR;
|
||
|
||
if ((Isr.sb.isr_code == ISR_ILLEGAL_OP) && (Isr.sb.isr_ei == 1)) {
|
||
|
||
if (KiEmulateBranchLongFault(ExceptionRecord,
|
||
ExceptionFrame,
|
||
TrapFrame) == TRUE) {
|
||
|
||
//
|
||
// emulation was successful;
|
||
//
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// If the exception is a data misalignment, the previous mode was user,
|
||
// this is the first chance for handling the exception, and the current
|
||
// thread has enabled automatic alignment fixup, then attempt to emulate
|
||
// the unaligned reference.
|
||
//
|
||
|
||
if (ExceptionRecord->ExceptionCode == STATUS_DATATYPE_MISALIGNMENT) {
|
||
|
||
AlignmentFaultHandled = KiHandleAlignmentFault( ExceptionRecord,
|
||
ExceptionFrame,
|
||
TrapFrame,
|
||
PreviousMode,
|
||
FirstChance,
|
||
&ExceptionWasForwarded );
|
||
if (AlignmentFaultHandled != FALSE) {
|
||
goto Handled2;
|
||
}
|
||
}
|
||
|
||
//
|
||
// N.B. BREAKIN_BREAKPOINT check is in KdpTrap()
|
||
//
|
||
|
||
//
|
||
// If the exception is a floating point exception, then the
|
||
// ExceptionCode was set to STATUS_FLOAT_MULTIPLE_TRAPS or
|
||
// STATUS_FLOAT_MULTIPLE_FAULTS.
|
||
//
|
||
|
||
if ((ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_FAULTS) ||
|
||
(ExceptionRecord->ExceptionCode == STATUS_FLOAT_MULTIPLE_TRAPS)) {
|
||
|
||
if (KiEmulateFloat(ExceptionRecord, ExceptionFrame, TrapFrame)) {
|
||
|
||
//
|
||
// Emulation is successful; continue execution
|
||
//
|
||
|
||
return;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move machine state from trap and exception frames to a context frame,
|
||
// and increment the number of exceptions dispatched.
|
||
//
|
||
|
||
ContextFrame.ContextFlags = CONTEXT_FULL;
|
||
KeContextFromKframes(TrapFrame, ExceptionFrame, &ContextFrame);
|
||
KeGetCurrentPrcb()->KeExceptionDispatchCount += 1;
|
||
|
||
//
|
||
// Select the method of handling the exception based on the previous mode.
|
||
//
|
||
|
||
if (PreviousMode == KernelMode) {
|
||
|
||
//
|
||
// Previous mode was kernel.
|
||
//
|
||
// If this is the first chance, the kernel debugger is active, and
|
||
// the exception is a kernel breakpoint, then give the kernel debugger
|
||
// a chance to handle the exception.
|
||
//
|
||
// If this is the first chance and the kernel debugger is not active
|
||
// or does not handle the exception, then attempt to find a frame
|
||
// handler to handle the exception.
|
||
//
|
||
// If this is the second chance or the exception is not handled, then
|
||
// if the kernel debugger is active, then give the kernel debugger a
|
||
// second chance to handle the exception. If the kernel debugger does
|
||
// not handle the exception, then bug check.
|
||
//
|
||
|
||
if (FirstChance != FALSE) {
|
||
|
||
//
|
||
// This is the first chance to handle the exception.
|
||
//
|
||
// Note: RtlpCaptureRnats() flushes the RSE and captures the
|
||
// Nat bits of stacked registers in the RSE frame at
|
||
// which exception happens.
|
||
//
|
||
|
||
RtlpCaptureRnats(&ContextFrame);
|
||
TrapFrame->RsRNAT = ContextFrame.RsRNAT;
|
||
|
||
//
|
||
// If the kernel debugger is active, the exception is a breakpoint,
|
||
// and the breakpoint is handled by the kernel debugger, then give
|
||
// the kernel debugger a chance to handle the exception.
|
||
//
|
||
|
||
if ((KiDebugRoutine != NULL) &&
|
||
(KdIsThisAKdTrap(ExceptionRecord,
|
||
&ContextFrame,
|
||
KernelMode) != FALSE)) {
|
||
|
||
if (((KiDebugRoutine) (TrapFrame,
|
||
ExceptionFrame,
|
||
ExceptionRecord,
|
||
&ContextFrame,
|
||
KernelMode,
|
||
FALSE)) != FALSE) {
|
||
|
||
goto Handled1;
|
||
}
|
||
}
|
||
|
||
if (RtlDispatchException(ExceptionRecord, &ContextFrame) != FALSE) {
|
||
goto Handled1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// This is the second chance to handle the exception.
|
||
//
|
||
|
||
if (KiDebugRoutine != NULL) {
|
||
if (((KiDebugRoutine) (TrapFrame,
|
||
ExceptionFrame,
|
||
ExceptionRecord,
|
||
&ContextFrame,
|
||
PreviousMode,
|
||
TRUE)) != FALSE) {
|
||
goto Handled1;
|
||
}
|
||
}
|
||
|
||
KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
|
||
ExceptionRecord->ExceptionCode,
|
||
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
|
||
ExceptionRecord->ExceptionInformation[0],
|
||
ExceptionRecord->ExceptionInformation[1]);
|
||
|
||
} else {
|
||
|
||
//
|
||
// Previous mode was user.
|
||
//
|
||
// If this is the first chance, the kernel debugger is active, the
|
||
// exception is a kernel breakpoint, and the current process is not
|
||
// being debugged, or the current process is being debugged, but the
|
||
// the breakpoint is not a kernel breakpoint instruction, then give
|
||
// the kernel debugger a chance to handle the exception.
|
||
//
|
||
// If this is the first chance and the current process has a debugger
|
||
// port, then send a message to the debugger port and wait for a reply.
|
||
// If the debugger handles the exception, then continue execution. Else
|
||
// transfer the exception information to the user stack, transition to
|
||
// user mode, and attempt to dispatch the exception to a frame based
|
||
// handler. If a frame based handler handles the exception, then continue
|
||
// execution. Otherwise, execute the raise exception system service
|
||
// which will call this routine a second time to process the exception.
|
||
//
|
||
// If this is the second chance and the current process has a debugger
|
||
// port, then send a message to the debugger port and wait for a reply.
|
||
// If the debugger handles the exception, then continue execution. Else
|
||
// if the current process has a subsystem port, then send a message to
|
||
// the subsystem port and wait for a reply. If the subsystem handles the
|
||
// exception, then continue execution. Else terminate the thread.
|
||
//
|
||
|
||
if (FirstChance != FALSE) {
|
||
|
||
//
|
||
// If the kernel debugger is active, the exception is a kernel
|
||
// breakpoint, and the current process is not being debugged,
|
||
// or the current process is being debugged, but the breakpoint
|
||
// is not a kernel breakpoint instruction, then give the kernel
|
||
// debugger a chance to handle the exception.
|
||
//
|
||
|
||
if ((KiDebugRoutine != NULL) &&
|
||
(KdIsThisAKdTrap(ExceptionRecord,
|
||
&ContextFrame,
|
||
UserMode) != FALSE) &&
|
||
((PsGetCurrentProcess()->DebugPort == NULL) ||
|
||
((PsGetCurrentProcess()->DebugPort != NULL) &&
|
||
((ExceptionRecord->ExceptionInformation[0] !=
|
||
BREAKPOINT_STOP) &&
|
||
(ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP))))) {
|
||
|
||
if (((KiDebugRoutine) (TrapFrame,
|
||
ExceptionFrame,
|
||
ExceptionRecord,
|
||
&ContextFrame,
|
||
UserMode,
|
||
FALSE)) != FALSE) {
|
||
|
||
goto Handled1;
|
||
}
|
||
}
|
||
|
||
//
|
||
// This is the first chance to handle the exception.
|
||
//
|
||
|
||
if (ExceptionWasForwarded == FALSE &&
|
||
DbgkForwardException(ExceptionRecord, TRUE, FALSE)) {
|
||
TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
|
||
goto Handled2;
|
||
}
|
||
|
||
//
|
||
// Transfer exception information to the user stack, transition
|
||
// to user mode, and attempt to dispatch the exception to a frame
|
||
// based handler.
|
||
//
|
||
//
|
||
// We are running on the kernel stack now. On the user stack, we
|
||
// build a stack frame containing the following:
|
||
//
|
||
// | |
|
||
// |-----------------------------------|
|
||
// | |
|
||
// | User's stack frame |
|
||
// | |
|
||
// |-----------------------------------|
|
||
// | |
|
||
// | Context record |
|
||
// | |
|
||
// | |
|
||
// |- - - - - - - - - - - - - - - - - -|
|
||
// | |
|
||
// | Exception record |
|
||
// | |
|
||
// |- - - - - - - - - - - - - - - - - -|
|
||
// | Stack Scratch Area |
|
||
// |-----------------------------------|
|
||
// | |
|
||
//
|
||
// This stack frame is for KiUserExceptionDispatcher, the assembly
|
||
// langauge routine that effects transfer in user mode to
|
||
// RtlDispatchException. KiUserExceptionDispatcher is passed
|
||
// pointers to the Exception Record and Context Record as
|
||
// parameters.
|
||
//
|
||
|
||
repeat:
|
||
try {
|
||
|
||
//
|
||
// Compute length of exception record and new aligned stack
|
||
// address.
|
||
//
|
||
|
||
ULONG Length = (STACK_SCRATCH_AREA + 15 +
|
||
sizeof(EXCEPTION_RECORD) + sizeof(CONTEXT)) & ~(15);
|
||
ULONGLONG UserStack = (ContextFrame.IntSp & (~15)) - Length;
|
||
ULONGLONG ContextSlot = UserStack + STACK_SCRATCH_AREA;
|
||
ULONGLONG ExceptSlot = ContextSlot + sizeof(CONTEXT);
|
||
PULONGLONG PUserStack = (PULONGLONG) UserStack;
|
||
|
||
//
|
||
// When the exception gets dispatched to the user the
|
||
// user BSP state will be loaded. Clear the preload
|
||
// count in the RSE so it is not reloaded after if the
|
||
// context is reused.
|
||
//
|
||
|
||
ContextFrame.RsRSC = ZERO_PRELOAD_SIZE(ContextFrame.RsRSC);
|
||
|
||
//
|
||
// Probe user stack area for writeability and then transfer the
|
||
// exception record and conext record to the user stack area.
|
||
//
|
||
|
||
ProbeForWrite((PCHAR)UserStack, Length, sizeof(QUAD));
|
||
RtlCopyMemory((PVOID)ContextSlot, &ContextFrame,
|
||
sizeof(CONTEXT));
|
||
RtlCopyMemory((PVOID)ExceptSlot, ExceptionRecord,
|
||
sizeof(EXCEPTION_RECORD));
|
||
|
||
//
|
||
// Set address of exception record and context record in
|
||
// the exception frame and the new stack pointer in the
|
||
// current trap frame. Also set the initial frame size
|
||
// to be zero.
|
||
//
|
||
// N.B. User exception dispatcher flushes the RSE
|
||
// and updates the BSPStore field upon entry.
|
||
//
|
||
|
||
TrapFrame->RsPFS = SANITIZE_PFS(TrapFrame->StIFS, UserMode);
|
||
TrapFrame->StIFS &= 0xffffffc000000000i64;
|
||
TrapFrame->StIPSR &= ~((0x3i64 << PSR_RI) | (0x1i64 << PSR_IS));
|
||
TrapFrame->IntSp = UserStack;
|
||
TrapFrame->IntNats = 0;
|
||
|
||
//
|
||
// reset the user FPSR so that a recursive exception will not occur.
|
||
//
|
||
|
||
// TrapFrame->StFPSR = USER_FPSR_INITIAL;
|
||
|
||
ExceptionFrame->IntS0 = ExceptSlot;
|
||
ExceptionFrame->IntS1 = ContextSlot;
|
||
ExceptionFrame->IntNats = 0;
|
||
|
||
//
|
||
// Set the address and the gp of the exception routine that
|
||
// will call the exception dispatcher and then return to the
|
||
// trap handler. The trap handler will restore the exception
|
||
// and trap frame context and continue execution in the routine
|
||
// that will call the exception dispatcher.
|
||
//
|
||
|
||
Plabel = (PPLABEL_DESCRIPTOR)KeUserExceptionDispatcher;
|
||
TrapFrame->StIIP = Plabel->EntryPoint;
|
||
TrapFrame->IntGp = Plabel->GlobalPointer;
|
||
|
||
return;
|
||
|
||
//
|
||
// If an exception occurs, then copy the new exception information
|
||
// to an exception record and handle the exception.
|
||
//
|
||
|
||
} except (KiCopyInformation(&ExceptionRecord1,
|
||
(GetExceptionInformation())->ExceptionRecord)) {
|
||
|
||
//
|
||
// If the exception is a stack overflow, then attempt
|
||
// to raise the stack overflow exception. Otherwise,
|
||
// the user's stack is not accessible, or is misaligned,
|
||
// and second chance processing is performed.
|
||
//
|
||
|
||
if (ExceptionRecord1.ExceptionCode == STATUS_STACK_OVERFLOW) {
|
||
ExceptionRecord1.ExceptionAddress = ExceptionRecord->ExceptionAddress;
|
||
RtlCopyMemory((PVOID)ExceptionRecord,
|
||
&ExceptionRecord1, sizeof(EXCEPTION_RECORD));
|
||
goto repeat;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// This is the second chance to handle the exception.
|
||
//
|
||
|
||
UserApcPending = KeGetCurrentThread()->ApcState.UserApcPending;
|
||
if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) {
|
||
TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
|
||
goto Handled2;
|
||
|
||
} else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) {
|
||
TrapFrame->StFPSR = SANITIZE_FSR(TrapFrame->StFPSR, UserMode);
|
||
goto Handled2;
|
||
|
||
} else {
|
||
ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode);
|
||
KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
|
||
ExceptionRecord->ExceptionCode,
|
||
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
|
||
ExceptionRecord->ExceptionInformation[0],
|
||
ExceptionRecord->ExceptionInformation[1]);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Move machine state from context frame to trap and exception frames and
|
||
// then return to continue execution with the restored state.
|
||
//
|
||
|
||
Handled1:
|
||
KeContextToKframes(TrapFrame, ExceptionFrame, &ContextFrame,
|
||
ContextFrame.ContextFlags, PreviousMode);
|
||
|
||
//
|
||
// Exception was handled by the debugger or the associated subsystem
|
||
// and state was modified, if necessary, using the get state and set
|
||
// state capabilities. Therefore the context frame does not need to
|
||
// be transfered to the trap and exception frames.
|
||
//
|
||
|
||
Handled2:
|
||
return;
|
||
}
|
||
|
||
ULONG
|
||
KiCopyInformation (
|
||
IN OUT PEXCEPTION_RECORD ExceptionRecord1,
|
||
IN PEXCEPTION_RECORD ExceptionRecord2
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called from an exception filter to copy the exception
|
||
information from one exception record to another when an exception occurs.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord1 - Supplies a pointer to the destination exception record.
|
||
|
||
ExceptionRecord2 - Supplies a pointer to the source exception record.
|
||
|
||
Return Value:
|
||
|
||
A value of EXCEPTION_EXECUTE_HANDLER is returned as the function value.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Copy one exception record to another and return value that causes
|
||
// an exception handler to be executed.
|
||
//
|
||
|
||
RtlCopyMemory((PVOID)ExceptionRecord1,
|
||
(PVOID)ExceptionRecord2,
|
||
sizeof(EXCEPTION_RECORD));
|
||
|
||
return EXCEPTION_EXECUTE_HANDLER;
|
||
}
|
||
|
||
NTSTATUS
|
||
KeRaiseUserException(
|
||
IN NTSTATUS ExceptionCode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function causes an exception to be raised in the calling thread's user-mode
|
||
context. It does this by editing the trap frame the kernel was entered with to
|
||
point to trampoline code that raises the requested exception.
|
||
|
||
Arguments:
|
||
|
||
ExceptionCode - Supplies the status value to be used as the exception
|
||
code for the exception that is to be raised.
|
||
|
||
Return Value:
|
||
|
||
The status value that should be returned by the caller.
|
||
|
||
--*/
|
||
|
||
{
|
||
PKTRAP_FRAME TrapFrame;
|
||
IA64_PFS Ifs;
|
||
|
||
ASSERT(KeGetPreviousMode() == UserMode);
|
||
|
||
TrapFrame = KeGetCurrentThread()->TrapFrame;
|
||
if (TrapFrame == NULL) {
|
||
return ExceptionCode;
|
||
}
|
||
|
||
try {
|
||
PULONGLONG IntSp;
|
||
|
||
IntSp = (PULONGLONG) TrapFrame->IntSp;
|
||
ProbeForWriteSmallStructure (IntSp, sizeof (*IntSp)*2, sizeof(QUAD));
|
||
*IntSp++ = TrapFrame->BrRp;
|
||
*IntSp = TrapFrame->RsPFS;
|
||
TrapFrame->StIIP = ((PPLABEL_DESCRIPTOR)KeRaiseUserExceptionDispatcher)->EntryPoint;
|
||
} except (EXCEPTION_EXECUTE_HANDLER) {
|
||
return (ExceptionCode);
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Set IFS the size after the the system call.
|
||
//
|
||
|
||
Ifs.ull = TrapFrame->StIFS;
|
||
Ifs.sb.pfs_sof = Ifs.sb.pfs_sof - Ifs.sb.pfs_sol;
|
||
Ifs.sb.pfs_sol = 0;
|
||
TrapFrame->StIFS = Ifs.ull;
|
||
|
||
return(ExceptionCode);
|
||
}
|