346 lines
9.4 KiB
C
346 lines
9.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1990 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
raisexcp.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the internal kernel code to continue execution
|
||
and raise a exception.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 8-Aug-1990
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
|
||
--*/
|
||
|
||
#include "ki.h"
|
||
|
||
VOID
|
||
KiContinuePreviousModeUser(
|
||
IN PCONTEXT ContextRecord,
|
||
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN KPROCESSOR_MODE PreviousMode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called from KiContinue if PreviousMode is
|
||
not KernelMode. In this case a kernel mode copy of the
|
||
ContextRecord is made before calling KeContextToKframes.
|
||
This is done in a seperate routine to save stack space for
|
||
the common case which is PreviousMode == Kernel.
|
||
|
||
N.B. This routine is called from within a try/except block
|
||
that will be used to handle errors like invalid context.
|
||
|
||
Arguments:
|
||
|
||
|
||
ContextRecord - Supplies a pointer to a context record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
PreviousMode - Not KernelMode.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
CONTEXT ContextRecord2;
|
||
|
||
//
|
||
// Copy the context record to kernel mode space.
|
||
//
|
||
|
||
ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN);
|
||
RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT));
|
||
ContextRecord = &ContextRecord2;
|
||
|
||
//
|
||
// Move information from the context record to the exception
|
||
// and trap frames.
|
||
//
|
||
|
||
KeContextToKframes(TrapFrame,
|
||
ExceptionFrame,
|
||
&ContextRecord2,
|
||
ContextRecord2.ContextFlags,
|
||
PreviousMode);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
KiContinue (
|
||
IN PCONTEXT ContextRecord,
|
||
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN PKTRAP_FRAME TrapFrame
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to copy the specified context frame to the
|
||
specified exception and trap frames for the continue system service.
|
||
|
||
Arguments:
|
||
|
||
ContextRecord - Supplies a pointer to a context record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
Return Value:
|
||
|
||
STATUS_ACCESS_VIOLATION is returned if the context record is not readable
|
||
from user mode.
|
||
|
||
STATUS_DATATYPE_MISALIGNMENT is returned if the context record is not
|
||
properly aligned.
|
||
|
||
STATUS_SUCCESS is returned if the context frame is copied successfully
|
||
to the specified exception and trap frames.
|
||
|
||
--*/
|
||
|
||
{
|
||
KPROCESSOR_MODE PreviousMode;
|
||
NTSTATUS Status;
|
||
KIRQL OldIrql;
|
||
BOOLEAN IrqlChanged = FALSE;
|
||
|
||
//
|
||
// Synchronize with other context operations.
|
||
//
|
||
|
||
Status = STATUS_SUCCESS;
|
||
if (KeGetCurrentIrql() < APC_LEVEL) {
|
||
|
||
//
|
||
// To support try-except and ExRaiseStatus in device driver code we
|
||
// need to check if we are already at raised level.
|
||
//
|
||
|
||
IrqlChanged = TRUE;
|
||
KeRaiseIrql(APC_LEVEL, &OldIrql);
|
||
}
|
||
|
||
//
|
||
// Establish an exception handler and probe and capture the specified
|
||
// context record if the previous mode is user. If the probe or copy
|
||
// fails, then return the exception code as the function value. Else
|
||
// copy the context record to the specified exception and trap frames,
|
||
// and return success as the function value.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Get the previous processor mode. If the previous processor mode is
|
||
// user, then probe and copy the specified context record.
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
if (PreviousMode != KernelMode) {
|
||
KiContinuePreviousModeUser(ContextRecord,
|
||
ExceptionFrame,
|
||
TrapFrame,
|
||
PreviousMode);
|
||
} else {
|
||
|
||
//
|
||
// Move information from the context record to the exception
|
||
// and trap frames.
|
||
//
|
||
|
||
KeContextToKframes(TrapFrame,
|
||
ExceptionFrame,
|
||
ContextRecord,
|
||
ContextRecord->ContextFlags,
|
||
PreviousMode);
|
||
}
|
||
|
||
//
|
||
// If an exception occurs during the probe or copy of the context
|
||
// record, then always handle the exception and return the exception
|
||
// code as the status value.
|
||
//
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
Status = GetExceptionCode();
|
||
}
|
||
|
||
if (IrqlChanged) {
|
||
KeLowerIrql (OldIrql);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
KiRaiseException (
|
||
IN PEXCEPTION_RECORD ExceptionRecord,
|
||
IN PCONTEXT ContextRecord,
|
||
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
IN PKTRAP_FRAME TrapFrame,
|
||
IN BOOLEAN FirstChance
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to raise an exception. The exception can be
|
||
raised as a first or second chance exception.
|
||
|
||
Arguments:
|
||
|
||
ExceptionRecord - Supplies a pointer to an exception record.
|
||
|
||
ContextRecord - Supplies a pointer to a context record.
|
||
|
||
ExceptionFrame - Supplies a pointer to an exception frame.
|
||
|
||
TrapFrame - Supplies a pointer to a trap frame.
|
||
|
||
FirstChance - Supplies a boolean value that specifies whether this is
|
||
the first (TRUE) or second (FALSE) chance for the exception.
|
||
|
||
Return Value:
|
||
|
||
STATUS_ACCESS_VIOLATION is returned if either the exception or the context
|
||
record is not readable from user mode.
|
||
|
||
STATUS_DATATYPE_MISALIGNMENT is returned if the exception record or the
|
||
context record are not properly aligned.
|
||
|
||
STATUS_INVALID_PARAMETER is returned if the number of exception parameters
|
||
is greater than the maximum allowable number of exception parameters.
|
||
|
||
STATUS_SUCCESS is returned if the exception is dispatched and handled.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
CONTEXT ContextRecord2;
|
||
EXCEPTION_RECORD ExceptionRecord2;
|
||
ULONG Length;
|
||
ULONG Params;
|
||
KPROCESSOR_MODE PreviousMode;
|
||
|
||
//
|
||
// Establish an exception handler and probe the specified exception and
|
||
// context records for read accessibility. If the probe fails, then
|
||
// return the exception code as the service status. Else call the exception
|
||
// dispatcher to dispatch the exception.
|
||
//
|
||
|
||
try {
|
||
|
||
//
|
||
// Get the previous processor mode. If the previous processor mode
|
||
// is user, then probe and copy the specified exception and context
|
||
// records.
|
||
//
|
||
|
||
PreviousMode = KeGetPreviousMode();
|
||
if (PreviousMode != KernelMode) {
|
||
ProbeForReadSmallStructure(ContextRecord, sizeof(CONTEXT), CONTEXT_ALIGN);
|
||
ProbeForReadSmallStructure(ExceptionRecord,
|
||
FIELD_OFFSET (EXCEPTION_RECORD, NumberParameters) +
|
||
sizeof (ExceptionRecord->NumberParameters), sizeof(ULONG));
|
||
Params = ExceptionRecord->NumberParameters;
|
||
if (Params > EXCEPTION_MAXIMUM_PARAMETERS) {
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// The exception record structure is defined unlike others with trailing
|
||
// information as being its maximum size rather than just a single trailing
|
||
// element.
|
||
//
|
||
Length = (sizeof(EXCEPTION_RECORD) -
|
||
((EXCEPTION_MAXIMUM_PARAMETERS - Params) *
|
||
sizeof(ExceptionRecord->ExceptionInformation[0])));
|
||
|
||
//
|
||
// The structure is currently less that 64k so we don't really need this probe.
|
||
//
|
||
ProbeForRead(ExceptionRecord, Length, sizeof(ULONG));
|
||
|
||
//
|
||
// Copy the exception and context record to local storage so an
|
||
// access violation cannot occur during exception dispatching.
|
||
//
|
||
|
||
RtlCopyMemory(&ContextRecord2, ContextRecord, sizeof(CONTEXT));
|
||
RtlCopyMemory(&ExceptionRecord2, ExceptionRecord, Length);
|
||
ContextRecord = &ContextRecord2;
|
||
ExceptionRecord = &ExceptionRecord2;
|
||
//
|
||
// The number of parameters might have changed after we validated but before we
|
||
// copied the structure. Fix this up as lower levels might not like this.
|
||
//
|
||
ExceptionRecord->NumberParameters = Params;
|
||
}
|
||
|
||
//
|
||
// If an exception occurs during the probe of the exception or context
|
||
// record, then always handle the exception and return the exception code
|
||
// as the status value.
|
||
//
|
||
|
||
} except(EXCEPTION_EXECUTE_HANDLER) {
|
||
return GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// Move information from the context record to the exception and
|
||
// trap frames.
|
||
//
|
||
|
||
KeContextToKframes(TrapFrame,
|
||
ExceptionFrame,
|
||
ContextRecord,
|
||
ContextRecord->ContextFlags,
|
||
PreviousMode);
|
||
|
||
//
|
||
// Make sure the reserved bit is clear in the exception code and
|
||
// perform exception dispatching.
|
||
//
|
||
// N.B. The reserved bit is used to differentiate internally gerarated
|
||
// codes from codes generated by application programs.
|
||
//
|
||
|
||
ExceptionRecord->ExceptionCode &= 0xefffffff;
|
||
KiDispatchException(ExceptionRecord,
|
||
ExceptionFrame,
|
||
TrapFrame,
|
||
PreviousMode,
|
||
FirstChance);
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|