xref: /reactos/ntoskrnl/ke/amd64/trap.S (revision c8d07514)
1/*
2 * FILE:            ntoskrnl/ke/amd64/trap.S
3 * COPYRIGHT:       See COPYING in the top level directory
4 * PURPOSE:         System Traps, Entrypoints and Exitpoints
5 * PROGRAMMER:      Timo Kreuzer (timo.kreuzer@reactos.org)
6 */
7
8/* INCLUDES ******************************************************************/
9
10#include <asm.inc>
11#include <ksamd64.inc>
12#include <trapamd64.inc>
13
14EXTERN KiDispatchException:PROC
15EXTERN KeBugCheckWithTf:PROC
16EXTERN MmAccessFault:PROC
17EXTERN KiSystemFatalException:PROC
18EXTERN KiNpxNotAvailableFaultHandler:PROC
19EXTERN KiGeneralProtectionFaultHandler:PROC
20EXTERN KiXmmExceptionHandler:PROC
21EXTERN KiDeliverApc:PROC
22EXTERN KiDpcInterruptHandler:PROC
23EXTERN PsConvertToGuiThread:PROC
24EXTERN MmCreateKernelStack:PROC
25EXTERN MmDeleteKernelStack:PROC
26
27EXTERN KdSetOwedBreakpoints:PROC
28
29
30/* Helper Macros *************************************************************/
31
32MACRO(DispatchException, Status, Number, P1, P2, P3)
33    mov eax, Status
34    mov edx, Number
35    mov r9, P1
36    mov r10, P2
37    mov r11, P3
38    call InternalDispatchException
39ENDM
40
41MACRO(Fatal, BugcheckCode)
42    /* Bugcheck */
43    mov ecx, BugcheckCode
44    mov rdx, rbp
45    call KiSystemFatalException
46ENDM
47
48
49/* FUNCTIONS *****************************************************************/
50
51.code64
52
53ALIGN 8
54
55MACRO(UnexpectedVectorStub, Vector)
56    /* This nop is to make the relative jmp address 4 bytes aligned and to
57       make the whole code 8 bytes long */
58    nop
59    /* This is a push instruction with 8bit operand. Since the instruction
60       sign extends the value to 32 bits, we need to offset it */
61PUBLIC KxUnexpectedInterrupt&Vector
62KxUnexpectedInterrupt&Vector:
63    push (Vector - 128)
64    jmp KiUnexpectedInterrupt
65ENDM
66
67PUBLIC KiUnexpectedRange
68KiUnexpectedRange:
69Vector = 0
70REPEAT 256
71    UnexpectedVectorStub %Vector
72    Vector = Vector+1
73ENDR
74PUBLIC KiUnexpectedRangeEnd
75KiUnexpectedRangeEnd:
76
77PUBLIC KiInterruptDispatchTemplate
78KiInterruptDispatchTemplate:
79    /* This instruction pushes the return address on the stack, which is the
80       address of the interrupt object's DispatchCode member, then jumps
81       to the address stored in the interrupt object's DispatchAddress member */
82    call qword ptr KiInterruptDispatchTemplate[rip - KINTERRUPT_DispatchCode + KINTERRUPT_DispatchAddress]
83
84
85// rbp = TrapFrame, eax = ExceptionCode, edx = NumParams, r9,r10,r11 = params
86FUNC InternalDispatchException
87
88    /* Allocate stack space for EXCEPTION_RECORD and KEXCEPTION_FRAME */
89    sub rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH
90    .allocstack (EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH)
91    .endprolog
92
93    /* Set up EXCEPTION_RECORD */
94    lea rcx, [rsp + KEXCEPTION_FRAME_LENGTH]
95    mov [rcx + EXCEPTION_RECORD_ExceptionCode], eax
96    xor rax, rax
97    mov [rcx + EXCEPTION_RECORD_ExceptionFlags], eax
98    mov [rcx + EXCEPTION_RECORD_ExceptionRecord], rax
99    mov rax, [rbp + KTRAP_FRAME_Rip]
100    mov [rcx + EXCEPTION_RECORD_ExceptionAddress], rax
101    mov [rcx + EXCEPTION_RECORD_NumberParameters], edx
102    mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(00)], r9
103    mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(08)], r10
104    mov [rcx + EXCEPTION_RECORD_ExceptionInformation + HEX(10)], r11
105
106    /* Set up KEXCEPTION_FRAME */
107    mov rax, [rbp + KTRAP_FRAME_Rbp]
108    mov [rsp + KEXCEPTION_FRAME_Rbp], rax
109    mov [rsp + KEXCEPTION_FRAME_Rbx], rbx
110    mov [rsp + KEXCEPTION_FRAME_Rdi], rdi
111    mov [rsp + KEXCEPTION_FRAME_Rsi], rsi
112    mov [rsp + KEXCEPTION_FRAME_R12], r12
113    mov [rsp + KEXCEPTION_FRAME_R13], r13
114    mov [rsp + KEXCEPTION_FRAME_R14], r14
115    mov [rsp + KEXCEPTION_FRAME_R15], r15
116    movdqa [rsp + KEXCEPTION_FRAME_Xmm6], xmm6
117    movdqa [rsp + KEXCEPTION_FRAME_Xmm7], xmm7
118    movdqa [rsp + KEXCEPTION_FRAME_Xmm8], xmm8
119    movdqa [rsp + KEXCEPTION_FRAME_Xmm9], xmm9
120    movdqa [rsp + KEXCEPTION_FRAME_Xmm10], xmm10
121    movdqa [rsp + KEXCEPTION_FRAME_Xmm11], xmm11
122    movdqa [rsp + KEXCEPTION_FRAME_Xmm12], xmm12
123    movdqa [rsp + KEXCEPTION_FRAME_Xmm13], xmm13
124    movdqa [rsp + KEXCEPTION_FRAME_Xmm14], xmm14
125    movdqa [rsp + KEXCEPTION_FRAME_Xmm15], xmm15
126    mov qword ptr [rsp + KEXCEPTION_FRAME_Return], 0
127
128    /* Call KiDispatchException */
129    // rcx already points to ExceptionRecord
130    mov rdx, rsp                                // ExceptionFrame
131    mov r8, rbp                                 // TrapFrame
132    mov r9b, [r8 + KTRAP_FRAME_PreviousMode]    // PreviousMode
133    mov byte ptr [rsp + KEXCEPTION_FRAME_P5], 1 // FirstChance
134    call KiDispatchException
135
136    /* Restore registers */
137    mov r12, [rsp + KEXCEPTION_FRAME_R12]
138    mov r13, [rsp + KEXCEPTION_FRAME_R13]
139    mov r14, [rsp + KEXCEPTION_FRAME_R14]
140    mov r15, [rsp + KEXCEPTION_FRAME_R15]
141    movdqa xmm6, [rsp + KEXCEPTION_FRAME_Xmm6]
142    movdqa xmm7, [rsp + KEXCEPTION_FRAME_Xmm7]
143    movdqa xmm8, [rsp + KEXCEPTION_FRAME_Xmm8]
144    movdqa xmm9, [rsp + KEXCEPTION_FRAME_Xmm9]
145    movdqa xmm10, [rsp + KEXCEPTION_FRAME_Xmm10]
146    movdqa xmm11, [rsp + KEXCEPTION_FRAME_Xmm11]
147    movdqa xmm12, [rsp + KEXCEPTION_FRAME_Xmm12]
148    movdqa xmm13, [rsp + KEXCEPTION_FRAME_Xmm13]
149    movdqa xmm14, [rsp + KEXCEPTION_FRAME_Xmm14]
150    movdqa xmm15, [rsp + KEXCEPTION_FRAME_Xmm15]
151
152    add rsp, EXCEPTION_RECORD_LENGTH + KEXCEPTION_FRAME_LENGTH
153    ret
154ENDFUNC
155
156
157/* CPU EXCEPTION HANDLERS ****************************************************/
158
159PUBLIC KiDivideErrorFault
160FUNC KiDivideErrorFault
161    /* Push pseudo error code */
162    EnterTrap TF_SAVE_ALL
163
164    /* Enable interrupts */
165    sti
166
167    /* Dispatch the exception */
168    DispatchException STATUS_INTEGER_DIVIDE_BY_ZERO, 0, 0, 0, 0
169
170    /* Return */
171    ExitTrap TF_SAVE_ALL
172ENDFUNC
173
174
175PUBLIC KiDebugTrapOrFault
176FUNC KiDebugTrapOrFault
177    /* Push pseudo error code */
178    EnterTrap TF_SAVE_ALL
179
180    /* Check if the frame was from kernelmode */
181    test word ptr [rbp + KTRAP_FRAME_SegCs], 3
182    jz KiDebugTrapOrFaultKMode
183
184    /* Enable interrupts for user-mode */
185    sti
186
187KiDebugTrapOrFaultKMode:
188    /* Dispatch the exception */
189    DispatchException STATUS_SINGLE_STEP, 0, 0, 0, 0
190
191    /* Return */
192    ExitTrap TF_SAVE_ALL
193ENDFUNC
194
195
196PUBLIC KiNmiInterrupt
197FUNC KiNmiInterrupt
198    /* Push pseudo error code */
199    EnterTrap TF_SAVE_ALL
200
201    UNIMPLEMENTED KiNmiInterrupt
202    int 3
203
204    /* Return */
205    ExitTrap TF_SAVE_ALL
206ENDFUNC
207
208
209PUBLIC KiBreakpointTrap
210FUNC KiBreakpointTrap
211    /* Push pseudo error code */
212    EnterTrap TF_SAVE_ALL
213
214    /* Check if the frame was from kernelmode */
215    test word ptr [rbp + KTRAP_FRAME_SegCs], 3
216    jz KiBreakpointTrapKMode
217
218    /* Enable interrupts for user-mode */
219    sti
220
221KiBreakpointTrapKMode:
222    /* Dispatch the exception */
223    DispatchException STATUS_BREAKPOINT, 3, BREAKPOINT_BREAK, 0, 0
224
225    /* Return */
226    ExitTrap TF_SAVE_ALL
227ENDFUNC
228
229
230PUBLIC KiOverflowTrap
231FUNC KiOverflowTrap
232    /* Push pseudo error code */
233    EnterTrap TF_SAVE_ALL
234
235    /* Enable interrupts */
236    sti
237
238    /* Dispatch the exception */
239    DispatchException STATUS_INTEGER_OVERFLOW, 3, 0, 0, 0
240
241    /* Return */
242    ExitTrap TF_SAVE_ALL
243ENDFUNC
244
245
246PUBLIC KiBoundFault
247FUNC KiBoundFault
248    /* Push pseudo error code */
249    EnterTrap TF_SAVE_ALL
250
251    /* Check if the frame was from kernelmode */
252    test word ptr [rbp + KTRAP_FRAME_SegCs], 3
253    jnz KiBoundFaultUserMode
254
255    /* Bugcheck */
256    Fatal EXCEPTION_BOUND_CHECK
257
258KiBoundFaultUserMode:
259    /* Enable interrupts for user-mode */
260    sti
261
262    /* Dispatch the exception */
263    DispatchException STATUS_ARRAY_BOUNDS_EXCEEDED, 0, 0, 0, 0
264
265    /* Return */
266    ExitTrap TF_SAVE_ALL
267ENDFUNC
268
269
270PUBLIC KiInvalidOpcodeFault
271FUNC KiInvalidOpcodeFault
272    /* Push pseudo error code */
273    EnterTrap TF_SAVE_ALL
274
275    /* Enable interrupts */
276    sti
277
278    /* Check if the frame was from kernelmode */
279    test word ptr [rbp + KTRAP_FRAME_SegCs], 3
280    jz KiInvalidOpcodeKernel
281
282    // FIXME: handle STATUS_INVALID_LOCK_SEQUENCE
283
284KiInvalidOpcodeKernel:
285    /* Kernel mode fault */
286
287    /* Dispatch the exception */
288    DispatchException STATUS_ILLEGAL_INSTRUCTION, 3, 0, 0, 0
289
290    /* Return */
291    ExitTrap TF_SAVE_ALL
292ENDFUNC
293
294
295PUBLIC KiNpxNotAvailableFault
296FUNC KiNpxNotAvailableFault
297    /* Push pseudo error code */
298    EnterTrap TF_SAVE_ALL
299
300    /* Call the C handler */
301    mov rcx, rbp
302    call KiNpxNotAvailableFaultHandler
303
304    /* Check the return status code */
305    test eax, eax
306    jz KiNpxNotAvailableFaultExit
307
308    /* Dispatch the exception */
309    DispatchException eax, 3, 0, 0, 0
310
311KiNpxNotAvailableFaultExit:
312    /* Return */
313    ExitTrap TF_SAVE_ALL
314ENDFUNC
315
316
317PUBLIC KiDoubleFaultAbort
318FUNC KiDoubleFaultAbort
319    /* A zero error code is pushed */
320    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
321
322    int 3
323
324    /* Bugcheck */
325    Fatal 8 // EXCEPTION_DOUBLE_FAULT
326    jmp $
327ENDFUNC
328
329
330PUBLIC KiNpxSegmentOverrunAbort
331FUNC KiNpxSegmentOverrunAbort
332    /* Push pseudo error code */
333    EnterTrap TF_SAVE_ALL
334
335    /* Bugcheck */
336    Fatal EXCEPTION_NPX_OVERRUN
337
338    jmp $
339ENDFUNC
340
341
342PUBLIC KiInvalidTssFault
343FUNC KiInvalidTssFault
344    /* We have an error code */
345    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
346
347    /* Bugcheck */
348    Fatal EXCEPTION_INVALID_TSS
349    jmp $
350ENDFUNC
351
352
353PUBLIC KiSegmentNotPresentFault
354FUNC KiSegmentNotPresentFault
355    /* We have an error code */
356    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
357
358    /* Bugcheck */
359    Fatal EXCEPTION_SEGMENT_NOT_PRESENT
360    jmp $
361ENDFUNC
362
363
364PUBLIC KiStackFault
365FUNC KiStackFault
366    /* We have an error code */
367    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
368
369    /* Bugcheck */
370    Fatal EXCEPTION_STACK_FAULT
371    jmp $
372ENDFUNC
373
374
375PUBLIC KiGeneralProtectionFault
376FUNC KiGeneralProtectionFault
377    /* We have an error code */
378    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
379
380    /* Call the C handler */
381    mov rcx, rbp
382    call KiGeneralProtectionFaultHandler
383
384    /* Check for success */
385    test eax, eax
386    jge KiGpfExit
387
388    /* Dispatch the exception */
389    DispatchException eax, 3, 0, 0, 0
390
391KiGpfFatal:
392
393    /* Bugcheck */
394    mov ecx, UNEXPECTED_KERNEL_MODE_TRAP
395    mov rdx, HEX(000D) // EXCEPTION_GP_FAULT
396    xor r8, r8
397    mov r9, [rbp + KTRAP_FRAME_ErrorCode] // error code
398    sub rsp, 8
399    mov [rsp + KTRAP_FRAME_P5+8], rbp // trap frame
400    call KeBugCheckWithTf
401
402KiGpfExit:
403    /* Return */
404    /* Return */
405    ExitTrap TF_SAVE_ALL
406ENDFUNC
407
408
409PUBLIC KiPageFault
410FUNC KiPageFault
411    /* We have an error code */
412    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
413
414    /* Save page fault address */
415    mov rdx, cr2
416    mov [rbp  + KTRAP_FRAME_FaultAddress], rdx
417
418    /* Enable interrupts for the page fault handler */
419    sti
420
421    /* Call page fault handler */
422    mov ecx, [rbp + KTRAP_FRAME_ErrorCode] // FaultCode
423    // rdx == Address
424    mov r8b, [rbp + KTRAP_FRAME_SegCs] // Mode
425    and r8b, 1
426    mov r9, rbp // TrapInformation
427    call MmAccessFault
428
429    /* Check for success */
430    test eax, eax
431    jl PageFaultError
432
433    /* Check whether the kernel debugger has owed breakpoints to be inserted */
434    call KdSetOwedBreakpoints
435    /* We succeeded, return */
436    jmp PageFaultReturn
437
438PageFaultError:
439
440    /* Disable interrupts again for the debugger */
441    cli
442
443    /* Set parameter 1 to error code */
444    mov r9d, [rbp + KTRAP_FRAME_ErrorCode]
445
446    /* Set parameter2 to faulting address */
447    mov r10, cr2  // Param2 = faulting address
448
449    cmp eax, STATUS_ACCESS_VIOLATION
450    je AccessViolation
451    cmp eax, STATUS_GUARD_PAGE_VIOLATION
452    je SpecialCode
453    cmp eax, STATUS_STACK_OVERFLOW
454    je SpecialCode
455
456InPageException:
457    /* Dispatch in-page exception */
458    mov r11d, eax // Param3 = Status
459    mov eax, STATUS_IN_PAGE_ERROR // ExceptionCode
460    mov edx, 3    // ParamCount
461    call InternalDispatchException
462    jmp PageFaultReturn
463
464AccessViolation:
465    /* Use more proper status code */
466    mov eax, KI_EXCEPTION_ACCESS_VIOLATION
467
468SpecialCode:
469    /* Setup a normal page fault exception */
470    mov edx, 2   // ParamCount
471    call InternalDispatchException
472
473PageFaultReturn:
474    /* Return */
475    ExitTrap (TF_SAVE_ALL or TF_CHECKUSERAPC)
476ENDFUNC
477
478
479PUBLIC KiFloatingErrorFault
480FUNC KiFloatingErrorFault
481    /* Push pseudo error code */
482    EnterTrap TF_SAVE_ALL
483
484    UNIMPLEMENTED KiFloatingErrorFault
485    int 3
486
487    /* Return */
488    ExitTrap TF_SAVE_ALL
489ENDFUNC
490
491
492PUBLIC KiAlignmentFault
493FUNC KiAlignmentFault
494    /* We have an error code */
495    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
496
497    /* Bugcheck */
498    Fatal EXCEPTION_ALIGNMENT_CHECK
499    jmp $
500ENDFUNC
501
502
503PUBLIC KiMcheckAbort
504FUNC KiMcheckAbort
505    /* Push pseudo error code */
506    EnterTrap TF_SAVE_ALL
507
508    /* Bugcheck */
509    Fatal HEX(12)
510    jmp $
511ENDFUNC
512
513
514PUBLIC KiXmmException
515FUNC KiXmmException
516    /* Push pseudo error code */
517    EnterTrap TF_SAVE_ALL
518
519    /* Call the C handler */
520    mov rcx, rbp
521    call KiXmmExceptionHandler
522
523    /* Check for success */
524    test eax, eax
525    jge KiXmmExit
526
527    /* Dispatch the exception */
528    DispatchException eax, 3, 0, 0, 0
529
530KiXmmExit:
531    /* Return */
532    ExitTrap TF_SAVE_ALL
533ENDFUNC
534
535
536/* SOFTWARE INTERRUPT SERVICES ***********************************************/
537
538PUBLIC KiRaiseAssertion
539FUNC KiRaiseAssertion
540    /* We have an error code */
541    EnterTrap (TF_SAVE_ALL)
542
543    /* Decrement RIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
544    sub qword ptr [rbp + KTRAP_FRAME_Rip], 2
545
546    /* Dispatch the exception */
547    DispatchException STATUS_ASSERTION_FAILURE, 0, 0, 0, 0
548
549    /* Return */
550    ExitTrap TF_SAVE_ALL
551ENDFUNC
552
553
554PUBLIC KiDebugServiceTrap
555FUNC KiDebugServiceTrap
556   /* No error code */
557    EnterTrap TF_SAVE_ALL
558
559    /* Increase Rip to skip the int3 */
560    inc qword ptr [rbp + KTRAP_FRAME_Rip]
561
562    /* Dispatch the exception (Params = service, buffer, legth) */
563    DispatchException STATUS_BREAKPOINT, 3, [rbp+KTRAP_FRAME_Rax], [rbp+KTRAP_FRAME_Rcx], [rbp+KTRAP_FRAME_Rdx]
564
565    /* Return */
566    ExitTrap TF_SAVE_ALL
567ENDFUNC
568
569
570PUBLIC KiApcInterrupt
571.PROC KiApcInterrupt
572   /* No error code */
573    EnterTrap (TF_VOLATILES or TF_IRQL)
574
575    /* Raise to APC_LEVEL */
576    mov rax, APC_LEVEL
577    mov cr8, rax
578
579    /* End the interrupt */
580    mov dword ptr [APIC_EOI], 0
581
582    /* Enable interrupts  */
583    sti
584
585    /* Call the worker routine */
586    mov cl, [rbp + KTRAP_FRAME_SegCs] // ProcessorMode
587    and cl, 1
588    mov rdx, 0                        // ExceptionFrame
589    mov r8, rbp                       // TrapFrame
590    call KiDeliverApc
591
592    /* Disable interrupts */
593    cli
594
595    /* Lower IRQL back to PASSIVE */
596    mov rax, PASSIVE_LEVEL
597    mov cr8, rax
598
599    /* Return */
600    ExitTrap (TF_VOLATILES or TF_IRQL)
601.ENDP
602
603EXTERN KiRetireDpcList:PROC
604PUBLIC KiRetireDpcListInDpcStack
605.PROC KiRetireDpcListInDpcStack
606    push rbp
607    .pushreg rbp
608    mov rbp, rsp
609    .setframe rbp, 0
610    .endprolog
611
612    /* Switch stack and call the function */
613    mov rsp, rdx
614    sub rsp, 40
615    call KiRetireDpcList
616
617    /* Restore stack, cleanup and return */
618    mov rsp, rbp
619    pop rbp
620    ret
621.ENDP
622
623PUBLIC KiDpcInterrupt
624.PROC KiDpcInterrupt
625   /* No error code */
626    EnterTrap (TF_VOLATILES or TF_IRQL)
627
628    /* Call the worker routine */
629    call KiDpcInterruptHandler
630
631    /* Return, but don't send an EOI! */
632    ExitTrap (TF_VOLATILES or TF_IRQL)
633.ENDP
634
635
636PUBLIC KiIpiInterrupt
637.PROC KiIpiInterrupt
638   /* No error code */
639    EnterTrap (TF_VOLATILES or TF_IRQL)
640
641    /* Raise to IPI_LEVEL */
642    mov rax, IPI_LEVEL
643    mov cr8, rax
644
645    /* End the interrupt */
646    mov dword ptr [APIC_EOI], 0
647
648    int 3
649
650    /* Return */
651    ExitTrap (TF_VOLATILES or TF_IRQL)
652.ENDP
653
654
655PUBLIC KiUnexpectedInterrupt
656FUNC KiUnexpectedInterrupt
657    /* The error code is the vector */
658    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
659
660#if 0
661    /* Set bugcheck parameters */
662    mov ecx, TRAP_CAUSE_UNKNOWN
663    mov rdx, [rbp + KTRAP_FRAME_ErrorCode] // the vector
664    mov r8, 0 // The unknown floating-point exception
665    mov r9, 0 // The enabled and asserted status bits
666    sub rsp, 8
667    mov [rbp + KTRAP_FRAME_P5 + 8], rbp // trap frame
668    call KeBugCheckWithTf
669    jmp $
670#endif
671    /* Return */
672    ExitTrap TF_SAVE_ALL
673ENDFUNC
674
675PUBLIC KiInterruptDispatch
676FUNC KiInterruptDispatch
677    /* The error code is a pointer to the interrupt object's code */
678    EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL)
679
680    /* Increase interrupt count */
681    inc dword ptr gs:[PcInterruptCount];
682
683    /* Load the address of the interrupt object into rcx */
684    mov rcx, [rbp + KTRAP_FRAME_ErrorCode]
685
686    /* Substract offset of the DispatchCode member plus 6 for the call instruction */
687    sub rcx, KINTERRUPT_DispatchCode + 6
688
689    /* Raise IRQL to SynchronizeIrql */
690    movzx rax, byte ptr [rcx + KINTERRUPT_SynchronizeIrql]
691    mov cr8, rax
692
693#ifdef CONFIG_SMP
694    /* Acquire interrupt lock */
695    mov r8, [rcx + KINTERRUPT_ActualLock]
696
697    //KxAcquireSpinLock(Interrupt->ActualLock);
698#endif
699
700    /* Call the ISR */
701    mov rdx, [rcx + KINTERRUPT_ServiceContext]
702    call qword ptr [rcx + KINTERRUPT_ServiceRoutine]
703
704#ifdef CONFIG_SMP
705    /* Release interrupt lock */
706    //KxReleaseSpinLock(Interrupt->ActualLock);
707#endif
708
709    /* Go back to old irql */
710    movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
711    mov cr8, rax
712
713    /* Return */
714    ExitTrap (TF_SAVE_ALL or TF_SEND_EOI)
715ENDFUNC
716
717
718#define MAX_SYSCALL_PARAM_SIZE (16 * 8)
719
720EXTERN KiSystemCallHandler:PROC
721
722/*! \name KiSystemCallEntry64
723 *
724 *  \brief This is the entrypoint for syscalls from 64bit user mode
725 *
726 *  \param rax - The system call number
727 *  \param rcx - User mode return address, set by the syscall instruction
728 *  \param rdx,r8,r9 - Parameters 2-4 to the service function
729 *  \param r10 - Parameter 1 to the service function
730 *  \param r11 - RFLAGS saved by the syscall instruction
731 *--*/
732PUBLIC KiSystemCallEntry64
733.PROC KiSystemCallEntry64
734
735    /* Old stack pointer is in rcx, lie and say we saved it in rbp */
736    .setframe rbp, 0
737    .endprolog
738
739    /* Swap gs to kernel, so we can access the PCR */
740    swapgs
741
742    /* Save the user mode rsp in the PCR */
743    mov gs:[PcUserRsp], rsp
744
745    /* Get the kernel stack from the PCR */
746    mov rsp, gs:[PcRspBase]
747
748    /* Allocate a TRAP_FRAME and space for parameters */
749    sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE)
750#if DBG
751    /* Save rbp and load it with the old stack pointer */
752    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp], rbp
753    mov rbp, gs:[PcUserRsp]
754#endif
755
756    /* Save important registers in the trap frame */
757    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
758    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], r10
759    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], r11
760
761    /* Set sane segments */
762    mov ax, (KGDT64_R3_DATA or RPL_MASK)
763    mov ds, ax
764    mov es, ax
765
766.ENDP
767
768.PROC KiSystemCall64Again
769
770    /* Old stack pointer is in rcx, lie and say we saved it in rbp */
771    .setframe rbp, 0
772    .endprolog
773
774    /* Call the C-handler (will enable interrupts) */
775    call KiSystemCallHandler
776
777    /* The return value from KiSystemCallHandler is the address of the Nt-function */
778    mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx]
779    mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
780    mov r8, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
781    mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
782    call rax
783
784.ENDP
785
786PUBLIC KiSystemServiceExit
787.PROC KiSystemServiceExit
788
789    /* Old stack pointer is in rcx, lie and say we saved it in rbp */
790    .setframe rbp, 0
791    .endprolog
792
793#if DBG
794    /* Restore rbp */
795    mov rbp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rbp]
796
797    test dword ptr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], HEX(200)
798    jnz IntsEnabled
799    int 3
800IntsEnabled:
801#endif
802
803    /* Check for pending user APC */
804    mov rcx, gs:qword ptr [PcCurrentThread]
805    cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0
806    jz no_user_apc_pending
807    call KiInitiateUserApc
808no_user_apc_pending:
809
810    /* Disable interrupts for return */
811    cli
812
813    /* Restore old trap frame */
814    mov rcx, gs:[PcCurrentThread]
815    mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
816    mov [rcx + KTHREAD_TrapFrame], rdx
817
818    /* Prepare user mode return address (rcx) and eflags (r11) for sysret */
819    mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
820    mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags]
821
822    /* Load user mode stack (It was copied to the trap frame) */
823    mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp]
824
825    /* Swap gs back to user */
826    swapgs
827
828    ; Zero out volatiles
829    pxor xmm0, xmm0
830    pxor xmm1, xmm1
831    pxor xmm2, xmm2
832    pxor xmm3, xmm3
833    pxor xmm4, xmm4
834    pxor xmm5, xmm5
835    xor rdx, rdx
836    xor r10, r10
837
838    /* return to user mode */
839    .byte HEX(48) // REX prefix to return to long mode
840    sysret
841
842.ENDP
843
844
845/*!
846 * VOID
847 * DECLSPEC_NORETURN
848 * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
849 */
850PUBLIC KiServiceExit
851.PROC KiServiceExit
852    .endprolog
853
854    lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE]
855    jmp KiSystemServiceExit
856
857.ENDP
858
859
860/*!
861 * VOID
862 * DECLSPEC_NORETURN
863 * KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
864 */
865PUBLIC KiServiceExit2
866.PROC KiServiceExit2
867    .ENDPROLOG
868
869    mov rbp, rcx
870    mov rsp, rcx
871
872    /* Return */
873    ExitTrap TF_SAVE_ALL
874.ENDP
875
876
877PUBLIC KiSystemCallEntry32
878KiSystemCallEntry32:
879    swapgs
880    int 3
881
882
883PUBLIC KiZwSystemService
884FUNC KiZwSystemService
885    push rbp
886    .pushreg rbp
887    sub rsp, KTRAP_FRAME_LENGTH
888    .allocstack KTRAP_FRAME_LENGTH
889    mov [rsp + KTRAP_FRAME_Rsi], rsi
890    .savereg rsi, KTRAP_FRAME_Rsi
891    mov [rsp + KTRAP_FRAME_Rdi], rdi
892    .savereg rdi, KTRAP_FRAME_Rdi
893    mov rbp, rsp
894    .setframe rbp, 0
895    .endprolog
896
897    /* Get current thread */
898    mov r11, gs:[PcCurrentThread]
899
900    /* Save PreviousMode in the trap frame */
901    mov dil, byte ptr [r11 + KTHREAD_PreviousMode]
902    mov byte ptr [rbp + KTRAP_FRAME_PreviousMode], dil
903
904    /* Save the old trap frame in TrapFrame.Rdx */
905    mov rdi, [r11 + KTHREAD_TrapFrame]
906    mov [rbp + KTRAP_FRAME_Rdx], rdi
907
908    /* Set the new trap frame and previous mode */
909    mov [r11 + ThTrapFrame], rbp
910    mov byte ptr [r11 + KTHREAD_PreviousMode], 0
911
912    /* allocate space for parameters */
913    sub rsp, r10
914    and rsp, HEX(0fffffffffffffff0)
915
916    /* Save rcx */
917    mov [rbp + KTRAP_FRAME_Rcx], rcx
918
919    /* copy parameters to the new location */
920    lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16]
921    lea rdi, [rsp]
922    mov rcx, r10
923    shr rcx, 3
924    rep movsq
925
926    /* Restore rcx */
927    mov rcx, [rbp + KTRAP_FRAME_Rcx]
928
929    /* Call the service function */
930    call rax
931
932    /* Restore the old trap frame */
933    mov r11, gs:[PcCurrentThread]
934    mov rsi, [rbp + KTRAP_FRAME_Rdx]
935    mov [r11 + KTHREAD_TrapFrame], rsi
936
937    /* Restore PreviousMode from the trap frame */
938    mov dil, byte ptr [rbp + KTRAP_FRAME_PreviousMode]
939    mov byte ptr [r11 + KTHREAD_PreviousMode], dil
940
941    /* Restore rdi and rsi */
942    mov rsi, [rbp + KTRAP_FRAME_Rsi]
943    mov rdi, [rbp + KTRAP_FRAME_Rdi]
944
945    /* Cleanup the stack and return */
946    lea rsp, [rbp + KTRAP_FRAME_LENGTH]
947    pop rbp
948    ret
949
950ENDFUNC
951
952PUBLIC KiConvertToGuiThread
953FUNC KiConvertToGuiThread
954
955    sub rsp, 40
956    .allocstack 40
957    .endprolog
958
959    // NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0);
960    mov cl, 1
961    xor rdx, rdx
962    call MmCreateKernelStack
963
964    /* Check for failure */
965    test rax, rax
966    jz KiConvertToGuiThreadFailed
967
968    ; OldStack = KeSwitchKernelStack((PVOID)NewStack, (PVOID)(NewStack - KERNEL_STACK_SIZE));
969    mov rcx, rax
970    mov rdx, rax
971    sub rdx, KERNEL_STACK_SIZE
972    call KeSwitchKernelStack
973
974    // MmDeleteKernelStack(OldStack, FALSE);
975    mov rcx, rax
976    xor rdx, rdx
977    call MmDeleteKernelStack
978
979    /* Call the worker function */
980    call PsConvertToGuiThread
981
982    /* Check for failure */
983    test rax, rax
984    js KiConvertToGuiThreadFailed
985
986    /* Disable interrupts for return */
987    cli
988
989    // FIXME: should just do the trap frame switch in KiSystemCallHandler64
990    /* Restore old trap frame */
991    mov rcx, gs:[PcCurrentThread]
992    mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
993    mov [rcx + KTHREAD_TrapFrame], rdx
994
995    // Restore register parameters
996    mov rcx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
997    mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
998    mov r8, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
999    mov r9, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
1000
1001    /* Run KiSystemCallHandler again */
1002    add rsp, 48
1003    jmp KiSystemCall64Again
1004
1005KiConvertToGuiThreadFailed:
1006
1007    /* Clean up the stack and return failure */
1008    add rsp, 40
1009    mov eax, HEX(C0000017) // STATUS_NO_MEMORY
1010    ret
1011
1012ENDFUNC
1013
1014;
1015; VOID
1016; KiDeliverApc(
1017;     _In_ KPROCESSOR_MODE DeliveryMode,
1018;     _In_ PKEXCEPTION_FRAME ExceptionFrame,
1019;     _In_ PKTRAP_FRAME TrapFrame);
1020;
1021EXTERN KiDeliverApc:PROC
1022
1023PUBLIC KiInitiateUserApc
1024.PROC KiInitiateUserApc
1025
1026    ; Generate a KEXCEPTION_FRAME on the stack
1027    GENERATE_EXCEPTION_FRAME
1028
1029    ; Raise IRQL to APC_LEVEL
1030    mov rax, APC_LEVEL
1031    mov cr8, rax
1032
1033    ; Enable interrupts
1034    sti
1035
1036    ; Get the current trap frame
1037    mov rax, gs:[PcCurrentThread]
1038    mov r8, [rax + KTHREAD_TrapFrame]
1039
1040    ; Call the C function
1041    mov ecx, 1
1042    mov rdx, rsp
1043    call KiDeliverApc
1044
1045    ; Disable interrupts again
1046    cli
1047
1048    ; Restore the registers from the KEXCEPTION_FRAME
1049    RESTORE_EXCEPTION_STATE
1050
1051    ; Return
1052    ret
1053
1054.ENDP
1055
1056
1057PUBLIC KiInitializeSegments
1058KiInitializeSegments:
1059    mov ax, KGDT64_R3_DATA or RPL_MASK
1060    mov gs, ax
1061    swapgs
1062    mov gs, ax
1063    ret
1064
1065/*!
1066 * VOID
1067 * KiSwitchKernelStackHelper(
1068 *     LONG_PTR StackOffset,
1069 *     PVOID OldStackBase);
1070 */
1071PUBLIC KiSwitchKernelStackHelper
1072KiSwitchKernelStackHelper:
1073
1074    /* Pop return address from the current stack */
1075    pop rax
1076
1077    /* Switch to new stack */
1078    lea rsp, [rsp + rcx]
1079
1080    /* Push return address on the new stack */
1081    push rax
1082
1083    /* Return on new stack */
1084    mov rax, rdx
1085    ret
1086
1087EXTERN KiSwitchKernelStack:PROC
1088
1089PUBLIC KeSwitchKernelStack
1090FUNC KeSwitchKernelStack
1091
1092    sub rsp, 40
1093    .allocstack 40
1094
1095    ; Save rcx
1096    mov [rsp], rcx
1097    .savereg rcx, 0
1098    .endprolog
1099
1100    ; Call the C handler, which returns the old stack in rax
1101   call KiSwitchKernelStack
1102
1103    ; Restore rcx (StackBase)
1104    mov rcx, [rsp]
1105
1106    ; Switch to new stack: RSP += (StackBase - OldStackBase)
1107    sub rcx, rax
1108    add rsp, rcx
1109
1110    ; Deallocate the home frame
1111    add rsp, 40
1112    ret
1113
1114ENDFUNC
1115
1116
1117
1118
1119#ifdef _MSC_VER
1120#undef lgdt
1121#undef lidt
1122
1123//void __lgdt(void *Source);
1124PUBLIC __lgdt
1125__lgdt:
1126    lgdt fword ptr [rcx]
1127    ret
1128
1129//void __sgdt(void *Destination);
1130PUBLIC __sgdt
1131__sgdt:
1132    sgdt fword ptr [rcx]
1133    ret
1134
1135// void __lldt(unsigned short Value)
1136PUBLIC __lldt
1137__lldt:
1138    lldt cx
1139    ret
1140
1141//void __sldt(void *Destination);
1142PUBLIC __sldt
1143__sldt:
1144    sldt word ptr [rcx]
1145    ret
1146
1147//void __ltr(unsigned short Source);
1148PUBLIC __ltr
1149__ltr:
1150    ltr cx
1151    ret
1152
1153//void __str(unsigned short *Destination);
1154PUBLIC __str
1155__str:
1156    str word ptr [rcx]
1157    ret
1158
1159PUBLIC __swapgs
1160__swapgs:
1161    swapgs
1162    ret
1163
1164#endif
1165
1166END
1167