EXTERN KiGeneralProtectionFaultHandler:PROC
EXTERN KiXmmExceptionHandler:PROC
EXTERN KiDeliverApc:PROC
-EXTERN KiDispatchInterrupt:PROC
+EXTERN KiDpcInterruptHandler:PROC
/* GLOBALS *******************************************************************/
MsgUnimplemented:
.asciz "WARNING: %s at %s:%d is UNIMPLEMENTED!\n"
+MsgPageFault:
+.asciz "Page fault! Code = 0x%x, RIP = %p, FaultingAddress = %p\n"
+
+MsgGeneralProtFault:
+.asciz "General protection fault at %p!\n"
+
+MsgBreakpointTrap:
+.asciz "BreakpointTrap at %p\n"
+
+MsgUnexpectedInterrupt:
+.asciz "UnexpectedInterrupt Vector=0x%02lx\n"
+
+MsgInvalidOpcodeFault:
+.asciz "Invalid opcode fault at %p!\n"
+
+MsgDoubleFault:
+.asciz "Double fault at %p, rbp=%p!\n"
+
+MsgTrapInfo:
+.asciz "Trap: %s at %p\n"
+
+MACRO(TRAPINFO, func)
+LOCAL label1, label2
+#if 0
+ jmp label2
+label1: .asciz "\func"
+label2:
+ push rax
+ push rcx
+ push rdx
+ push r8
+ push r9
+ push r10
+ push r11
+ sub rsp, 32
+ lea rcx, MsgTrapInfo[rip]
+ lea rdx, 1b[rip]
+ mov r8, [rbp + KTRAP_FRAME_Rip]
+ call qword ptr FrLdrDbgPrint[rip]
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rdx
+ pop rcx
+ pop rax
+ add rsp, 32
+#endif
+ENDM
/* Helper Macros *************************************************************/
ALIGN 8
-PUBLIC InterruptDispatchTable
-InterruptDispatchTable:
+MACRO(UnexpectedVectorStub, Vector)
+ /* This nop is to make the relative jmp address 4 bytes aligned and to
+ make the whole code 8 bytes long */
+ nop
+ /* This is a push instruction with 8bit operand. Since the instruction
+ sign extends the value to 32 bits, we need to offset it */
+PUBLIC KxUnexpectedInterrupt&Vector
+KxUnexpectedInterrupt&Vector:
+ push (Vector - 128)
+ jmp KiUnexpectedInterrupt
+ENDM
+
+PUBLIC KiUnexpectedRange
+KiUnexpectedRange:
Vector = 0
REPEAT 256
- push Vector
- jmp KiUnexpectedInterrupt
- ALIGN 8
+ UnexpectedVectorStub %Vector
Vector = Vector+1
ENDR
+PUBLIC KiUnexpectedRangeEnd
+KiUnexpectedRangeEnd:
+
+PUBLIC KiInterruptDispatchTemplate
+KiInterruptDispatchTemplate:
+ /* This instruction pushes the return address on the stack, which is the
+ address of the interrupt object's DispatchCode member, then jumps
+ to the address stored in the interrupt object's DispatchAddress member */
+ call qword ptr KiInterruptDispatchTemplate[rip - KINTERRUPT_DispatchCode + KINTERRUPT_DispatchAddress]
+
// rbp = TrapFrame, eax = ExceptionCode, edx = NumParams, r9,r10,r11 = params
-.PROC InternalDispatchException
+FUNC InternalDispatchException
/* Allocate stack space for EXCEPTION_RECORD and KEXCEPTION_FRAME */
sub rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH
add rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH
ret
-.ENDP InternalDispatchException
+ENDFUNC InternalDispatchException
-/* SOFTWARE INTERRUPT SERVICES ***********************************************/
+/* CPU EXCEPTION HANDLERS ****************************************************/
PUBLIC KiDivideErrorFault
FUNC KiDivideErrorFault
/* Push pseudo error code */
EnterTrap TF_SAVE_ALL
+ TRAPINFO KiDebugTrapOrFault
+
/* Check if the frame was from kernelmode */
test word ptr [rbp + KTRAP_FRAME_SegCs], 3
jz KiDebugTrapOrFaultKMode
/* Push pseudo error code */
EnterTrap TF_SAVE_ALL
+ /* Check if the frame was from kernelmode */
+ test word ptr [rbp + KTRAP_FRAME_SegCs], 3
+ jz KiBreakpointTrapKMode
+
+ /* Enable interrupts for user-mode */
+ sti
+
+KiBreakpointTrapKMode:
/* Dispatch the exception */
- DispatchException STATUS_BREAKPOINT, 3, 0, 0, 0
+ DispatchException STATUS_BREAKPOINT, 3, BREAKPOINT_BREAK, 0, 0
/* Return */
ExitTrap TF_SAVE_ALL
/* No error code */
EnterTrap TF_SAVE_ALL
+ TRAPINFO KiInvalidOpcodeFault
+
+ mov rdx, [rbp + KTRAP_FRAME_Rip]
+ lea rcx, MsgInvalidOpcodeFault[rip]
+ call qword ptr FrLdrDbgPrint[rip]
+
/* Enable interrupts */
sti
/* No error code */
EnterTrap TF_SAVE_ALL
+ lea rcx, MsgDoubleFault[rip]
+ mov rdx, [rbp + KTRAP_FRAME_FaultAddress]
+ mov r8, rbp
+ call qword ptr FrLdrDbgPrint[rip]
+
/* Bugcheck */
Fatal 8 // EXCEPTION_DOUBLE_FAULT
jmp $
/* Bugcheck */
Fatal EXCEPTION_NPX_OVERRUN
+
jmp $
ENDFUNC KiNpxSegmentOverrunAbort
/* We have an error code */
EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
+ //TRAPINFO KiGeneralProtectionFault
+ //mov rdx, [rbp + KTRAP_FRAME_Rip]
+ //lea rcx, MsgGeneralProtFault[rip]
+ //call qword ptr FrLdrDbgPrint[rip]
+
/* Call the C handler */
mov rcx, rbp
call KiGeneralProtectionFaultHandler
/* We have an error code */
EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
+ TRAPINFO KiPageFault
+
+#if 0
+ lea rcx, MsgPageFault[rip]
+ mov rdx, [rbp + KTRAP_FRAME_ErrorCode]
+ mov r8, [rbp + KTRAP_FRAME_Rip]
+ mov r9, [rbp + KTRAP_FRAME_FaultAddress]
+ call qword ptr FrLdrDbgPrint[rip]
+#endif
+
/* Save page fault address */
mov rdx, cr2
mov [rbp + KTRAP_FRAME_FaultAddress], rdx
+ /* Enable interrupts for the page fault handler */
+ sti
+
/* Call page fault handler */
mov ecx, [rbp + KTRAP_FRAME_ErrorCode] // StoreInstruction
and ecx, 1
test eax, eax
jge PageFaultReturn
+ /* Disable interrupts again for the debugger */
+ cli
+
/* Set parameter 1 to error code */
mov r9d, [rbp + KTRAP_FRAME_ErrorCode]
PageFaultReturn:
/* Return */
- ExitTrap TF_SAVE_ALL
-ENDFUNC KiPageFault
+ ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC)
+ENDFUNC
PUBLIC KiFloatingErrorFault
ENDFUNC KiXmmException
+/* SOFTWARE INTERRUPT SERVICES ***********************************************/
+
PUBLIC KiRaiseAssertion
FUNC KiRaiseAssertion
/* We have an error code */
- EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
+ EnterTrap (TF_SAVE_ALL)
/* Decrement RIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
sub qword ptr [rbp + KTRAP_FRAME_Rip], 2
PUBLIC KiDebugServiceTrap
-.PROC KiDebugServiceTrap
+FUNC KiDebugServiceTrap
/* No error code */
EnterTrap TF_SAVE_ALL
+ TRAPINFO KiDebugServiceTrap
+
/* Increase Rip to skip the int3 */
inc qword ptr [rbp + KTRAP_FRAME_Rip]
/* Return */
ExitTrap TF_SAVE_ALL
-.ENDP KiDebugServiceTrap
+ENDFUNC KiDebugServiceTrap
PUBLIC KiApcInterrupt
/* Disable interrupts */
cli
+ /* Lower IRQL back to PASSIVE */
+ mov rax, PASSIVE_LEVEL
+ mov cr8, rax
+
/* Return */
ExitTrap (TF_VOLATILES or TF_IRQL)
-.ENDP KiApcInterrupt
+.ENDP
+
+EXTERN KiRetireDpcList:PROC
+PUBLIC KiRetireDpcListInDpcStack
+.PROC KiRetireDpcListInDpcStack
+ push rbp
+ .pushreg rbp
+ mov rbp, rsp
+ .setframe rbp, 0
+ .endprolog
+
+ /* Switch stack and call the function */
+ mov rsp, rdx
+ sub rsp, 40
+ call KiRetireDpcList
+ /* Restore stack, cleanup and return */
+ mov rsp, rbp
+ pop rbp
+ ret
+.ENDP
PUBLIC KiDpcInterrupt
.PROC KiDpcInterrupt
/* No error code */
EnterTrap (TF_VOLATILES or TF_IRQL)
- /* Raise to DISPATCH_LEVEL */
- mov rax, DISPATCH_LEVEL
- mov cr8, rax
-
- /* End the interrupt */
- mov dword ptr [APIC_EOI], 0
-
/* Call the worker routine */
- sti
- call KiDispatchInterrupt
- cli
+ call KiDpcInterruptHandler
- /* Return */
+ /* Return, but don't send an EOI! */
ExitTrap (TF_VOLATILES or TF_IRQL)
-.ENDP KiDpcInterrupt
+.ENDP
PUBLIC KiIpiInterrupt
/* Return */
ExitTrap (TF_VOLATILES or TF_IRQL)
-.ENDP KiIpiInterrupt
+.ENDP
PUBLIC KiUnexpectedInterrupt
ExitTrap TF_SAVE_ALL
ENDFUNC KiUnexpectedInterrupt
+PUBLIC KiInterruptDispatch
+FUNC KiInterruptDispatch
+ /* The error code is a pointer to the interrupt object's code */
+ EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL)
+
+ /* Increase interrupt count */
+ inc dword ptr gs:[PcInterruptCount];
+
+ /* Load the address of the interrupt object into rcx */
+ mov rcx, [rbp + KTRAP_FRAME_ErrorCode]
+
+ /* Substract offset of the DispatchCode member plus 6 for the call instruction */
+ sub rcx, KINTERRUPT_DispatchCode + 6
+
+ /* Raise IRQL to SynchronizeIrql */
+ movzx rax, byte ptr [rcx + KINTERRUPT_SynchronizeIrql]
+ mov cr8, rax
+
+#ifdef CONFIG_SMP
+ /* Acquire interrupt lock */
+ mov r8, [rcx + KINTERRUPT_ActualLock]
+
+ //KxAcquireSpinLock(Interrupt->ActualLock);
+#endif
+
+ /* Call the ISR */
+ mov rdx, [rcx + KINTERRUPT_ServiceContext]
+ call qword ptr [rcx + KINTERRUPT_ServiceRoutine]
+
+#ifdef CONFIG_SMP
+ /* Release interrupt lock */
+ //KxReleaseSpinLock(Interrupt->ActualLock);
+#endif
+
+ /* Go back to old irql */
+ movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
+ mov cr8, rax
+
+ /* Return */
+ ExitTrap (TF_SAVE_ALL or TF_SEND_EOI)
+ENDFUNC
+
+
+#define MAX_SYSCALL_PARAM_SIZE (16 * 8)
+#define HOME_SIZE 6*8
+#define SYSCALL_ALLOCATION (MAX_SYSCALL_PARAM_SIZE + HOME_SIZE)
+
+EXTERN KiSystemCallHandler:PROC
+
+/*! \name KiSystemCallEntry64
+ *
+ * \brief This is the entrypoint for syscalls from 64bit user mode
+ *
+ * \param rax - The system call number
+ * \param rcx - User mode return address, set by the syscall instruction
+ * \param rdx,r8,r9 - Parameters 2-4 to the service function
+ * \param r10 - Parameter 1 to the service function
+ * \param r11 - RFLAGS saved by the syscall instruction
+ *--*/
+PUBLIC KiSystemCallEntry64
+.PROC KiSystemCallEntry64
+
+ /* Old stack pointer is in rcx, lie and say we saved it in rbp */
+ .setframe rbp, 0
+ .endprolog
+
+ /* Swap gs to kernel, so we can access the PCR */
+ swapgs
+
+ /* Save the user mode rsp in the PCR */
+ mov gs:[PcUserRsp], rsp
+
+ /* Get the kernel stack from the PCR */
+ mov rsp, gs:[PcRspBase]
+
+ /* Allocate a TRAP_FRAME and space for parameters */
+ sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE)
+#if DBG
+ /* Save rbp and load it with the old stack pointer */
+ mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + HOME_SIZE + KTRAP_FRAME_Rbp], rbp
+ mov rbp, gs:[PcUserRsp]
+#endif
+
+ /* Save important volatiles in the trap frame */
+ mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
+ mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], rcx
+ mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R10], r10
+ mov [rsp + HOME_SIZE + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11], r11
+
+ /* Set sane segments */
+ mov ax, (KGDT64_R3_DATA or RPL_MASK)
+ mov ds, ax
+ mov es, ax
+
+ /* Call the C-handler (will enable interrupts) */
+ lea rcx, [rsp + SYSCALL_ALLOCATION]
+ call KiSystemCallHandler
+
+ /* Deallocate the handlers home stack frame */
+ add rsp, HOME_SIZE
+
+ /* The return value is the address of the Nt-function */
+ mov rcx, [rsp + 0]
+ mov rdx, [rsp + 8]
+ mov r8, [rsp + 16]
+ mov r9, [rsp + 24]
+ call rax
+
+#if DBG
+ /* Restore rbp */
+ mov rbp, [rsp + SYSCALL_ALLOCATION + KTRAP_FRAME_Rbp]
+#endif
+
+ /* Disable interrupts for return */
+ cli
+
+ /* Restore old trap frame */
+ mov rcx, gs:[PcCurrentThread]
+ mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
+ mov [rcx + KTHREAD_TrapFrame], rdx
+
+ /* Prepare user mode return address (rcx) and eflags (r11) for sysret */
+ mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx]
+ mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R11]
+
+ /* Load user mode stack (It was copied to the trap frame) */
+ mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp]
+
+ /* Swap gs back to user */
+ swapgs
+
+ /* return to user mode */
+ .byte HEX(48) // REX prefix to return to long mode
+ sysret
+.ENDP
+
+
+PUBLIC KiSystemCallEntry32
+KiSystemCallEntry32:
+ swapgs
+ int 3
+
+
+PUBLIC KiZwSystemService
+FUNC KiZwSystemService
+ push rbp
+ .pushreg rbp
+ sub rsp, KTRAP_FRAME_LENGTH
+ .allocstack KTRAP_FRAME_LENGTH
+ mov [rsp + KTRAP_FRAME_Rsi], rsi
+ .savereg rsi, KTRAP_FRAME_Rsi
+ mov [rsp + KTRAP_FRAME_Rdi], rdi
+ .savereg rdi, KTRAP_FRAME_Rdi
+ mov rbp, rsp
+ .setframe rbp, 0
+ .endprolog
+
+ /* Get current thread */
+ mov r11, gs:[PcCurrentThread]
+
+ /* Save the old trap frame in TrapFrame.Rdx */
+ mov rdi, [r11 + KTHREAD_TrapFrame]
+ mov [rbp + KTRAP_FRAME_Rdx], rdi
+
+ /* Set the new trap frame and previous mode */
+ mov [r11 + ThTrapFrame], rbp
+ mov byte ptr [r11 + KTHREAD_PreviousMode], 0
+
+ /* allocate space for parameters */
+ sub rsp, r10
+ and rsp, HEX(0fffffffffffffff0)
+
+ /* Save rcx */
+ mov [rbp + KTRAP_FRAME_Rcx], rcx
+
+ /* copy parameters to the new location */
+ lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16]
+ lea rdi, [rsp]
+ mov rcx, r10
+ shr rcx, 3
+ rep movsq
+
+ /* Restore rcx */
+ mov rcx, [rbp + KTRAP_FRAME_Rcx]
+
+ /* Call the service function */
+ call rax
+
+ /* Restore the old trap frame */
+ mov r11, gs:[PcCurrentThread]
+ mov rsi, [rsp + KTRAP_FRAME_Rdx]
+ mov [r11 + KTHREAD_TrapFrame], rsi
+
+ /* Restore rdi and rsi */
+ mov rsi, [rbp + KTRAP_FRAME_Rsi]
+ mov rdi, [rbp + KTRAP_FRAME_Rdi]
+
+ /* Cleanup the stack and return */
+ lea rsp, [rbp + KTRAP_FRAME_LENGTH]
+ pop rbp
+ ret
+
+ENDFUNC
+
+
+KiExitToUserApc:
+ int 3
+
+/*!
+ * VOID
+ * DECLSPEC_NORETURN
+ * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
+ */
+PUBLIC KiServiceExit
+KiServiceExit:
+ mov [rcx + KTRAP_FRAME_Rax], rdx
+ mov rbp, rcx
+ mov rsp, rcx
+
+ /* Return */
+ //ExitTrap TF_SAVE_ALL
+
+/*!
+ * VOID
+ * DECLSPEC_NORETURN
+ * KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
+ */
+PUBLIC KiServiceExit2
+.PROC KiServiceExit2
+ .ENDPROLOG
+
+ mov rbp, rcx
+ mov rsp, rcx
+
+ /* Return */
+ ExitTrap TF_SAVE_ALL
+.ENDP
+
+PUBLIC KiInitializeSegments
+KiInitializeSegments:
+ mov ax, KGDT64_R3_DATA or RPL_MASK
+ mov gs, ax
+ swapgs
+ mov gs, ax
+ ret
+
+
#ifdef _MSC_VER
#undef lgdt
#undef lidt
str word ptr [rcx]
ret
+PUBLIC __swapgs
+__swapgs:
+ swapgs
+ ret
+
#endif
END