xref: /reactos/ntoskrnl/ke/amd64/trap.S (revision 53221834)
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
603/*
604 * VOID
605 * KiRetireDpcList(
606 *     PKPRCB Prcb);
607 */
608EXTERN KiRetireDpcList:PROC
609
610/*
611 * VOID
612 * KiRetireDpcListInDpcStack(
613 *     PKPRCB Prcb,
614 *     PVOID DpcStack);
615 */
616PUBLIC KiRetireDpcListInDpcStack
617.PROC KiRetireDpcListInDpcStack
618    push rbp
619    .pushreg rbp
620    mov rbp, rsp
621    .setframe rbp, 0
622    .endprolog
623
624    /* Switch to the DpcStack */
625    mov rsp, rdx
626
627    /* The stack is 16 byte aligned, allocate 32 bytes home space */
628    sub rsp, 32
629
630    /* Call KiRetireDpcList on the given stack */
631    call KiRetireDpcList
632
633    /* Restore stack, cleanup and return */
634    mov rsp, rbp
635    pop rbp
636    ret
637.ENDP
638
639PUBLIC KiDpcInterrupt
640.PROC KiDpcInterrupt
641   /* No error code */
642    EnterTrap (TF_VOLATILES or TF_IRQL)
643
644    /* Call the worker routine */
645    call KiDpcInterruptHandler
646
647    /* Return, but don't send an EOI! */
648    ExitTrap (TF_VOLATILES or TF_IRQL)
649.ENDP
650
651
652PUBLIC KiIpiInterrupt
653.PROC KiIpiInterrupt
654   /* No error code */
655    EnterTrap (TF_VOLATILES or TF_IRQL)
656
657    /* Raise to IPI_LEVEL */
658    mov rax, IPI_LEVEL
659    mov cr8, rax
660
661    /* End the interrupt */
662    mov dword ptr [APIC_EOI], 0
663
664    int 3
665
666    /* Return */
667    ExitTrap (TF_VOLATILES or TF_IRQL)
668.ENDP
669
670
671PUBLIC KiUnexpectedInterrupt
672FUNC KiUnexpectedInterrupt
673    /* The error code is the vector */
674    EnterTrap (TF_HAS_ERROR_CODE OR TF_SAVE_ALL)
675
676#if 0
677    /* Set bugcheck parameters */
678    mov ecx, TRAP_CAUSE_UNKNOWN
679    mov rdx, [rbp + KTRAP_FRAME_ErrorCode] // the vector
680    mov r8, 0 // The unknown floating-point exception
681    mov r9, 0 // The enabled and asserted status bits
682    sub rsp, 8
683    mov [rbp + KTRAP_FRAME_P5 + 8], rbp // trap frame
684    call KeBugCheckWithTf
685    jmp $
686#endif
687    /* Return */
688    ExitTrap TF_SAVE_ALL
689ENDFUNC
690
691PUBLIC KiInterruptDispatch
692FUNC KiInterruptDispatch
693    /* The error code is a pointer to the interrupt object's code */
694    EnterTrap (TF_HAS_ERROR_CODE or TF_SAVE_ALL or TF_IRQL)
695
696    /* Increase interrupt count */
697    inc dword ptr gs:[PcInterruptCount];
698
699    /* Save rbx and rsi in the trap frame */
700    mov [rbp + KTRAP_FRAME_Rbx], rbx
701    mov [rbp + KTRAP_FRAME_Rsi], rsi
702
703    /* Load the address of the dispatch code into rbx */
704    mov rbx, [rbp + KTRAP_FRAME_ErrorCode]
705
706    /* Substract offset of the DispatchCode member plus 6 for the call instruction */
707    sub rbx, KINTERRUPT_DispatchCode + 6
708
709    /* Save the address of the InterruptListEntry in rsi */
710    lea rsi, [rbx + KINTERRUPT_InterruptListEntry]
711
712.DoDispatchInterrupt:
713    /* Raise IRQL to SynchronizeIrql */
714    movzx rax, byte ptr [rbx + KINTERRUPT_SynchronizeIrql]
715    mov cr8, rax
716
717#ifdef CONFIG_SMP
718    /* Acquire interrupt lock */
719    mov r8, [rbx + KINTERRUPT_ActualLock]
720
721    //KxAcquireSpinLock(Interrupt->ActualLock);
722#endif
723
724    /* Call the ISR */
725    mov rcx, rbx
726    mov rdx, [rbx + KINTERRUPT_ServiceContext]
727    call qword ptr [rbx + KINTERRUPT_ServiceRoutine]
728
729#ifdef CONFIG_SMP
730    /* Release interrupt lock */
731    //KxReleaseSpinLock(Interrupt->ActualLock);
732#endif
733
734    /* Go back to old irql */
735    movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql]
736    mov cr8, rax
737
738    /* Check for chained interrupts */
739    mov rax, [rbx + KINTERRUPT_InterruptListEntry]
740    cmp rax, rsi
741    je .Done
742
743    /* Load the next interrupt object into rbx and repeat */
744    lea rbx, [rax - KINTERRUPT_InterruptListEntry]
745    jmp .DoDispatchInterrupt
746
747.Done:
748    /* Restore rbx and rsi */
749    mov rbx, [rbp + KTRAP_FRAME_Rbx]
750    mov rsi, [rbp + KTRAP_FRAME_Rsi]
751
752    /* Return */
753    ExitTrap (TF_SAVE_ALL or TF_SEND_EOI)
754ENDFUNC
755
756EXTERN KiSystemCallHandler:PROC
757
758/*! \name KiSystemCallEntry64
759 *
760 *  \brief This is the entrypoint for syscalls from 64bit user mode
761 *
762 *  \param rax - The system call number
763 *  \param rcx - User mode return address, set by the syscall instruction
764 *  \param rdx,r8,r9 - Parameters 2-4 to the service function
765 *  \param r10 - Parameter 1 to the service function
766 *  \param r11 - RFLAGS saved by the syscall instruction
767 *--*/
768PUBLIC KiSystemCallEntry64
769.PROC KiSystemCallEntry64
770    /* The unwind info pretends we have a machine frame */
771    .PUSHFRAME
772    .ALLOCSTACK (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE - MachineFrameLength)
773    .ENDPROLOG
774
775    /* Swap gs to kernel, so we can access the PCR */
776    swapgs
777
778    /* Save the user mode rsp in the PCR */
779    mov gs:[PcUserRsp], rsp
780
781    /* Get the kernel stack from the PCR */
782    mov rsp, gs:[PcRspBase]
783
784    /* Allocate a TRAP_FRAME and space for parameters */
785    sub rsp, (KTRAP_FRAME_LENGTH + MAX_SYSCALL_PARAM_SIZE)
786
787    /* Save volatile registers in the trap frame */
788    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rax], rax
789    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip], rcx
790    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx], rdx
791    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8], r8
792    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9], r9
793    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx], r10
794    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], r11
795
796    /* Store user stack pointer in the trap frame */
797    mov rax, gs:[PcUserRsp]
798    mov [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp], rax
799
800    /* Set sane segments */
801    mov ax, (KGDT64_R3_DATA or RPL_MASK)
802    mov ds, ax
803    mov es, ax
804
805#if DBG
806    /* Check IRQL */
807    mov rax, cr8
808    test eax, eax
809    jz KiSystemCall64Again
810    int HEX(2C)
811#endif
812
813GLOBAL_LABEL KiSystemCall64Again
814
815    /* Call the C-handler (will enable interrupts) */
816    call KiSystemCallHandler
817
818    /* The return value from KiSystemCallHandler is the address of the Nt-function */
819    mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rcx]
820    mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
821    mov r8, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
822    mov r9, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
823    call rax
824
825GLOBAL_LABEL KiSystemServiceExit
826
827#if DBG
828    test dword ptr [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags], HEX(200)
829    jnz IntsEnabled
830    int 3
831IntsEnabled:
832#endif
833
834    /* Check for pending user APC */
835    mov rcx, gs:qword ptr [PcCurrentThread]
836    cmp byte ptr [rcx + ThApcState + AsUserApcPending], 0
837    jz no_user_apc_pending
838    call KiInitiateUserApc
839no_user_apc_pending:
840
841    /* Disable interrupts for return */
842    cli
843
844    /* Restore old trap frame */
845    mov rcx, gs:[PcCurrentThread]
846    mov rdx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
847    mov [rcx + KTHREAD_TrapFrame], rdx
848
849    /* Prepare user mode return address (rcx) and eflags (r11) for sysret */
850    mov rcx, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
851    mov r11, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_EFlags]
852
853    /* Load user mode stack (It was copied to the trap frame) */
854    mov rsp, [rsp + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rsp]
855
856    /* r8 points to the user stack */
857    mov r8, rsp
858
859    /* r9 matches rbp */
860    mov r9, rbp
861
862    /* Swap gs back to user */
863    swapgs
864
865    /* Zero out volatiles */
866    pxor xmm0, xmm0
867    pxor xmm1, xmm1
868    pxor xmm2, xmm2
869    pxor xmm3, xmm3
870    pxor xmm4, xmm4
871    pxor xmm5, xmm5
872    xor rdx, rdx
873    xor r10, r10
874
875    /* return to user mode */
876    .byte HEX(48) // REX prefix to return to long mode
877    sysretq
878
879.ENDP
880
881
882/*!
883 * VOID
884 * DECLSPEC_NORETURN
885 * KiServiceExit(IN PKTRAP_FRAME TrapFrame, IN NTSTATUS Status));
886 */
887PUBLIC KiServiceExit
888.PROC KiServiceExit
889    .endprolog
890
891    lea rsp, [rcx - MAX_SYSCALL_PARAM_SIZE]
892    jmp KiSystemServiceExit
893
894.ENDP
895
896
897/*!
898 * VOID
899 * DECLSPEC_NORETURN
900 * KiServiceExit2(IN PKTRAP_FRAME TrapFrame);
901 */
902PUBLIC KiServiceExit2
903.PROC KiServiceExit2
904    .ENDPROLOG
905
906#if DBG
907    /* Get the current IRQL and compare it to the trap frame */
908    mov rax, cr8
909    cmp byte ptr [rcx + KTRAP_FRAME_PreviousIrql], al
910    je KiServiceExit2_ok1
911    int HEX(2C)
912
913KiServiceExit2_ok1:
914    /* Check if this is a user mode exit */
915    mov ah, byte ptr [rcx + KTRAP_FRAME_SegCs]
916    test ah, 1
917    jz KiServiceExit2_kernel
918
919    /* Validate that we are at PASSIVE_LEVEL */
920    test al, al
921    jz KiServiceExit2_kernel
922    int HEX(2C)
923
924KiServiceExit2_kernel:
925#endif
926
927    mov rbp, rcx
928    mov rsp, rcx
929
930    /* Return */
931    ExitTrap TF_SAVE_ALL
932.ENDP
933
934
935PUBLIC KiSystemCallEntry32
936KiSystemCallEntry32:
937    swapgs
938    int 3
939
940
941PUBLIC KiZwSystemService
942FUNC KiZwSystemService
943    push rbp
944    .pushreg rbp
945    sub rsp, KTRAP_FRAME_LENGTH
946    .allocstack KTRAP_FRAME_LENGTH
947    mov [rsp + KTRAP_FRAME_Rsi], rsi
948    .savereg rsi, KTRAP_FRAME_Rsi
949    mov [rsp + KTRAP_FRAME_Rdi], rdi
950    .savereg rdi, KTRAP_FRAME_Rdi
951    mov rbp, rsp
952    .setframe rbp, 0
953    .endprolog
954
955    /* Get current thread */
956    mov r11, gs:[PcCurrentThread]
957
958    /* Save PreviousMode in the trap frame */
959    mov dil, byte ptr [r11 + KTHREAD_PreviousMode]
960    mov byte ptr [rbp + KTRAP_FRAME_PreviousMode], dil
961
962    /* Save the old trap frame in TrapFrame.Rdx */
963    mov rdi, [r11 + KTHREAD_TrapFrame]
964    mov [rbp + KTRAP_FRAME_Rdx], rdi
965
966    /* Set the new trap frame and previous mode */
967    mov [r11 + ThTrapFrame], rbp
968    mov byte ptr [r11 + KTHREAD_PreviousMode], 0
969
970    /* allocate space for parameters */
971    sub rsp, r10
972    and rsp, HEX(0fffffffffffffff0)
973
974    /* Save rcx */
975    mov [rbp + KTRAP_FRAME_Rcx], rcx
976
977    /* copy parameters to the new location */
978    lea rsi, [rbp + KTRAP_FRAME_LENGTH + 16]
979    lea rdi, [rsp]
980    mov rcx, r10
981    shr rcx, 3
982    rep movsq
983
984    /* Restore rcx */
985    mov rcx, [rbp + KTRAP_FRAME_Rcx]
986
987    /* Call the service function */
988    call rax
989
990    /* Restore the old trap frame */
991    mov r11, gs:[PcCurrentThread]
992    mov rsi, [rbp + KTRAP_FRAME_Rdx]
993    mov [r11 + KTHREAD_TrapFrame], rsi
994
995    /* Restore PreviousMode from the trap frame */
996    mov dil, byte ptr [rbp + KTRAP_FRAME_PreviousMode]
997    mov byte ptr [r11 + KTHREAD_PreviousMode], dil
998
999    /* Restore rdi and rsi */
1000    mov rsi, [rbp + KTRAP_FRAME_Rsi]
1001    mov rdi, [rbp + KTRAP_FRAME_Rdi]
1002
1003    /* Cleanup the stack and return */
1004    lea rsp, [rbp + KTRAP_FRAME_LENGTH]
1005    pop rbp
1006    ret
1007
1008ENDFUNC
1009
1010PUBLIC KiConvertToGuiThread
1011FUNC KiConvertToGuiThread
1012
1013    sub rsp, 40
1014    .allocstack 40
1015    .endprolog
1016
1017    // NewStack = (ULONG_PTR)MmCreateKernelStack(TRUE, 0);
1018    mov cl, 1
1019    xor rdx, rdx
1020    call MmCreateKernelStack
1021
1022    /* Check for failure */
1023    test rax, rax
1024    jz KiConvertToGuiThreadFailed
1025
1026    /* OldStack = KeSwitchKernelStack((PVOID)NewStack, (PVOID)(NewStack - KERNEL_STACK_SIZE)); */
1027    mov rcx, rax
1028    mov rdx, rax
1029    sub rdx, KERNEL_STACK_SIZE
1030    call KeSwitchKernelStack
1031
1032    // MmDeleteKernelStack(OldStack, FALSE);
1033    mov rcx, rax
1034    xor rdx, rdx
1035    call MmDeleteKernelStack
1036
1037    /* Call the worker function */
1038    call PsConvertToGuiThread
1039
1040    /* Check for failure */
1041    test rax, rax
1042    js KiConvertToGuiThreadFailed
1043
1044    /* Disable interrupts for return */
1045    cli
1046
1047    // FIXME: should just do the trap frame switch in KiSystemCallHandler64
1048    /* Restore old trap frame */
1049    mov rcx, gs:[PcCurrentThread]
1050    mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_TrapFrame]
1051    mov [rcx + KTHREAD_TrapFrame], rdx
1052
1053    // Restore register parameters
1054    mov rcx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rip]
1055    mov rdx, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_Rdx]
1056    mov r8, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R8]
1057    mov r9, [rsp + 48 + MAX_SYSCALL_PARAM_SIZE + KTRAP_FRAME_R9]
1058
1059    /* Run KiSystemCallHandler again */
1060    add rsp, 48
1061    jmp KiSystemCall64Again
1062
1063KiConvertToGuiThreadFailed:
1064
1065    /* Clean up the stack and return failure */
1066    add rsp, 40
1067    mov eax, HEX(C0000017) // STATUS_NO_MEMORY
1068    ret
1069
1070ENDFUNC
1071
1072
1073EXTERN KiSetTrapContextInternal:PROC
1074
1075/*
1076 * VOID
1077 * KiSetTrapContext(
1078 *     _Out_ PKTRAP_FRAME TrapFrame,
1079 *     _In_ PCONTEXT Context,
1080 *     _In_ KPROCESSOR_MODE RequestorMode);
1081 */
1082PUBLIC KiSetTrapContext
1083.PROC KiSetTrapContext
1084
1085    /* Generate a KEXCEPTION_FRAME on the stack */
1086    GENERATE_EXCEPTION_FRAME
1087
1088    call KiSetTrapContextInternal
1089
1090    /* Restore the registers from the KEXCEPTION_FRAME */
1091    RESTORE_EXCEPTION_STATE
1092
1093    /* Return */
1094    ret
1095
1096.ENDP
1097
1098
1099/*
1100 * VOID
1101 * KiDeliverApc(
1102 *     _In_ KPROCESSOR_MODE DeliveryMode,
1103 *     _In_ PKEXCEPTION_FRAME ExceptionFrame,
1104 *     _In_ PKTRAP_FRAME TrapFrame);
1105 *
1106 */
1107EXTERN KiDeliverApc:PROC
1108
1109PUBLIC KiInitiateUserApc
1110.PROC KiInitiateUserApc
1111
1112    /* Generate a KEXCEPTION_FRAME on the stack */
1113    GENERATE_EXCEPTION_FRAME
1114
1115    /* Raise IRQL to APC_LEVEL */
1116    mov rax, APC_LEVEL
1117    mov cr8, rax
1118
1119    /* Enable interrupts */
1120    sti
1121
1122    /* Get the current trap frame */
1123    mov rax, gs:[PcCurrentThread]
1124    mov r8, [rax + KTHREAD_TrapFrame]
1125
1126    /* Call the C function */
1127    mov ecx, 1
1128    mov rdx, rsp
1129    call KiDeliverApc
1130
1131    /* Disable interrupts again */
1132    cli
1133
1134    /* Go back to PASSIVE_LEVEL */
1135    mov rax, PASSIVE_LEVEL
1136    mov cr8, rax
1137
1138    /* Restore the registers from the KEXCEPTION_FRAME */
1139    RESTORE_EXCEPTION_STATE
1140
1141    /* Return */
1142    ret
1143
1144.ENDP
1145
1146
1147PUBLIC KiInitializeSegments
1148KiInitializeSegments:
1149    mov ax, KGDT64_R3_DATA or RPL_MASK
1150    mov gs, ax
1151    swapgs
1152    mov gs, ax
1153    ret
1154
1155/*!
1156 * VOID
1157 * KiSwitchKernelStackHelper(
1158 *     LONG_PTR StackOffset,
1159 *     PVOID OldStackBase);
1160 */
1161PUBLIC KiSwitchKernelStackHelper
1162KiSwitchKernelStackHelper:
1163
1164    /* Pop return address from the current stack */
1165    pop rax
1166
1167    /* Switch to new stack */
1168    lea rsp, [rsp + rcx]
1169
1170    /* Push return address on the new stack */
1171    push rax
1172
1173    /* Return on new stack */
1174    mov rax, rdx
1175    ret
1176
1177EXTERN KiSwitchKernelStack:PROC
1178
1179PUBLIC KeSwitchKernelStack
1180FUNC KeSwitchKernelStack
1181
1182    sub rsp, 40
1183    .allocstack 40
1184
1185    /* Save rcx */
1186    mov [rsp], rcx
1187    .savereg rcx, 0
1188    .endprolog
1189
1190    /* Call the C handler, which returns the old stack in rax */
1191    call KiSwitchKernelStack
1192
1193    /* Restore rcx (StackBase) */
1194    mov rcx, [rsp]
1195
1196    /* Switch to new stack: RSP += (StackBase - OldStackBase) */
1197    sub rcx, rax
1198    add rsp, rcx
1199
1200    /* Deallocate the home frame */
1201    add rsp, 40
1202    ret
1203
1204ENDFUNC
1205
1206
1207
1208
1209#ifdef _MSC_VER
1210#undef lgdt
1211#undef lidt
1212
1213//void __lgdt(void *Source);
1214PUBLIC __lgdt
1215__lgdt:
1216    lgdt fword ptr [rcx]
1217    ret
1218
1219//void __sgdt(void *Destination);
1220PUBLIC __sgdt
1221__sgdt:
1222    sgdt fword ptr [rcx]
1223    ret
1224
1225// void __lldt(unsigned short Value)
1226PUBLIC __lldt
1227__lldt:
1228    lldt cx
1229    ret
1230
1231//void __sldt(void *Destination);
1232PUBLIC __sldt
1233__sldt:
1234    sldt word ptr [rcx]
1235    ret
1236
1237//void __ltr(unsigned short Source);
1238PUBLIC __ltr
1239__ltr:
1240    ltr cx
1241    ret
1242
1243//void __str(unsigned short *Destination);
1244PUBLIC __str
1245__str:
1246    str word ptr [rcx]
1247    ret
1248
1249PUBLIC __swapgs
1250__swapgs:
1251    swapgs
1252    ret
1253
1254#endif
1255
1256END
1257