Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1856 lines
67 KiB

title "Trap Processing"
;++
;
; Copyright (c) 2000 Microsoft Corporation
;
; Module Name:
;
; trap.asm
;
; Abstract:
;
; This module implements the code necessary to field and process AMD64
; trap conditions.
;
; Author:
;
; David N. Cutler (davec) 28-May-2000
;
; Environment:
;
; Kernel mode only.
;
;--
include ksamd64.inc
altentry KiExceptionExit
altentry KiSystemService
altentry KiSystemServiceCopyStart
altentry KiSystemServiceExit
altentry KiSystemServiceGdiTebAccess
extern ExpInterlockedPopEntrySListFault:byte
extern ExpInterlockedPopEntrySListResume:byte
extern KdpOweBreakpoint:byte
extern KdSetOwedBreakpoints:proc
extern KeBugCheckEx:proc
extern KeGdiFlushUserBatch:qword
extern KeServiceDescriptorTableShadow:qword
extern KiConvertToGuiThread:proc
extern KiDispatchException:proc
extern KiInitiateUserApc:proc
extern KiProcessNMI:proc
extern MmAccessFault:proc
extern MmUserProbeAddress:qword
extern RtlUnwind:proc
extern PsWatchEnabled:byte
extern PsWatchWorkingSet:proc
extern __imp_HalEndSystemInterrupt:qword
extern __imp_HalHandleMcheck:qword
subttl "Divide Error Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of an attempted division by zero
; or the result of an attempted division does not fit in the destination
; operand (i.e., the largest negative number divided by minus one).
;
; N.B. The two possible conditions that can cause this exception are not
; separated and the exception is reported as a divide by zero.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiDivideErrorFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_INTEGER_DIVIDE_BY_ZERO ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiDivideErrorFault, _TEXT$00
subttl "Debug Trap Or Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a debug trap or fault. The
; following conditions cause entry to this routine:
;
; 1. Instruction fetch breakpoint fault.
; 2. Data read or write breakpoint trap.
; 3. I/O read or write breakpoint trap.
; 4. General detect condition fault (in-circuit emulator).
; 5. Single step trap (TF set).
; 6. Task switch trap (not possible on this system).
; 7. Execution of an int 1 instruction.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiDebugTrapOrFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_SINGLE_STEP ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiDebugTrapOrFault, _TEXT$00
subttl "Nonmaskable Interrupt"
;++
;
; Routine Description:
;
; This routine is entered as the result of a nonmaskable interrupt. A
; switch to the panic stack occurs before the exception frame is pushed
; on the stack.
;
; N.B. This routine executes on the panic stack.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack and the NMI is
; processed. If a return to this routine occurs, then the NMI was handled.
;
;--
NESTED_ENTRY KiNmiInterrupt, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
call KxNmiInterrupt ; call secondary routine
RESTORE_TRAP_STATE <Volatile> ; restore trap state and exit
NESTED_END KiNmiInterrupt, _TEXT$00
;
; This routine generates an exception frame, then processes the NMI.
;
NESTED_ENTRY KxNmiInterrupt, _TEXT$00
GENERATE_EXCEPTION_FRAME ; generate exception frame
lea rcx, (-128)[rbp] ; set trap frame address
mov rdx, rsp ; set exception frame address
call KiProcessNMI ; process NMI
RESTORE_EXCEPTION_STATE ; restore exception state/deallocate
ret ; return
NESTED_END KxNmiInterrupt, _TEXT$00
subttl "Breakpoint Trap"
;++
;
; Routine Description:
;
; This routine is entered as the result of the execution of an int 3
; instruction.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiBreakpointTrap, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_BREAKPOINT ; set exception code
mov edx, 1 ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
dec r8 ;
mov r9d, BREAKPOINT_BREAK ; set parameter 1 value
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiBreakpointTrap, _TEXT$00
subttl "Overflow Trap"
;++
;
; Routine Description:
;
; This routine is entered as the result of the execution of an into
; instruction when the OF flag is set.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiOverflowTrap, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_INTEGER_OVERFLOW ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
dec r8 ;
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiOverflowTrap, _TEXT$00
subttl "Bound Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of the execution of a bound
; instruction and when the bound range is exceeded.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiBoundFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_ARRAY_BOUNDS_EXCEEDED ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiBoundFault, _TEXT$00
subttl "Invalid Opcode Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of the execution of an invalid
; instruction.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiInvalidOpcodeFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_ILLEGAL_INSTRUCTION ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiInvalidOpcodeFault, _TEXT$00
subttl "NPX Not Available Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of the numeric coprocessor not
; being available for one of the following conditions:
;
; 1. A floating point instruction was executed and EM is set in CR0 -
; this condition should never happen since EM will never be set.
;
; 2. A floating point instruction was executed and the TS flag is set
; in CR0 - this condition should never happen since TS will never
; be set.
;
; 3. A WAIT of FWAIT instruction was executed and the MP and TS flags
; are set in CR0 - this condition should never occur since neither
; TS nor MP will ever be set.
;
; N.B. The NPX state should always be available.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack and bug check
; is called.
;
;--
NESTED_ENTRY KiNpxNotAvailableFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9, cr4 ; set parameter 4 to control register 4
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 1 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiNpxNotAvailableFault, _TEXT$00
subttl "Double Fault Abort"
;++
;
; Routine Description:
;
; This routine is entered as the result of the generation of a second
; exception while another exception is being generated. A switch to the
; panic stack occurs before the exception frame is pushed on the stack.
;
; N.B. This routine executes on the panic stack.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the new stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack and bug check
; is called.
;
;--
NESTED_ENTRY KiDoubleFaultAbort, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9, cr4 ; set parameter 4 to control register 4
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 2 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiDoubleFaultAbort, _TEXT$00
subttl "NPX Segment Overrrun Abort"
;++
;
; Routine Description:
;
; This routine is entered as the result of a hardware failure since this
; vector is obsolete.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the new stack.
; There is no error code for this exception.
;
; Disposition:
;
; This trap should never occur and the system is shutdown via a call to
; bug check.
;
;--
NESTED_ENTRY KiNpxSegmentOverrunAbort, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9, cr4 ; set parameter 4 to control register 4
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 3 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiNpxSegmentOverrunAbort, _TEXT$00
subttl "Invalid TSS Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a hardware or software failure
; since there is no task switching in 64-bit mode and 32-bit code does not
; have any task state segments.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the new stack.
; The segment selector index for the segment descriptor that caused the
; violation is pushed as the error code.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack and bug check
; is called.
;
;--
NESTED_ENTRY KiInvalidTssFault, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9d, TrErrorCode[rbp] ; set parameter 4 to selector index
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 4 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiInvalidTssFault, _TEXT$00
subttl "Segment Not Present Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a segment not present (P bit 0)
; fault. This fault can only occur in legacy 32-bit code.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the new stack.
; The segment selector index for the segment descriptor that is not
; present is pushed as the error code.
;
; Disposition:
;
; A standard trap frame is constructed. If the previous mode is user,
; then the exception parameters are loaded into registers and the exception
; is dispatched via common code. Otherwise, bug check is called.
;
;--
NESTED_ENTRY KiSegmentNotPresentFault, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov r8, TrRip[rbp] ; get exception address
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user
jz short KiSN10 ; if z, previous mode not user
;
; The previous mode was user.
;
mov ecx, STATUS_ACCESS_VIOLATION ; set exception code
mov edx, 2 ; set number of parameters
mov r9d, TrErrorCode[rbp] ; set parameter 1 value
or r9d, RPL_MASK ;
and r9d, 0ffffh ;
xor r10, r10 ; set parameter 2 value
call KiExceptionDispatch ; dispatch exception - no return
;
; The previous mode was kernel.
;
KiSN10: mov r10, r8 ; set parameter 5 to exception address
mov r9d, TrErrorCode[rbp] ; set parameter 4 to selector index
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 5 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiSegmentNotPresentFault, _TEXT$00
subttl "Stack Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a stack fault. This fault can
; only occur in legacy 32-bit code.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the new stack.
; The segment selector index for the segment descriptor that caused the
; exception is pushed as the error code.
;
; Disposition:
;
; A standard trap frame is constructed. If the previous mode is user,
; then the exception parameters are loaded into registers and the exception
; is dispatched via common code. Otherwise, bug check is called.
;
;--
NESTED_ENTRY KiStackFault, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov r8, TrRip[rbp] ; get exception address
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user
jz short KiSF10 ; if z, previous mode not user
;
; The previous mode was user.
;
mov ecx, STATUS_ACCESS_VIOLATION ; set exception code
mov edx, 2 ; set number of parameters
mov r9d, TrErrorCode[rbp] ; set parameter 1 value
or r9d, RPL_MASK ;
and r9d, 0ffffh ;
xor r10, r10 ; set parameter 2 value
call KiExceptionDispatch ; dispatch exception - no return
;
; The previous mode was kernel.
;
KiSF10: mov r10, r8 ; set parameter 5 to exception address
mov r9d, TrErrorCode[rbp] ; set parameter 4 to selector index
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 6 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiStackFault, _TEXT$00
subttl "General Protection Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a general protection violation.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; The segment selector index for the segment descriptor that caused the
; exception, the IDT vector number for the descriptor that caused the
; exception, or zero is pushed as the error code.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiGeneralProtectionFault, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov ecx, STATUS_ACCESS_VIOLATION ; set exception code
mov edx, 2 ; set number of parameters
mov r9d, TrErrorCode[rbp] ; set parameter 1 to error code
and r9d, 0ffffh ;
xor r10, r10 ; set parameter 2 value
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiGeneralProtectionFault, _TEXT$00
subttl "Page Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of a page fault which can occur
; because of the following reasons:
;
; 1. The referenced page is not present.
;
; 2. The referenced page does not allow the requested access.
;
; Arguments:
;
; A standard exception frame is pushed by hardware on the kernel stack.
; A special format error code is pushed which specifies the cause of the
; page fault as not present, read/write access denied, from user/kernel
; mode, and attempting to set reserved bits.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack and memory
; management is called to resolve the page fault. If memory management
; successfully resolves the page fault, then working set information is
; recorded, owed breakpoints are inserted, and execution is continued.
; If memory management cannot resolve the page fault and the fault
; address is the pop SLIST code, then the execution of the pop SLIST
; code is continued at the resumption address. Otherwise, if the page
; fault occurred at an IRQL greater than APC_LEVEL, then the system is
; shut down via a call to bug check. Otherwise, an appropriate exception
; is raised.
;
;--
NESTED_ENTRY KiPageFault, _TEXT$00
GENERATE_TRAP_FRAME <Virtual> ; generate trap frame
;
; The registers eax and rcx are loaded with the error code and the virtual
; address of the fault respectively when the trap frame is generated.
;
shr eax, 1 ; isolate load/store and i/d indicators
and eax, 09h ;
;
; Save the load/store indicator and the faulting virtual address in the
; exception record in case an exception is raised.
;
mov TrFaultIndicator[rbp], al ; save load/store indicator
mov TrFaultAddress[rbp], rcx ; save fault address
lea r9, (-128)[rbp] ; set trap frame address
mov r8b, TrSegCs[rbp] ; isolate previous mode
and r8b, MODE_MASK ;
mov rdx, rcx ; set faulting virtual address
mov cl, al ; set load/store indicator
call MmAccessFault ; attempt to resolve page fault
test eax, eax ; test for successful completion
jl short KiPF20 ; if l, not successful completion
;
; If watch working set is enabled, then record working set information.
;
cmp PsWatchEnabled, 0 ; check if working set watch enabled
je short KiPF10 ; if e, working set watch not enabled
mov r8, TrFaultAddress[rbp] ; set fault address
mov rdx, TrRip[rbp] ; set exception address
mov ecx, eax ; set completion status
call PsWatchWorkingSet ; record working set information
;
; If the debugger has any breakpoints that should be inserted, then attempt
; to insert them now.
;
KiPF10: cmp KdpOweBreakPoint, 0 ; check if breakpoints are owed
je KiPF60 ; if e, no owed breakpoints
call KdSetOwedBreakpoints ; notify the debugger of new page
jmp KiPF60 ; finish in common code
;
; Check to determine if the page fault occurred in the interlocked pop entry
; SLIST code. There is a case where a page fault may occur in this code when
; the right set of circumstances present themselves. The page fault can be
; ignored by simply restarting the instruction sequence.
;
KiPF20: lea rcx, ExpInterlockedPopEntrySListFault ; get fault address
cmp rcx, TrRip[rbp] ; check if address matches
je KiPF50 ; if e, address match
;
; Memory management failed to resolve the fault.
;
; STATUS_IN_PAGE_ERROR | 0x10000000 is a special status that indicates a
; page fault at IRQL greater than APC level. This status causes a
; bugcheck.
;
; The following status values can be raised:
;
; STATUS_ACCESS_VIOLATION
; STATUS_GUARD_PAGE_VIOLATION
; STATUS_STACK_OVERFLOW
;
; All other status values are sconverted to:
;
; STATUS_IN_PAGE_ERROR
;
mov ecx, eax ; set status code
mov edx, 2 ; set number of parameters
cmp ecx, STATUS_IN_PAGE_ERROR or 10000000h ; check for bugcheck code
je short KiPF40 ; if e, bugcheck code returned
cmp ecx, STATUS_ACCESS_VIOLATION ; check for status values
je short KiPF30 ; if e, raise exception with code
cmp ecx, STATUS_GUARD_PAGE_VIOLATION ; check for status code
je short KiPF30 ; if e, raise exception with code
cmp ecx, STATUS_STACK_OVERFLOW ; check for status code
je short KiPF30 ; if e, raise exception with code
mov ecx, STATUS_IN_PAGE_ERROR ; convert all other status codes
mov edx, 3 ; set number of parameters
mov r11d, eax ; set parameter 3 to real status value
;
; Set virtual address, load/store and i/d indicators, exception address, and
; dispatch the exception.
;
KiPF30: mov r10, TrFaultAddress[rbp] ; set fault address
movzx r9, byte ptr TrFaultIndicator[rbp] ; set load/store indicator
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
;
; A page fault occurred at an IRQL that was greater than APC_LEVEL. Set bug
; check parameters and join common code.
;
KiPF40: CurrentIrql ; get current IRQL
mov r10, TrRip[rbp] ; set parameter 5 to exception address
movzx r9, byte ptr TrFaultIndicator[rbp] ; set load/store indicator
and eax, 0ffh ; isolate current IRQL
mov r8, rax ;
mov rdx, TrFaultAddress[rbp] ; set fault address
mov ecx, IRQL_NOT_LESS_OR_EQUAL ; set bug check code
call KiBugCheckDispatch ; bug check system - no return
;
; An unresolved page fault occurred in the pop SLIST code at the resumable
; fault address.
;
KiPF50: lea rax, ExpInterlockedPopEntrySListResume ; get resume address
mov TrRip[rbp], rax ; set resume address
;
; Test if a user APC should be delivered and exit exception.
;
KiPF60: RESTORE_TRAP_STATE <Volatile> ; restore trap state and exit
NESTED_END KiPageFault, _TEXT$00
subttl "Legacy Floating Error"
;++
;
; Routine Description:
;
; This routine is entered as the result of a legacy floating point fault.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack. If the previous
; mode is user, then reason for the exception is determine, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code. Otherwise, bug check is called.
;
;--
NESTED_ENTRY KiFloatingErrorFault, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov edx, 7 ; set unexpected trap number
test byte ptr TrSegCs[rbp], MODE_MASK ; check if previous mode user
jz KiFE40 ; if z, previous mode not user
;
; The previous mode was user mode.
;
fnstcw TrErrorCode[rbp] ; store floating control word
fnstsw ax ; store floating status word
mov cx, TrErrorCode[rbp] ; get control word
and cx, FSW_ERROR_MASK ; isolate masked exceptions
not cx ; compute enabled exceptions
and ax, cx ; isolate exceptions
mov ecx, STATUS_FLOAT_INVALID_OPERATION ; set exception code
xor r9, r9 ; set first exception parameter
mov edx, 1 ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
test al, FSW_INVALID_OPERATION ; test for invalid operation
jz short KiFE10 ; if z, non invalid operation
test al, FSW_STACK_FAULT ; test is caused by stack fault
jz short KiFE20 ; if z, not caused by stack fault
mov ecx, STATUS_FLOAT_STACK_CHECK ; set exception code
jmp short KiFE20 ; finish in common code
KiFE10: mov ecx, STATUS_FLOAT_DIVIDE_BY_ZERO ; set exception code
test al, FSW_ZERO_DIVIDE ; test for divide by zero
jnz short KiFE20 ; if nz, divide by zero
mov ecx, STATUS_FLOAT_INVALID_OPERATION ; set exception code
test al, FSW_DENORMAL ; test if denormal operand
jnz short KiFE20 ; if nz, denormal operand
mov ecx, STATUS_FLOAT_OVERFLOW ; set exception code
test al, FSW_OVERFLOW ; test if overflow
jnz short KiFE20 ; if nz, overflow
mov ecx, STATUS_FLOAT_UNDERFLOW ; set exception code
test al, FSW_UNDERFLOW ; test if underflow
jnz short KiFE20 ; if nz, underflow
mov ecx, STATUS_FLOAT_INEXACT_RESULT ; set exception code
test al, FSW_PRECISION ; test for inexact result
jz short KiFE30 ; if z, not inexact result
KiFE20: call KiExceptionDispatch ; dispatch exception - no return
;
; The previous mode was kernel mode or the cause of the exception is unknown.
;
KiFE30: mov edx, 8 ; set unexpected trap number
KiFE40: mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9, cr4 ; set parameter 4 to control register 4
mov r8, cr0 ; set parameter 3 to control register 0
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiFloatingErrorFault, _TEXT$00
subttl "Alignment Fault"
;++
;
; Routine Description:
;
; This routine is entered as the result of an attempted access to unaligned
; data.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; An error error code of zero is pushed on the stack.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiAlignmentFault, _TEXT$00
GENERATE_TRAP_FRAME <ErrorCode> ; generate trap frame
mov ecx, STATUS_DATATYPE_MISALIGNMENT ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiAlignmentFault, _TEXT$00
subttl "Machine Check Abort"
;++
;
; Routine Description:
;
; This routine is entered as the result of a machine check. A switch to
; the machine check stack occurs before the exception frame is pushed on
; the stack.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap and exception frame are constructed on the kernel stack
; and the HAL is called to determine if the machine check abort is fatal.
; If the HAL call returns, then system operation is continued.
;
;--
NESTED_ENTRY KiMcheckAbort, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
;
; Check to determine if a recursive machine check has occurred. This can
; happen when machine check in progress is cleared and another machine
; check exception occurs before a complete exit from the below code can
; be performed.
;
lea rax, KTRAP_FRAME_LENGTH[rsp] ; get base stack address
cmp rax, TrRsp[rbp] ; check if with range
jbe short KiMC10 ; if be, old stack above base
sub rax, KERNEL_MCA_EXCEPTION_STACK_SIZE ; compute limit stack address
cmp rax, TrRsp[rbp] ; check if with range
jbe KiMC20 ; if be, old stack in range
KiMC10: call KxMcheckAbort ; call secondary routine
;
; Clear machine check in progress.
;
; N.B. This is done very late to ensure that the window whereby a recursive
; machine can occur is as small as possible. A recursive machine check
; reloads the machine stack pointer from the TSS and overwrites any
; information previously on the stack.
;
xor eax, eax ; clear machine check in progress
xor edx, edx ;
mov ecx, MSR_MCG_STATUS ;
wrmsr ;
RESTORE_TRAP_STATE <Volatile> ; restore trap state and exit
;
; A recursive machine check exception has occurred.
;
;
KiMC20: xor r10,r10 ; clear bugcheck parameters
xor r9, r9 ;
xor r8, r8 ;
xor edx, edx ;
mov ecx, RECURSIVE_MACHINE_CHECK ; set bug check code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiMcheckAbort, _TEXT$00
;
; This routine generates an exception frame, then calls the HAL to process
; the machine check.
;
NESTED_ENTRY KxMcheckAbort, _TEXT$00
GENERATE_EXCEPTION_FRAME ; generate exception frame
lea rcx, (-128)[rbp] ; set trap frame address
mov rdx, rsp ; set exception frame address
call __imp_HalHandleMcheck ; give HAL a chance to handle mcheck
RESTORE_EXCEPTION_STATE ; restore exception state/deallocate
ret ; return
NESTED_END KxMcheckAbort, _TEXT$00
subttl "XMM Floating Error"
;++
;
; Routine Description:
;
; This routine is entered as the result of a XMM floating point fault.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, mode is user,
; then reason for the exception is determine, the exception parameters are
; loaded into registers, and the exception is dispatched via common code.
; If no reason can be determined for the exception, then bug check is called.
;
;--
NESTED_ENTRY KiXmmException, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ax, TrMxCsr[rbp] ; get saved MXCSR
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user
jnz short KiXE05 ; if nz, previous mode user
stmxcsr TrErrorCode[rbp] ; get floating control/status word
mov ax, TrErrorCode[rbp] ; for kernel mode
KiXE05: mov cx, ax ; shift enables into position
shr cx, XSW_ERROR_SHIFT ;
and cx, XSW_ERROR_MASK ; isolate masked exceptions
not cx ; compute enabled exceptions
movzx r10d, ax ; set second exception parameter
and ax, cx ; isolate exceptions
mov edx, 2 ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
xor r9, r9 ; set first exception parameter
cmp word ptr TrSegCs[rbp], KGDT64_R3_CMCODE or RPL_MASK ; legacy code?
je short KiXE15 ; if e, legacy code
;
; The XMM exception occurred in 64-bit code.
;
mov ecx, STATUS_FLOAT_INVALID_OPERATION ; set exception code
test al, XSW_INVALID_OPERATION ; test for invalid operation
jnz short KiXE10 ; if z, invalid operation
mov ecx, STATUS_FLOAT_DIVIDE_BY_ZERO ; set exception code
test al, XSW_ZERO_DIVIDE ; test for divide by zero
jnz short KiXE10 ; if nz, divide by zero
mov ecx, STATUS_FLOAT_INVALID_OPERATION ; set exception code
test al, XSW_DENORMAL ; test if denormal operand
jnz short KiXE10 ; if nz, denormal operand
mov ecx, STATUS_FLOAT_OVERFLOW ; set exception code
test al, XSW_OVERFLOW ; test if overflow
jnz short KiXE10 ; if nz, overflow
mov ecx, STATUS_FLOAT_UNDERFLOW ; set exception code
test al, XSW_UNDERFLOW ; test if underflow
jnz short KiXE10 ; if nz, underflow
mov ecx, STATUS_FLOAT_INEXACT_RESULT ; set exception code
test al, XSW_PRECISION ; test for inexact result
jz short KiXE20 ; if z, not inexact result
KiXE10: call KiExceptionDispatch ; dispatch exception - no return
;
; The XMM exception occurred in legacy 32-bit code
;
KiXE15: mov ecx, STATUS_FLOAT_MULTIPLE_TRAPS ; set exception code
test al, XSW_INVALID_OPERATION ; test for invalid operation
jnz short KiXE10 ; if z, invalid operation
test al, XSW_ZERO_DIVIDE ; test for divide by zero
jnz short KiXE10 ; if nz, divide by zero
test al, XSW_DENORMAL ; test if denormal operand
jnz short KiXE10 ; if nz, denormal operand
mov ecx, STATUS_FLOAT_MULTIPLE_FAULTS ; set exception code
test al, XSW_OVERFLOW ; test if overflow
jnz short KiXE10 ; if nz, overflow
test al, XSW_UNDERFLOW ; test if underflow
jnz short KiXE10 ; if nz, underflow
test al, XSW_PRECISION ; test for inexact result
jnz short KiXE10 ; if nz, inexact result
;
; The cause of the exception is unknown.
;
KiXE20: mov r10, TrRip[rbp] ; set parameter 5 to exception address
mov r9, cr4 ; set parameter 4 to control register 4
mov r8, cr0 ; set parameter 3 to control register 0
mov edx, 9 ; set unexpected trap number
mov ecx, UNEXPECTED_KERNEL_MODE_TRAP ; set bugcheck code
call KiBugCheckDispatch ; bug check system - no return
nop ; fill - do not remove
NESTED_END KiXmmException, _TEXT$00
subttl "Debug Service Trap"
;++
;
; Routine Description:
;
; This routine is entered as the result of the execution of an int 2d
; instruction.
;
; Arguments:
;
; The standard exception frame is pushed by hardware on the kernel stack.
; There is no error code for this exception.
;
; Disposition:
;
; A standard trap frame is constructed on the kernel stack, the exception
; arguments are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiDebugServiceTrap, _TEXT$00
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_BREAKPOINT ; set exception code
mov edx, 1 ; set number of parameters
mov r9, TrRax[rbp] ; set parameter 1 value
mov r8, TrRip[rbp] ; set exception address
inc qword ptr TrRip[rbp] ; point past int 3 instruction
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiDebugServiceTrap, _TEXT$00
subttl "System Service Call 32-bit"
;++
;
; Routine Description:
;
; This routine gains control when a system call instruction is executed
; from 32-bit mode. System service calls from 32-bit code are not supported
; and this exception is turned into an invalid opcode fault.
;
; N.B. This routine is never entered from kernel mode and it executed with
; interrupts disabled.
;
; Arguments:
;
; The standard exception frame is pushed on the stack.
;
; Return Value:
;
; A standard trap frame is constructed on the kernel stack, the exception
; parameters are loaded into registers, and the exception is dispatched via
; common code.
;
;--
NESTED_ENTRY KiSystemCall32, _TEXT$00
swapgs ; swap GS base to kernel PCR
mov r8, gs:[PcTss] ; get address of task state segment
mov r9, rsp ; save user stack pointer
mov rsp, TssRsp0[r8] ; set kernel stack pointer
pushq KGDT64_R3_DATA or RPL_MASK ; push dummy SS selector
push r9 ; push user stack pointer
pushq r11 ; push previous EFLAGS
pushq KGDT64_R3_CODE or RPL_MASK ; push dummy 64-bit CS selector
pushq rcx ; push return address
GENERATE_TRAP_FRAME ; generate trap frame
mov ecx, STATUS_ILLEGAL_INSTRUCTION ; set exception code
xor edx, edx ; set number of parameters
mov r8, TrRip[rbp] ; set exception address
call KiExceptionDispatch ; dispatch exception - no return
nop ; fill - do not remove
NESTED_END KiSystemCall32, _TEXT$00
subttl "System Service Exception Handler"
;++
;
; EXCEPTION_DISPOSITION
; KiSystemServiceHandler (
; IN PEXCEPTION_RECORD ExceptionRecord,
; IN PVOID EstablisherFrame,
; IN OUT PCONTEXT ContextRecord,
; IN OUT PDISPATCHER_CONTEXT DispatcherContext
; )
;
; Routine Description:
;
; This routine is the exception handler for the system service dispatcher.
;
; 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 and the previous mode is kernel, then
; the previous mode field from the trap frame is restored to the thread
; object.
;
; If an exception is being raised and the exception PC is the address
; 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 search 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 (rcx) - Supplies a pointer to an exception record.
;
; EstablisherFrame (rdx) - Supplies the frame pointer of the establisher
; of this exception handler.
;
; ContextRecord (r8) - Supplies a pointer to a context record.
;
; DispatcherContext (r9) - 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.
;
;--
ShFrame struct
P1Home dq ? ; parameter home addresses
P2Home dq ? ;
P3Home dq ? ;
P4Home dq ? ;
P5Home dq ? ;
ShFrame ends
NESTED_ENTRY KiSystemServiceHandler, _TEXT$00
alloc_stack (sizeof ShFrame) ; allocate stack frame
END_PROLOGUE
test dword ptr ErExceptionFlags[rcx], EXCEPTION_UNWIND ; test for unwind
jnz short KiSH30 ; if nz, unwind in progress
;
; An exception is in progress.
;
; If the exception PC is the address of the GDI TEB access, then call unwind
; to transfer control to the system service exit code. Otherwise, check if
; the exception PC is the address of the in memory argument copy code for
; the system service dispatcher. If the exception PC is within the range of
; the in memory copy code, then call unwind to transfer control to the
; system service exit code. Otherwise, check if the previous mode is user
; or kernel mode.
;
lea rax, KiSystemServiceGdiTebAccess ; get GDI TEB access address
cmp rax, ErExceptionAddress[rcx] ; check if address match
je short KiSH05 ; if e, address match
lea rax, KiSystemServiceCopyStart ; get copy code start address
cmp rax, ErExceptionAddress[rcx] ; check if address match
jne short KiSH10 ; if ne, address mismatch
;
; The exception was raised by the system service dispatcher GDI TEB access
; code or the argument copy code. Unwind to the system service exit with the
; exception status code as the return value.
;
KiSH05: mov r9d, ErExceptionCode[rcx] ; set return value
xor r8, r8 ; set exception record address
mov rcx, rdx ; set target frame address
lea rdx, KiSystemServiceExit ; set target IP address
call RtlUnwind ; unwind - no return
;
; If the previous mode was kernel mode, then the continue the search for an
; exception handler. Otherwise, bug check the system.
;
KiSH10: mov rax, gs:[PcCurrentThread] ; get current thread address
cmp byte ptr ThPreviousMode[rax], KernelMode ; check for kernel mode
je short KiSH20 ; if e, previous mode kernel
;
; Previous mode is user mode - bug check the system.
;
xor r10, r10 ; zero parameter 5
mov r9, r8 ; set context record address
mov r8, ErExceptionAddress[rcx] ; set exception address
mov edx, ErExceptionCode[rcx] ; set exception code
mov ecx, SYSTEM_SERVICE_EXCEPTION ; set bug check code
call KiBugCheckDispatch ; bug check system - no return
;
; Previous mode is kernel mode - continue search for a handler.
;
KiSH20: mov eax, ExceptionContinueSearch ; set return value
add rsp, sizeof ShFrame ; deallocate stack frame
ret ; return
;
; An unwind is in progress.
;
; If a target unwind is being performed, then continue the unwind operation.
; Otherwise, check if the previous mode is user or kernel mode.
;
KiSH30: test dword ptr ErExceptionFlags[rcx], EXCEPTION_TARGET_UNWIND ; test for target unwind
jnz short KiSH20 ; if nz, target unwind in progress
;
; If the previous mode was kernel mode, then restore the previous mode and
; continue the unwind operation. Otherwise, bug check the system.
;
mov rax, gs:[PcCurrentThread] ; get current thread address
cmp byte ptr ThPreviousMode[rax], KernelMode ; check for kernel mode
je short KiSH40 ; if e, previous mode kernel
;
; Previous mode was user mode - bug check the system.
;
mov ecx, SYSTEM_UNWIND_PREVIOUS_USER ; set bug check code
call KiBugCheckDispatch ; bug check system - no return
;
; Previous mode is kernel mode - restore previous mode and continue unwind
; operation.
;
KiSH40: mov rcx, ThTrapFrame[rax] ; get current frame pointer address
mov cl, TrPreviousMode[rcx] ; get previous mode
mov ThPreviousMode[rax], cl ; restore previous mode
jmp short KiSH20 ; finish in common code
NESTED_END KiSystemServiceHandler, _TEXT$00
subttl "System Service Call 64-bit"
;++
;
; Routine Description:
;
; This routine gains control when a system call instruction is executed
; from 64-bit mode. The specified system service is executed by locating
; its routine address in system service dispatch table and calling the
; specified function.
;
; N.B. This routine is never entered from kernel mode and it executed with
; interrupts disabled.
;
; Arguments:
;
; eax - Supplies the system service number.
;
; Return Value:
;
; eax - System service status code.
;
; r10, rdx, r8, and r9 - Supply the first four system call arguments.
;
; rcx - Supplies the RIP of the system call.
;
; r11 - Supplies the previous EFLAGS.
;
;--
NESTED_ENTRY KiSystemCall64, _TEXT$00, KiSystemServiceHandler
swapgs ; swap GS base to kernel PCR
mov gs:[PcSavedRcx], rcx ; save return address
mov gs:[PcSavedR11], r11 ; save previous EFLAGS
mov rcx, gs:[PcTss] ; get address of task state segment
mov r11, rsp ; save user stack pointer
mov rsp, TssRsp0[rcx] ; set kernel stack pointer
pushq KGDT64_R3_DATA or RPL_MASK ; push dummy SS selector
push r11 ; push user stack pointer
pushq gs:[PcSavedR11] ; push previous EFLAGS
pushq KGDT64_R3_CODE or RPL_MASK ; push dummy 64-bit CS selector
pushq gs:[PcSavedRcx] ; push return address
mov rcx, r10 ; set first argument value
;
; Generate a trap frame without saving any of the volatile registers, i.e.,
; they are assumed to be destroyed as per the AMD64 calling standard.
;
; N.B. RBX, RDI, and RSI are also saved in this trap frame.
;
ALTERNATE_ENTRY KiSystemService
push_frame ; mark machine frame
alloc_stack 8 ; allocate dummy error code
push_reg rbp ; save standard register
push_reg rsi ; save extra registers
push_reg rdi ;
push_reg rbx ;
alloc_stack (KTRAP_FRAME_LENGTH - (10 * 8)) ; allocate fixed frame
set_frame rbp, 128 ; set frame pointer
END_PROLOGUE
SAVE_TRAP_STATE <Service> ; save trap state
sti ; enable interrupts
mov rbx, gs:[PcCurrentThread] ; get current thread address
mov r10b, TrSegCs[rbp] ; ioslate system call previous mode
and r10b, MODE_MASK ;
mov r11b, ThPreviousMode[rbx] ; save previous mode in trap frame
mov TrPreviousMode[rbp], r11b ;
mov ThPreviousMode[rbx], r10b ; set thread previous mode
mov r10, ThTrapFrame[rbx] ; save previous frame pointer address
mov TrTrapFrame[rbp], r10 ;
;
; Dispatch system service.
;
; eax - Supplies the system service number.
; rbx - Supplies the current thread address.
; rcx - Supplies the first argument if present.
; rdx - Supplies the second argument if present.
; r8 - Supplies the third argument if present.
; r9 - Supplies the fourth argument if present.
;
ALTERNATE_ENTRY KiSystemServiceRepeat
mov ThTrapFrame[rbx], rsp ; set current frame pointer address
mov edi, eax ; copy system service number
shr edi, SERVICE_TABLE_SHIFT ; isolate service table number
and edi, SERVICE_TABLE_MASK ;
mov esi, edi ; save service table number
add rdi, ThServiceTable[rbx] ; compute service descriptor address
mov r10d, eax ; save system service number
and eax, SERVICE_NUMBER_MASK ; isolate service table offset
;
; If the specified system service number is not within range, then attempt
; to convert the thread to a GUI thread and retry the service dispatch.
;
cmp eax, SdLimit[rdi] ; check if valid service
jae KiSS50 ;if ae, not valid service
;
; If the service is a GUI service and the GDI user batch queue is not empty,
; then call the appropriate service to flush the user batch.
;
cmp esi, SERVICE_TABLE_TEST ; check if GUI service
jne short KiSS10 ; if ne, not GUI service
mov r10, ThTeb[rbx] ; get user TEB adresss
ALTERNATE_ENTRY KiSystemServiceGdiTebAccess
cmp dword ptr TeGdiBatchCount[r10], 0 ; check batch queue depth
je short KiSS10 ; if e, batch queue empty
mov TrRax[rbp], eax ; save system service table offset
mov TrP1Home[rbp], rcx ; save system service arguments
mov TrP2Home[rbp], rdx ;
mov TrP3Home[rbp], r8 ;
mov TrP4Home[rbp], r9 ;
call KeGdiFlushUserBatch ; call flush GDI user batch routine
mov eax, TrRax[rbp] ; restore system service table offset
mov rcx, TrP1Home[rbp] ; restore system service arguments
mov rdx, TrP2Home[rbp] ;
mov r8, TrP3Home[rbp] ;
mov r9, TrP4Home[rbp] ;
;
; Check if system service has any in memory arguments.
;
KiSS10: mov r10, SdBase[rdi] ; get service table base address
mov r10, [r10][rax * 8] ; get system service routine address
btr r10, 0 ; check if any in memory arguments
jnc short KiSS30 ; if nc, no in memory arguments
mov TrP1Home[rbp], rcx ; save first argument if present
mov rdi, SdNumber[rdi] ; get argument table address
movzx ecx, byte ptr [rdi][rax] ; get number of in memory bytes
sub rsp, rcx ; allocate stack argument area
and spl, 0f0h ; align stack on 0 mod 16 boundary
mov rdi, rsp ; set copy destination address
mov rsi, TrRsp[rbp] ; get previous stack address
add rsi, 5 * 8 ; compute copy source address
test byte ptr TrSegCs[rbp], MODE_MASK ; check if previous mode user
jz short KiSS20 ; if z, previous mode kernel
cmp rsi, MmUserProbeAddress ; check if source address in range
cmovae rsi, MmUserProbeAddress ; if ae, reset copy source address
KiSS20: shr ecx, 3 ; compute number of quadwords
ALTERNATE_ENTRY KiSystemServiceCopyStart
rep movsq ; move arguments to kernel stack
sub rsp, 4 * 8 ; allocate argument home area
mov rcx, TrP1Home[rbp] ; restore first argument if present
;
; Call system service.
;
KiSS30: call r10 ; call system service
inc dword ptr gs:[PcSystemCalls] ; increment number of system calls
;
; System service exit.
;
; eax - Supplies the system service status.
;
; rbp - Supplies the address of the trap frame.
;
ALTERNATE_ENTRY KiSystemServiceExit
mov rcx, gs:[PcCurrentThread] ; get current thread address
mov rdx, TrTrapFrame[rbp] ; restore frame pointer address
mov ThTrapFrame[rcx], rdx ;
mov dl, TrPreviousMode[rbp] ; restore previous mode
mov ThPreviousMode[rbx], dl ;
mov rbx, TrRbx[rbp] ; restore extra registers
mov rdi, TrRdi[rbp] ;
mov rsi, TrRsi[rbp] ;
;
; Test if a user APC should be delivered and exit system service.
;
test byte ptr TrSegCs[rbp], MODE_MASK ; test if previous mode user
jz KiSS40 ; if z, previous mode not user
RESTORE_TRAP_STATE <Service> ; restore trap state/exit to user mode
KiSS40: RESTORE_TRAP_STATE <Kernel> ; restore trap state/exit to kernel mode
;
; The specified system service number is not within range. Attempt to convert
; the thread to a GUI thread if the specified system service is a GUI service
; and the thread has not already been converted to a GUI thread.
;
KiSS50: cmp esi, SERVICE_TABLE_TEST ; check if GUI service
jne short KiSS60 ; if ne, not GUI service
mov TrRax[rbp], r10d ; save system service number
mov TrP1Home[rbp], rcx ; save system service arguments
mov TrP2Home[rbp], rdx ;
mov TrP3Home[rbp], r8 ;
mov TrP4Home[rbp], r9 ;
call KiConvertToGuiThread ; attempt to convert to GUI thread
or eax, eax ; check if service was successful
mov eax, TrRax[rbp] ; restore system service number
mov rcx, TrP1Home[rbp] ; restore system service arguments
mov rdx, TrP2Home[rbp] ;
mov r8, TrP3Home[rbp] ;
mov r9, TrP4Home[rbp] ;
jz KiSystemServiceRepeat ; if z, successful conversion to GUI
;
; The conversion to a GUI thread failed. The correct return value is encoded
; in a byte table indexed by the service number that is at the end of the
; service address table. The encoding is as follows:
;
; 0 - return 0.
; -1 - return -1.
; 1 - return status code.
;
lea rdi, KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST ;
mov esi, SdLimit[rdi] ; get service table limit
mov rdi, SdBase[rdi] ; get service table base
lea rdi, [rdi][rsi * 8] ; get ending service table address
and eax, SERVICE_NUMBER_MASK ; isolate service number
movsx eax, byte ptr [rdi][rax] ; get status byte value
or eax, eax ; check for 0 or - 1
jle KiSystemServiceExit ; if le, return status byte value
KiSS60: mov eax, STATUS_INVALID_SYSTEM_SERVICE ; set return status
jmp KiSystemServiceExit ; finish in common code
NESTED_END KiSystemCall64, _TEXT$00
subttl "Common Bug Check Dispatch"
;++
;
; Routine Description:
;
; This routine allocates an exception frame on stack, saves nonvolatile
; machine state, and calls the system bug check code.
;
; N.B. It is the responsibility of the caller to initialize the exception
; record.
;
; Arguments:
;
; ecx - Supplies the bug check code.
;
; rdx to r10 - Supplies the bug check parameters.
;
; Return Value:
;
; There is no return from this function.
;
;--
NESTED_ENTRY KiBugCheckDispatch, _TEXT$00
GENERATE_EXCEPTION_FRAME ; generate exception frame
mov ExP5[rsp], r10 ; save parameter 5
call KeBugCheckEx ; bugcheck system - not return
nop ; fill - do not remove
NESTED_END KiBugCheckDispatch, _TEXT$00
subttl "Common Exception Dispatch"
;++
;
; Routine Description:
;
; This routine allocates an exception frame on stack, saves nonvolatile
; machine state, and calls the system exception dispatcher.
;
; N.B. It is the responsibility of the caller to initialize the exception
; record.
;
; Arguments:
;
; ecx - Supplies the exception code.
;
; edx - Supplies the number of parameters.
;
; r8 - Supplies the exception address.
;
; r9 - r11 - Supply the exception parameters.
;
; rbp - Supplies a pointer to the trap frame.
;
; rsp - Supplies a pointer to the trap frame.
;
; Return Value:
;
; There is no return from this function.
;
;--
NESTED_ENTRY KiExceptionDispatch, _TEXT$00
GENERATE_EXCEPTION_FRAME ; generate exception frame
lea rax, ExExceptionRecord[rsp] ; get exception record address
mov ErExceptionCode[rax], ecx ; set exception code
xor ecx, ecx ;
mov dword ptr ErExceptionFlags[rax], ecx ; clear exception flags
mov ErExceptionRecord[rax], rcx ; clear exception record address
mov ErExceptionAddress[rax], r8 ; set exception address
mov ErNumberParameters[rax], edx ; set number of parameters
mov ErExceptionInformation[rax], r9 ; set exception parameters
mov ErExceptionInformation + 8[rax], r10 ;
mov ErExceptionInformation + 16[rax], r11 ;
mov r9b, TrSegCs[rbp] ; isolate previous mode
and r9b, MODE_MASK ;
jz short KiEE10 ; if z, previous mode not user
mov rbx, gs:[PcCurrentThread] ; get current thread address
cmp byte ptr ThNpxState[rbx], LEGACY_STATE_SWITCH ; check if switched
jne short KiEE10 ; if ne, legacy state not switched
;
; N.B. The legacy floating point state must be saved and restored since saving
; the state initializes some of the state.
;
; N.B. Interrupts must also be disabled during this sequence to ensure that a
; get context APC interrupt does not occur.
;
lea rsi, (KTRAP_FRAME_LENGTH - 128)[rbp] ; get legacy save address
cli ; disable interrupts
fnsaved [rsi] ; save legacy floating state
mov di, LfControlWord[rsi] ; save current control word
mov word ptr LfControlWord[rsi], 03fh ; set to mask all exceptions
frstord [rsi] ; restore legacy floating point state
mov LfControlWord[rsi], di ; restore control word
fldcw word ptr LfControlWord[rsi] ; load legacy control word
sti ; enable interrupts
KiEE10: mov byte ptr ExP5[rsp], TRUE ; set first chance parameter
lea r8, (-128)[rbp] ; set trap frame address
mov rdx, rsp ; set exception frame address
mov rcx, rax ; set exception record address
call KiDispatchException ; dispatch exception
subttl "Common Exception Exit"
;++
;
; Routine Description:
;
; This routine is called to exit an exception.
;
; N.B. This transfer of control occurs from:
;
; 1. a fall through from above.
; 2. the exit from a continue system service.
; 3. the exit form a raise exception system service.
; 4. the exit into user mode from thread startup.
;
; N.B. Control is transfered to this code via a jump.
;
; Arguments:
;
; rbp - Supplies the address of the trap frame.
;
; rsp - Supplies the address of the exception frame.
;
; Return Value:
;
; Function does not return.
;
;--
ALTERNATE_ENTRY KiExceptionExit
RESTORE_EXCEPTION_STATE <NoPop> ; restore exception state/deallocate
RESTORE_TRAP_STATE <Volatile> ; restore trap state and exit
NESTED_END KiExceptionDispatch, _TEXT$00
subttl "Check for Allowable Invalid Address"
;++
;
; BOOLEAN
; KeInvalidAccessAllowed (
; IN PVOID TrapFrame
; )
;
; Routine Description:
;
; This function checks to determine if the fault address in the specified
; trap frame is an allowed fault address. Currently there is only one such
; address and it is the pop SLIST fault address.
;
; Arguments:
;
; TrapFrame (rcx) - Supplies a pointer to a trap frame.
;
; Return value:
;
; If the fault address is allowed, then TRUE is returned. Otherwise, FALSE
; is returned.
;
;--
LEAF_ENTRY KeInvalidAccessAllowed, _TEXT$00
lea rdx, ExpInterlockedPopEntrySListFault ; get fault address
cmp rdx, TrRip + 128[rcx] ; check if address match
sete al ; set return value
ret ; return
LEAF_END KeInvalidAccessAllowed, _TEXT$00
subttl "System Service Linkage"
;++
;
; VOID
; KiServiceLinkage (
; VOID
; )
;
; Routine Description:
;
; This is a dummay function that only exists to make trace back through
; a kernel mode to kernel mode system call work.
; Arguments:
;
; None.
;
; Return value:
;
; None.
;
;--
LEAF_ENTRY KiServiceLinkage, _TEXT$00
ret ;
LEAF_END KiServiceLinkage, _TEXT$00
subttl "Unexpected Interrupt Code"
;++
;
; RoutineDescription:
;
; An entry in the following table is generated for each vector that can
; receive an unexpected interrupt. Each entry in the table contains code
; to push the vector number on the stack and then jump to common code to
; process the unexpected interrupt.
;
; Arguments:
;
; None.
;
;--
NESTED_ENTRY KiUnexpectedInterrupt, _TEXT$00
.pushframe code ; mark machine frame
.pushreg rbp ; mark nonvolatile register push
GENERATE_INTERRUPT_FRAME <Vector> ; generate interrupt frame
mov ecx, eax ; compute interrupt IRQL
shr ecx, 4 ;
ENTER_INTERRUPT <NoEOI> ; raise IRQL and enable interrupts
EXIT_INTERRUPT ; do EOI, lower IRQL, and restore state
NESTED_END KiUnexpectedInterrupt, _TEXT$00
subttl "Unexpected Interrupt Dispatch Code"
;++
; The following code is a table of unexpected interrupt dispatch code
; fragments for each interrupt vector. Empty interrupt vectors are
; initialized to jump to this code which pushes the interrupt vector
; number on the stack and jumps to the above unexpected interrupt code.
;--
EMPTY_VECTOR macro Vector
LEAF_ENTRY KxUnexpectedInterrupt&Vector, _TEXT$00
push &Vector ; push vector number
push rbp ; push nonvolatile register
jmp KiUnexpectedInterrupt ; finish in common code
LEAF_END KxUnexpectedInterrupt&Vector, _TEXT$00
endm
interrupt_vector = 0
rept (MAXIMUM_PRIMARY_VECTOR + 1)
EMPTY_VECTOR %interrupt_vector
interrupt_vector = interrupt_vector + 1
endm
end