/*++ Copyright (c) 1990 Microsoft Corporation Module Name: trapc.c Abstract: This module implements the specific exception handlers for EM exceptions. Called by the KiGenericExceptionHandler. Author: Bernard Lint 4-Apr-96 Environment: Kernel mode only. Revision History: --*/ #include "ki.h" #include "ps.h" #include extern BOOLEAN PsWatchEnabled; extern VOID ExpInterlockedPopEntrySListResume(); BOOLEAN KiMemoryFault ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This function processes memory faults. Arguments: TrapFrame - Pointer to the trap frame. Return Value: TRUE on success, FALSE on failure. --*/ { PEXCEPTION_RECORD ExceptionRecord; BOOLEAN StoreInstruction; PVOID VirtualAddress; NTSTATUS Status; VirtualAddress = (PVOID)TrapFrame->StIFA; if (TrapFrame->StISR & (1i64 << ISR_X)) { #if _MERCED_A0_ if ((TrapFrame->StIPSR & (1i64 << PSR_IS)) == 0) { VirtualAddress = (PVOID)TrapFrame->StIIP; } #endif // // Indicate execution fault. // StoreInstruction = 2; } else if (TrapFrame->StISR & (1i64 << ISR_W)) { // // Indicate store. // StoreInstruction = 1; } else { // // Indicate read. // StoreInstruction = 0; } if (((ULONG_PTR)VirtualAddress < MM_MAX_WOW64_ADDRESS) && (PsGetCurrentProcess()->Wow64Process != NULL)) { Status = MmX86Fault(StoreInstruction, VirtualAddress, (KPROCESSOR_MODE)TrapFrame->PreviousMode, TrapFrame); } else { Status = MmAccessFault(StoreInstruction, VirtualAddress, (KPROCESSOR_MODE)TrapFrame->PreviousMode, TrapFrame); } // // Check if working set watch is enabled. // if (NT_SUCCESS(Status)) { if (PsWatchEnabled) { PsWatchWorkingSet(Status, (PVOID)TrapFrame->StIIP, (PVOID)VirtualAddress); } // // Check if debugger has any breakpoints that should be inserted // KdSetOwedBreakpoints(); return FALSE; } if (KeInvalidAccessAllowed(TrapFrame)) { TrapFrame->StIIP = ((PPLABEL_DESCRIPTOR)ExpInterlockedPopEntrySListResume)->EntryPoint; return FALSE; } if (TrapFrame->StISR & (1i64 << ISR_SP)) { // // Set IPSR.ed bit if it was a fault on a speculative load. // TrapFrame->StIPSR |= (1i64 << PSR_ED); return FALSE; } // // Failure returned from MmAccessFault. // Initialize Exception record. // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionCode = Status; ExceptionRecord->ExceptionAddress = (PVOID)RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; if (StoreInstruction == 2) { PSR Psr; Psr.ull = TrapFrame->StIPSR; // // instruction access fault // ExceptionRecord->ExceptionInformation[0] = TrapFrame->StIIPA; } else { // // data access fault // ExceptionRecord->ExceptionInformation[0] = (ULONG_PTR)StoreInstruction; } ExceptionRecord->ExceptionInformation[1] = (ULONG_PTR)VirtualAddress; ExceptionRecord->ExceptionInformation[2] = (ULONG_PTR)Status; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; // // Status = STATUS_IN_PAGE_ERROR | 0x10000000 // is a special status that indicates a page fault at Irql > APC // // The following statuses can be forwarded: // STATUS_ACCESS_VIOLATION // STATUS_GUARD_PAGE_VIOLATION // STATUS_STACK_OVERFLOW // // All other status will be set to: // STATUS_IN_PAGE_ERROR // switch (Status) { case STATUS_ACCESS_VIOLATION: case STATUS_GUARD_PAGE_VIOLATION: case STATUS_STACK_OVERFLOW: case STATUS_IN_PAGE_ERROR: break; default: ExceptionRecord->ExceptionCode = STATUS_IN_PAGE_ERROR; break; case STATUS_IN_PAGE_ERROR | 0x10000000: // // Handle the special case status returned from MmAccessFault, // we have taken a page fault at Irql > APC_LEVEL. // KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL, (ULONG_PTR)VirtualAddress, (ULONG_PTR)KeGetCurrentIrql(), (ULONG_PTR)StoreInstruction, (ULONG_PTR)TrapFrame->StIIP); // // should not get here // break; } return TRUE; } typedef struct _BREAK_INST { union { struct { ULONGLONG qp: 6; ULONGLONG imm20: 20; ULONGLONG x: 1; ULONGLONG x6: 6; ULONGLONG x3: 3; ULONGLONG i: 1; ULONGLONG Op: 4; ULONGLONG Rsv: 23; } i_field; ULONGLONG Ulong64; } u; } BREAK_INST; ULONG KiExtractImmediate ( IN ULONGLONG Iip, IN ULONG SlotNumber ) /*++ Routine Description: Extract immediate operand from break instruction. Arguments: Iip - Bundle address of instruction SlotNumber - Slot of break instruction within bundle Return Value: Value of immediate operand. --*/ { PULONGLONG BundleAddress; ULONGLONG BundleLow; ULONGLONG BundleHigh; BREAK_INST BreakInst; ULONG Imm21; BundleAddress = (PULONGLONG)Iip; BundleLow = *BundleAddress; BundleHigh = *(BundleAddress+1); // // Align instruction // switch (SlotNumber) { case 0: BreakInst.u.Ulong64 = BundleLow >> 5; break; case 1: BreakInst.u.Ulong64 = (BundleLow >> 46) | (BundleHigh << 18); break; case 2: BreakInst.u.Ulong64 = (BundleHigh >> 23); break; } // // Extract immediate value // Imm21 = (ULONG)(BreakInst.u.i_field.i<<20) | (ULONG)(BreakInst.u.i_field.imm20); return Imm21; } BOOLEAN KiDebugFault ( IN PKTRAP_FRAME TrapFrame ) { PEXCEPTION_RECORD ExceptionRecord; KEXCEPTION_FRAME Dummy; PKPRCB Prcb; TrapFrame->StIPSR |= (1i64 << PSR_DD); if (((TrapFrame->StIPSR >> PSR_CPL) & (PSR_CPL_LEN - 1)) == IA64_KERNEL_PL) { // // Disable all hardware breakpoints // KeSetLowPsrBit(PSR_DB, 0); } // // Initialize exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionCode = STATUS_SINGLE_STEP; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = TrapFrame->StIFA; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; return TRUE; } BOOLEAN KiOtherBreakException ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for break exception other than the ones for fast and normal system calls. This includes debug break points. Arguments: TrapFrame - Pointer to the trap frame. Return Value: NT status code. --*/ { PEXCEPTION_RECORD ExceptionRecord; ULONG BreakImmediate; ISR Isr; BreakImmediate = (ULONG)(TrapFrame->StIIM); // // Handle break.b case // try { if (BreakImmediate == 0) { Isr.ull = TrapFrame->StISR; BreakImmediate = KiExtractImmediate(TrapFrame->StIIP, (ULONG)Isr.sb.isr_ei); TrapFrame->StIIM = BreakImmediate; } } except (EXCEPTION_EXECUTE_HANDLER) { // // if an exception (memory fault) occurs, then let it re-execute break.b. // return FALSE; } // // Initialize exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; switch (BreakImmediate) { case KERNEL_BREAKPOINT: case USER_BREAKPOINT: case BREAKPOINT_PRINT: case BREAKPOINT_PROMPT: case BREAKPOINT_STOP: case BREAKPOINT_LOAD_SYMBOLS: case BREAKPOINT_UNLOAD_SYMBOLS: case BREAKPOINT_BREAKIN: ExceptionRecord->ExceptionCode = STATUS_BREAKPOINT; ExceptionRecord->ExceptionInformation[0] = BreakImmediate; break; case INTEGER_DIVIDE_BY_ZERO_BREAK: ExceptionRecord->ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO; break; case INTEGER_OVERFLOW_BREAK: ExceptionRecord->ExceptionCode = STATUS_INTEGER_OVERFLOW; break; case MISALIGNED_DATA_BREAK: ExceptionRecord->ExceptionCode = STATUS_DATATYPE_MISALIGNMENT; break; case RANGE_CHECK_BREAK: case NULL_POINTER_DEFERENCE_BREAK: case DECIMAL_OVERFLOW_BREAK: case DECIMAL_DIVIDE_BY_ZERO_BREAK: case PACKED_DECIMAL_ERROR_BREAK: case INVALID_ASCII_DIGIT_BREAK: case INVALID_DECIMAL_DIGIT_BREAK: case PARAGRAPH_STACK_OVERFLOW_BREAK: default: #if DBG InbvDisplayString ("KiOtherBreakException: Unknown break code.\n"); #endif // DBG ExceptionRecord->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION; break; } return TRUE; } BOOLEAN KiGeneralExceptions ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for general exception faults: attempt to execute an illegal operation, privileged instruction, access a privileged register, unimplemented field, unimplemented register, or take an inter-ISA branch when disabled. Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: ISR.ei bits indicate which instruction caused the exception. ISR.code{3:0} Non-access instruction (ISR.na = 1) = 0 tpa = 1 fc = 2 probe = 3 tak = 4 lfetch ISR.code{7:4} = 0: Illegal operation fault: All reported as STATUS_ILLEGAL_INSTRUCTION. ISR.rs = 0: An attempt to execute an illegal operation: -- unassigned major opcodes -- unassigned sub-opcodes -- reserved instruction fields -- writing a read-only register -- accessing a reserved register ISR.rs = 1: -- attempt to write outside the current register stack frame -- INVALRS operation with RCS.en = 1 -- write to BSP with RCS.en = 1 -- write to RNATRC with RCS.en = 1 -- read from RNATRC with RCS.en = 1 ISR.code{7:4} = 1: Privileged operation fault: Reported as STATUS_PRIVILEGED_INSTRUCTION. ISR.code{7:4} = 2: Privileged register fault: Reported as STATUS_PRIVILEGED_INSTRUCTION. ISR.code{7:4} = 3: Reserved register fault: Reported as STATUS_ILLEGAL_INSTRUCTION. ISR.code{7:4} = 4: Illegal ISA transition fault: Reported as STATUS_ILLEGAL_INSTRUCTION. --*/ { BOOLEAN StoreInstruction = FALSE; ULONG IsrCode; PEXCEPTION_RECORD ExceptionRecord; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; IsrCode = (LONG)((TrapFrame->StISR >> ISR_CODE) & ISR_CODE_MASK); // // Look at ISR code bits {7:4} // switch (IsrCode >> 4) { case ISR_PRIV_OP: case ISR_PRIV_REG: ExceptionRecord->ExceptionCode = STATUS_PRIVILEGED_INSTRUCTION; break; case ISR_RESVD_REG: // // Indicate store or not // if (TrapFrame->StISR & (1i64 << ISR_W)) { StoreInstruction = TRUE; } else if (TrapFrame->StISR & (1i64 << ISR_X)) { // // Indicate execution fault or not // StoreInstruction = 2; } ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; ExceptionRecord->ExceptionInformation[0] = (ULONG_PTR)StoreInstruction; ExceptionRecord->ExceptionInformation[1] = 0x1ff8000000000000; ExceptionRecord->ExceptionInformation[2] = (ULONG_PTR)STATUS_ACCESS_VIOLATION; break; case ISR_ILLEGAL_OP: case ISR_ILLEGAL_ISA: ExceptionRecord->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION; break; case ISR_ILLEGAL_HAZARD: // // a new status code will be introduced for hazard faults. // ExceptionRecord->ExceptionCode = STATUS_ILLEGAL_INSTRUCTION; break; default: if (TrapFrame->PreviousMode == KernelMode) { KeBugCheckEx(0xFFFFFFFF, (ULONG_PTR)TrapFrame->StISR, (ULONG_PTR)TrapFrame->StIIP, (ULONG_PTR)TrapFrame, 0 ); } break; } return TRUE; } BOOLEAN KiUnimplementedAddressTrap ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for unimplemented instruction faults: an attempt is made to execute an instruction at an unimplemented address. Arguments: TrapFrame - Pointer to the trap frame. Return Value: --*/ { PEXCEPTION_RECORD ExceptionRecord; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[1] = TrapFrame->StIIP; ExceptionRecord->ExceptionInformation[2] = STATUS_ACCESS_VIOLATION; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; return TRUE; } BOOLEAN KiNatExceptions ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for NaT consumption exception faults Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: ISR.ei bits indicate which instruction caused the exception. ISR.code{3:0} Non-access instruction (ISR.na = 1) = 0 tpa = 1 fc = 2 probe = 3 tak = 4 lfetch ISR.code{7:4} = 1: Register NaT consumption fault ISR.code{7:4} = 2: NaT page consumption fault --*/ { BOOLEAN StoreInstruction = FALSE; ULONG IsrCode; PEXCEPTION_RECORD ExceptionRecord; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; IsrCode = (LONG)((TrapFrame->StISR >> ISR_CODE) & ISR_CODE_MASK); // // Look at ISR code bits {7:4} // switch (IsrCode >> 4) { case ISR_NAT_REG: #if 0 if (TrapFrame->PreviousMode == KernelMode) { DbgPrint("FATAL ERROR: Kernel hit a Nat Consumpation Fault!\n"); KeBugCheckEx(0xFFFFFFFF, (ULONG_PTR)TrapFrame->StISR, (ULONG_PTR)TrapFrame->StIIP, (ULONG_PTR)TrapFrame, 0 ); // Do not return from KeBugCheckEx } #endif // 0 ExceptionRecord->ExceptionCode = STATUS_REG_NAT_CONSUMPTION; break; case ISR_NAT_PAGE: // // If we start using a NaT page, we should treat this as a page fault and // should call KiMemoryFault(). // ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; break; default: if (TrapFrame->PreviousMode == KernelMode) { KeBugCheckEx(0xFFFFFFFF, (ULONG_PTR)TrapFrame->StISR, (ULONG_PTR)TrapFrame->StIIP, (ULONG_PTR)TrapFrame, 0 ); } break; } return TRUE; } BOOLEAN KiSingleStep ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for single step trap. An instruction was successfully executed and the PSR.ss bit is 1. Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: ISR.ei bits indicate which instruction caused the exception. ISR.code{3:0} = 1000 --*/ { PEXCEPTION_RECORD ExceptionRecord; ULONG IpsrRi; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; // // We only want the low order 2 bits so typecast to ULONG // IpsrRi = (ULONG)(TrapFrame->StIPSR >> PSR_RI) & 0x3; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, IpsrRi); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; // 0 for traps ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; ExceptionRecord->ExceptionCode = STATUS_SINGLE_STEP; return TRUE; } BOOLEAN KiFloatFault ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for EM floating point fault. Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: IIP contains address of bundle causing the fault. ISR.ei bits indicate which instruction caused the exception. ISR.code{7:0} = ISR.code{0} = 1: IEEE V (invalid) exception (Normal or SIMD-HI) ISR.code{1} = 1: Denormal/Unnormal operand exception (Normal or SIMD-HI) ISR.code{2} = 1: IEEE Z (divide by zero) exception (Normal or SIMD-HI) ISR.code{3} = 1: Software assist (Normal or SIMD-HI) ISR.code{4} = 1: IEEE V (invalid) exception (SIMD-LO) ISR.code{5} = 1: Denormal/Unnormal operand exception (SIMD-LO) ISR.code{6} = 1: IEEE Z (divide by zero) exception (SIMD-LO) ISR.code{7} = 1: Software assist (SIMD-LO) --*/ { PEXCEPTION_RECORD ExceptionRecord; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; ExceptionRecord->ExceptionCode = STATUS_FLOAT_MULTIPLE_FAULTS; return TRUE; } BOOLEAN KiFloatTrap ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for EM floating point trap. Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: IIP contains address of bundle with the instruction to be executed next. ISR.ei bits indicate which instruction caused the exception. The fp trap may occur simultaneously with single-step traps. The fp trap is reported by the hardware. The singel step trap must be detected by software. ISR.code{3:0} = ss 0 0 1 (ss = single step) ISR{15:7} = fp trap code. --*/ { PEXCEPTION_RECORD ExceptionRecord; ULONGLONG SavedISR = TrapFrame->StISR; // // Initialize the exception record // ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID) RtlIa64InsertIPSlotNumber(TrapFrame->StIIPA, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = 0; ExceptionRecord->ExceptionInformation[1] = 0; ExceptionRecord->ExceptionInformation[2] = 0; ExceptionRecord->ExceptionInformation[3] = TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = TrapFrame->StISR; ExceptionRecord->ExceptionCode = STATUS_FLOAT_MULTIPLE_TRAPS; // // check for single-step trap // if (SavedISR & (1i64 << ISR_SS_TRAP)) { return KiSingleStep(TrapFrame); } return TRUE; } #pragma warning( disable : 4715 ) // not all control paths return a value EXCEPTION_DISPOSITION KiSystemServiceHandler ( IN PEXCEPTION_RECORD ExceptionRecord, IN FRAME_POINTERS EstablisherFrame, IN OUT PCONTEXT ContextRecord, IN OUT PDISPATCHER_CONTEXT DispatcherContext ) /*++ Routine Description: Control reaches here when a exception is raised in a system service or the system service dispatcher, and for an unwind during a kernel exception. If an unwind is being performed and the system service dispatcher is the target of the unwind, then an exception occured while attempting to copy the user's in-memory argument list. Control is transfered to the system service exit by return a continue execution disposition value. If an unwind is being performed and the previous mode is user, then bug check is called to crash the system. It is not valid to unwind out of a system service into user mode. If an unwind is being performed, the previous mode is kernel, the system service dispatcher is not the target of the unwind, and the thread does not own any mutexes, then the previous mode field from the trap frame is restored to the thread object. Otherwise, bug check is called to crash the system. It is invalid to unwind out of a system service while owning a mutex. If an exception is being raised and the exception PC is within the range of the system service dispatcher in-memory argument copy code, then an unwind to the system service exit code is initiated. If an exception is being raised and the exception PC is not within the range of the system service dispatcher, and the previous mode is not user, then a continue searh disposition value is returned. Otherwise, a system service has failed to handle an exception and bug check is called. It is invalid for a system service not to handle all exceptions that can be raised in the service. Arguments: ExceptionRecord - Supplies a pointer to an exception record. EstablisherFrame - Supplies the frame pointer of the establisher of this exception handler. N.B. This is not actually the frame pointer of the establisher of this handler. It is actually the stack pointer of the caller of the system service. Therefore, the establisher frame pointer is not used and the address of the trap frame is determined by examining the saved s8 register in the context record. ContextRecord - Supplies a pointer to a context record. DispatcherContext - Supplies a pointer to the dispatcher context record. Return Value: If bug check is called, there is no return from this routine and the system is crashed. If an exception occured while attempting to copy the user in-memory argument list, then there is no return from this routine, and unwind is called. Otherwise, ExceptionContinueSearch is returned as the function value. --*/ { CONTEXT Context; PKTHREAD Thread; PKTRAP_FRAME TrapFrame; ULONG_PTR ExceptionAddress; extern ULONG KiSystemServiceStartOffset; extern ULONG KiSystemServiceEndOffset; extern ULONG KiSystemServiceExitOffset; if (IS_UNWINDING(ExceptionRecord->ExceptionFlags)) { // // An unwind is in progress. // If a target unwind is being performed, then continue execution // is returned to transfer control to the system service exit // code. Otherwise, restore the previous mode if the previous // mode is not user and there is no mutex owned by the current // thread. // if (ExceptionRecord->ExceptionFlags & EXCEPTION_TARGET_UNWIND) { return ExceptionContinueSearch; } else { Thread = KeGetCurrentThread(); if (Thread->PreviousMode == KernelMode) { // // Previous mode is kernel and no mutex owned. // // N.B. System convention: unwinder puts the trap frame // address in IntT0 field of // context record when it // encounters an interrupt region. // TrapFrame = (PKTRAP_FRAME) ContextRecord->IntT0; Thread->PreviousMode = (KPROCESSOR_MODE)TrapFrame->PreviousMode; return ExceptionContinueSearch; } else { // // Previous mode is user, call bug check. // KeBugCheck(SYSTEM_UNWIND_PREVIOUS_USER); } } } else { ULONG IsrCode; // // An exception dispatching is in progress. // If the exception PC is within the in-memory argument copy code // of the system service dispatcher, then call unwind to transfer // control to the system service exit code. Otherwise, check if // the previous mode is user or kernel mode. // ExceptionAddress = (ULONG_PTR)ExceptionRecord->ExceptionAddress; if ((ExceptionAddress < MM_EPC_VA+KiSystemServiceStartOffset) || (ExceptionAddress >= MM_EPC_VA+KiSystemServiceEndOffset)) { if (KeGetCurrentThread()->PreviousMode == UserMode) { // // Previous mode is user, call bug check. // KeBugCheck(SYSTEM_SERVICE_EXCEPTION); } else { // // Previous mode is kernel, continue to search // return ExceptionContinueSearch; } } else { IsrCode = (ULONG)((ExceptionRecord->ExceptionInformation[4] >> ISR_CODE) & ISR_CODE_MASK) >> 4; if ( (IsrCode == ISR_NAT_REG) || (IsrCode == ISR_NAT_PAGE) ) { DbgPrint("WARNING: Kernel hit a Nat Consumpation Fault\n"); DbgPrint("WARNING: At %p\n", ExceptionRecord->ExceptionAddress); } #pragma warning( disable : 4312 ) // disabling warning on PVOID casting for the ExceptionCode RtlUnwind2(EstablisherFrame, (PVOID)(MM_EPC_VA+KiSystemServiceExitOffset), NULL, (PVOID)ExceptionRecord->ExceptionCode, &Context); #pragma warning ( default: 4312 ) } } } // KiSystemServiceHandler( ) #pragma warning( default : 4715 ) BOOLEAN KiUnalignedFault ( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: Handler for unaligned data reference. Arguments: TrapFrame - Pointer to the trap frame. Return Value: None. Notes: ISR.ei bits indicate which instruction caused the exception. --*/ { PEXCEPTION_RECORD ExceptionRecord; PVOID VirtualAddress; VirtualAddress = (PVOID)TrapFrame->StIFA; ExceptionRecord = (PEXCEPTION_RECORD)&TrapFrame->ExceptionRecord; ExceptionRecord->ExceptionAddress = (PVOID)RtlIa64InsertIPSlotNumber(TrapFrame->StIIP, ((TrapFrame->StISR & ISR_EI_MASK) >> ISR_EI)); ExceptionRecord->ExceptionFlags = 0; ExceptionRecord->ExceptionRecord = (PEXCEPTION_RECORD)NULL; ExceptionRecord->NumberParameters = 5; ExceptionRecord->ExceptionInformation[0] = (ULONG_PTR)0; ExceptionRecord->ExceptionInformation[1] = (ULONG_PTR)VirtualAddress; ExceptionRecord->ExceptionInformation[2] = (ULONG_PTR)0; ExceptionRecord->ExceptionInformation[3] = (ULONG_PTR)TrapFrame->StIIPA; ExceptionRecord->ExceptionInformation[4] = (ULONG_PTR)TrapFrame->StISR; ExceptionRecord->ExceptionCode = STATUS_DATATYPE_MISALIGNMENT; return TRUE; } VOID KiAdvanceInstPointer( IN PKTRAP_FRAME TrapFrame ) /*++ Routine Description: This function is called to advance the instruction pointer in the trap frame. Arguments: TrapFrame - Supplies a pointer to a trap frame. Return Value: The intruction pointer in the trap frame has been advanced. --*/ { ULONGLONG PsrRi; PsrRi = ((TrapFrame->StIPSR >> PSR_RI) & 3i64) + 1; if (PsrRi == 3) { PsrRi = 0; TrapFrame->StIIP += 16; } TrapFrame->StIPSR &= ~(3i64 << PSR_RI); TrapFrame->StIPSR |= (PsrRi << PSR_RI); return; } #if 0 // obsolete; may be used for debug purposes typedef struct _CHECK_INST { union { struct { ULONGLONG qp: 6; ULONGLONG imm7: 7; ULONGLONG r2: 7; ULONGLONG imm13:13; ULONGLONG x3: 3; ULONGLONG s: 1; ULONGLONG Op: 4; ULONGLONG Rsv: 23; } i; ULONGLONG Ulong64; } u; } CHECK_INST; BOOLEAN KiEmulateSpeculationFault( IN PKTRAP_FRAME TrapFrame ) { PULONGLONG BundleAddress; ULONGLONG BundleLow; ULONGLONG BundleHigh; ULONG SlotNumber; CHECK_INST CheckInst; ISR Isr; ULONGLONG Imm24; BundleAddress = (PULONGLONG)TrapFrame->StIIP; try { BundleLow = *BundleAddress; BundleHigh = *(BundleAddress+1); } except (EXCEPTION_EXECUTE_HANDLER) { // // if an exception (memory fault) occurs, then let it re-execute chk.s again // return FALSE; } Isr.ull = TrapFrame->StISR; SlotNumber = (ULONG)Isr.sb.isr_ei; // // Align instruction // switch (SlotNumber) { case 0: CheckInst.u.Ulong64 = BundleLow >> 5; break; case 1: CheckInst.u.Ulong64 = (BundleLow >> 46) | (BundleHigh << 18); break; case 2: CheckInst.u.Ulong64 = (BundleHigh >> 23); break; } // // Extract immediate value // Imm24 = ((CheckInst.u.i.imm13 << 7)|(CheckInst.u.i.imm7)) << 4; if (CheckInst.u.i.s == 1) { Imm24 = 0xFFFFFFFFFF000000|Imm24; } TrapFrame->StIIP += Imm24; TrapFrame->StIPSR &= ~(3i64 << PSR_RI); return FALSE; } #endif // 0