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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; 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 ; restore trap state/exit to user mode KiSS40: RESTORE_TRAP_STATE ; 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 ; restore exception state/deallocate RESTORE_TRAP_STATE ; 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 ; generate interrupt frame mov ecx, eax ; compute interrupt IRQL shr ecx, 4 ; ENTER_INTERRUPT ; 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