[NTOSKRNL/AMD64]
[reactos.git] / reactos / ntoskrnl / ke / amd64 / trap.S
index b275175..ca2e45a 100644 (file)
@@ -20,7 +20,7 @@ EXTERN KiNpxNotAvailableFaultHandler:PROC
 EXTERN KiGeneralProtectionFaultHandler:PROC
 EXTERN KiXmmExceptionHandler:PROC
 EXTERN KiDeliverApc:PROC
-EXTERN KiDispatchInterrupt:PROC
+EXTERN KiDpcInterruptHandler:PROC
 
 /* GLOBALS *******************************************************************/
 
@@ -30,6 +30,55 @@ PUBLIC MsgUnimplemented
 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 *************************************************************/
 
@@ -56,18 +105,38 @@ ENDM
 
 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
@@ -135,10 +204,10 @@ ENDR
 
     add rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH
     ret
-.ENDP InternalDispatchException
+ENDFUNC InternalDispatchException
 
 
-/* SOFTWARE INTERRUPT SERVICES ***********************************************/
+/* CPU EXCEPTION HANDLERS ****************************************************/
 
 PUBLIC KiDivideErrorFault
 FUNC KiDivideErrorFault
@@ -161,6 +230,8 @@ FUNC KiDebugTrapOrFault
     /* 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
@@ -195,8 +266,16 @@ FUNC KiBreakpointTrap
     /* 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
@@ -248,6 +327,12 @@ FUNC KiInvalidOpcodeFault
    /* 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
 
@@ -295,6 +380,11 @@ FUNC KiDoubleFaultAbort
    /* 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 $
@@ -308,6 +398,7 @@ FUNC KiNpxSegmentOverrunAbort
 
     /* Bugcheck */
     Fatal EXCEPTION_NPX_OVERRUN
+
     jmp $
 ENDFUNC KiNpxSegmentOverrunAbort
 
@@ -350,6 +441,11 @@ FUNC KiGeneralProtectionFault
     /* 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
@@ -384,10 +480,23 @@ FUNC KiPageFault
     /* 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
@@ -401,6 +510,9 @@ FUNC KiPageFault
     test eax, eax
     jge PageFaultReturn
 
+    /* Disable interrupts again for the debugger */
+    cli
+
     /* Set parameter 1 to error code */
     mov r9d, [rbp + KTRAP_FRAME_ErrorCode]
 
@@ -434,8 +546,8 @@ SpecialCode:
 
 PageFaultReturn:
     /* Return */
-    ExitTrap TF_SAVE_ALL
-ENDFUNC KiPageFault
+    ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC)
+ENDFUNC
 
 
 PUBLIC KiFloatingErrorFault
@@ -495,10 +607,12 @@ KiXmmExit:
 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
@@ -512,10 +626,12 @@ ENDFUNC KiRaiseAssertion
 
 
 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]
 
@@ -524,7 +640,7 @@ PUBLIC KiDebugServiceTrap
 
     /* Return */
     ExitTrap TF_SAVE_ALL
-.ENDP KiDebugServiceTrap
+ENDFUNC KiDebugServiceTrap
 
 
 PUBLIC KiApcInterrupt
@@ -552,31 +668,45 @@ 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
@@ -595,7 +725,7 @@ PUBLIC KiIpiInterrupt
 
     /* Return */
     ExitTrap (TF_VOLATILES or TF_IRQL)
-.ENDP KiIpiInterrupt
+.ENDP
 
 
 PUBLIC KiUnexpectedInterrupt
@@ -618,6 +748,253 @@ FUNC 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
@@ -658,6 +1035,11 @@ __str:
     str word ptr [rcx]
     ret
 
+PUBLIC __swapgs
+__swapgs:
+    swapgs
+    ret
+
 #endif
 
 END