2 * FILE: ntoskrnl/ke/i386/trap.S
3 * COPYRIGHT: See COPYING in the top level directory
4 * PURPOSE: System Traps, Entrypoints and Exitpoints
5 * PROGRAMMER: Alex Ionescu (alex@relsoft.net)
6 * NOTE: See asmmacro.S for the shared entry/exit code.
9 /* INCLUDES ******************************************************************/
12 #include <internal/i386/asmmacro.S>
13 .intel_syntax noprefix
15 /* GLOBALS ******************************************************************/
19 /* This is the Software Interrupt Table that we handle in this file: */
20 idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
21 idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
22 idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
23 idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
24 idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
25 idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
26 idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
27 idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
28 idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
29 idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
30 idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
31 idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
32 idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
33 idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
34 idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
35 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
36 idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
37 idt _KiTrap17, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
38 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
39 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
41 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
43 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
44 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
45 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
46 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
47 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
48 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
49 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
51 /* System call entrypoints: */
52 .globl _KiFastCallEntry
53 .globl _KiSystemService
55 /* And special system-defined software traps: */
56 .globl _NtRaiseException@12
59 /* We implement the following trap exit points: */
60 .globl _KiServiceExit /* Exit from syscall */
61 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
62 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
63 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
65 .globl _KiIdtDescriptor
70 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
80 /* Enter the shared system call prolog */
83 /* Jump to the actual handler */
94 /* Set DS/ES to Kernel Selector */
99 /* Set the current stack to Kernel Stack */
100 mov ecx, [fs:KPCR_TSS]
101 mov esp, ss:[ecx+KTSS_ESP0]
103 /* Set up a fake INT Stack. */
104 push KGDT_R3_DATA + RPL_MASK
105 push edx /* Ring 3 SS:ESP */
106 pushf /* Ring 3 EFLAGS */
107 push 2 /* Ring 0 EFLAGS */
108 add edx, 8 /* Skip user parameter list */
109 popf /* Set our EFLAGS */
110 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
111 push KGDT_R3_CODE + RPL_MASK
112 push KUSER_SHARED_SYSCALL_RET
114 /* Setup the Trap Frame stack */
120 push KGDT_R3_TEB + RPL_MASK
122 /* Save pointer to our PCR */
123 mov ebx, [fs:KPCR_SELF]
125 /* Get a pointer to the current thread */
126 mov esi, [ebx+KPCR_CURRENT_THREAD]
128 /* Set the exception handler chain terminator */
129 push [ebx+KPCR_EXCEPTION_LIST]
130 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
132 /* Use the thread's stack */
133 mov ebp, [esi+KTHREAD_INITIAL_STACK]
135 /* Push previous mode */
138 /* Skip the other registers */
141 /* Hack: it seems that on VMWare someone damages ES/DS on exit. Investigate! */
142 mov dword ptr [esp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
143 mov dword ptr [esp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
145 /* Make space for us on the stack */
148 /* Write the previous mode */
149 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
156 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
158 /* Check if the thread was being debugged */
159 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
161 /* Set the thread's trap frame */
162 mov [esi+KTHREAD_TRAP_FRAME], ebp
164 /* Save DR registers if needed */
165 //jnz Dr_FastCallDrSave
167 /* Set the trap frame debug header */
170 #ifdef DBG // FIXME: Is this for GDB? Can it be moved in the stub?
172 * We want to know the address from where the syscall stub was called.
173 * If PrevMode is KernelMode, that address is stored in our own (kernel)
174 * stack, at location KTRAP_FRAME_ESP.
175 * If we're coming from UserMode, we load the usermode stack pointer
176 * and go back two frames (first frame is the syscall stub, second call
177 * is the caller of the stub).
179 mov edi, [ebp+KTRAP_FRAME_ESP]
180 test byte ptr [esi+KTHREAD_PREVIOUS_MODE], 0x01
184 mov [ebp+KTRAP_FRAME_DEBUGEIP], edi
187 /* Enable interrupts */
193 * Find out which table offset to use. Converts 0x1124 into 0x10.
194 * The offset is related to the Table Index as such: Offset = TableIndex x 10
197 shr edi, SERVICE_TABLE_SHIFT
198 and edi, SERVICE_TABLE_MASK
201 /* Now add the thread's base system table to the offset */
202 add edi, [esi+KTHREAD_SERVICE_TABLE]
204 /* Get the true syscall ID and check it */
206 and eax, SERVICE_NUMBER_MASK
207 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
209 /* Invalid ID, try to load Win32K Table */
210 jnb KiBBTUnexpectedRange
212 #if 0 // <== Disabled for two reasons: We don't save TEB in 0x18, but KPCR.
213 // <== We don't have a KeGdiFlushUserBatch callback yet (needs to be
214 // sent through the PsInitializeWin32Callouts structure)
215 /* Check if this was Win32K */
216 cmp ecx, SERVICE_TABLE_TEST
220 mov ecx, [fs:KPCR_TEB]
222 /* Check if we should flush the User Batch */
224 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
230 call [_KeGdiFlushUserBatch]
236 /* Increase total syscall count */
237 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
240 /* Increase per-syscall count */
241 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
243 inc dword ptr [ecx+eax*4]
246 /* Users's current stack frame pointer is source */
250 /* Allocate room for argument list from kernel stack */
251 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
255 /* Get pointer to function */
256 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
259 /* Allocate space on our stack */
262 /* Set the size of the arguments and the destination */
266 /* Make sure we're within the User Probe Address */
267 cmp esi, _MmUserProbeAddress
271 /* Copy the parameters */
276 * The following lines are for the benefit of GDB. It will see the return
277 * address of the "call ebx" below, find the last label before it and
278 * thinks that that's the start of the function. It will then check to see
279 * if it starts with a standard function prolog (push ebp, mov ebp,esp1).
280 * When that standard function prolog is not found, it will stop the
281 * stack backtrace. Since we do want to backtrace into usermode, let's
282 * make GDB happy and create a standard prolog.
290 /* Do the System Call */
295 /* Make sure the user-mode call didn't return at elevated IRQL */
296 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
298 mov esi, eax /* We need to save the syscall's return val */
299 call _KeGetCurrentIrql@0
302 mov eax, esi /* Restore it */
304 /* Get our temporary current thread pointer for sanity check */
305 mov ecx, fs:[KPCR_CURRENT_THREAD]
307 /* Make sure that we are not attached and that APCs are not disabled */
308 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
311 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
318 /* Deallocate the kernel stack frame */
321 KeReturnFromSystemCall:
323 /* Get the Current Thread */
324 mov ecx, [fs:KPCR_CURRENT_THREAD]
326 /* Restore the old trap frame pointer */
327 mov edx, [ebp+KTRAP_FRAME_EDX]
328 mov [ecx+KTHREAD_TRAP_FRAME], edx
333 /* Disable interrupts */
336 /* Check for, and deliver, User-Mode APCs if needed */
337 CHECK_FOR_APC_DELIVER 1
339 /* Hack for VMWare: Sometimes ES/DS seem to be invalid when returning to user-mode. Investigate! */
340 mov es, [ebp+KTRAP_FRAME_ES]
341 mov ds, [ebp+KTRAP_FRAME_DS]
343 /* Exit and cleanup */
344 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
347 KiBBTUnexpectedRange:
349 /* If this isn't a Win32K call, fail */
350 cmp ecx, SERVICE_TABLE_TEST
353 /* Set up Win32K Table */
356 call _PsConvertToGuiThread@0
358 /* Check return code */
361 /* Restore registers */
365 /* Reset trap frame address */
367 mov [esi+KTHREAD_TRAP_FRAME], ebp
369 /* Try the Call again, if we suceeded */
373 * The Shadow Table should have a special byte table which tells us
374 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
377 /* Get the table limit and base */
378 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
379 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
380 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
382 /* Get the table address and add our index into the array */
384 and eax, SERVICE_NUMBER_MASK
387 /* Find out what we should return */
388 movsx eax, byte ptr [edx]
391 /* Return either 0 or -1, we've set it in EAX */
392 jle KeReturnFromSystemCall
394 /* Set STATUS_INVALID_SYSTEM_SERVICE */
395 mov eax, STATUS_INVALID_SYSTEM_SERVICE
396 jmp KeReturnFromSystemCall
400 /* Invalid System Call */
401 mov eax, STATUS_INVALID_SYSTEM_SERVICE
402 jmp KeReturnFromSystemCall
406 /* Check if this came from kernel-mode */
407 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
409 /* It's fine, go ahead with it */
412 /* Caller sent invalid parameters, fail here */
413 mov eax, STATUS_ACCESS_VIOLATION
418 /* Restore ESP0 stack */
419 mov ecx, [fs:KPCR_TSS]
420 mov esp, ss:[ecx+KTSS_ESP0]
422 /* Generate V86M Stack for Trap 6 */
428 /* Generate interrupt stack for Trap 6 */
429 push KGDT_R3_DATA + RPL_MASK
432 push KGDT_R3_CODE + RPL_MASK
438 /* Save current IRQL */
441 /* Set us at passive */
442 mov dword ptr fs:[KPCR_IRQL], 0
450 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
451 call _KeBugCheckEx@20
455 /* Get the index and APC state */
456 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
457 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
464 push APC_INDEX_MISMATCH
465 call _KeBugCheckEx@20
472 /* Disable interrupts */
475 /* Check for, and deliver, User-Mode APCs if needed */
476 CHECK_FOR_APC_DELIVER 0
478 /* Exit and cleanup */
479 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
482 .func Kei386EoiHelper@0
485 /* Disable interrupts */
488 /* Check for, and deliver, User-Mode APCs if needed */
489 CHECK_FOR_APC_DELIVER 0
491 /* Exit and cleanup */
492 _Kei386EoiHelper2ndEntry:
493 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
497 /* Move to EDX position */
498 add esp, KTRAP_FRAME_EDX
500 /* Restore volatiles */
505 /* Move to non-volatiles */
506 lea esp, [ebp+KTRAP_FRAME_EDI]
512 /* Skip error code and return */
517 /* Not yet supported */
523 /* Push error code */
529 /* Increase EIP so we skip the INT3 */
530 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
532 /* Call debug service dispatcher */
533 mov eax, [ebp+KTRAP_FRAME_EAX]
534 mov ecx, [ebp+KTRAP_FRAME_ECX]
535 mov edx, [ebp+KTRAP_FRAME_EAX]
537 /* Check for V86 mode */
538 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
541 /* Check if this is kernel or user-mode */
542 test byte ptr [ebp+KTRAP_FRAME_CS], 1
544 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
547 /* Re-enable interrupts */
551 /* Call the debug routine */
560 call _KdpServiceDispatcher@12
564 /* Get the current process */
565 mov ebx, [fs:KPCR_CURRENT_THREAD]
566 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
568 /* Check if this is a VDM Process */
569 //cmp dword ptr [ebx+KPROCESS_VDM_OBJECTS], 0
572 /* Exit through common routine */
573 jmp _Kei386EoiHelper@0
576 .func NtRaiseException@12
577 _NtRaiseException@12:
579 /* NOTE: We -must- be called by Zw* to have the right frame! */
580 /* Push the stack frame */
583 /* Get the current thread and restore its trap frame */
584 mov ebx, [fs:KPCR_CURRENT_THREAD]
585 mov edx, [ebp+KTRAP_FRAME_EDX]
586 mov [ebx+KTHREAD_TRAP_FRAME], edx
588 /* Set up stack frame */
591 /* Get the Trap Frame in EBX */
594 /* Get the exception list and restore */
595 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
596 mov [fs:KPCR_EXCEPTION_LIST], eax
598 /* Get the parameters */
599 mov edx, [ebp+16] /* Search frames */
600 mov ecx, [ebp+12] /* Context */
601 mov eax, [ebp+8] /* Exception Record */
603 /* Raise the exception */
609 call _KiRaiseException@20
611 /* Restore trap frame in EBP */
615 /* Check the result */
619 /* Restore debug registers too */
626 /* NOTE: We -must- be called by Zw* to have the right frame! */
627 /* Push the stack frame */
630 /* Get the current thread and restore its trap frame */
631 mov ebx, [fs:KPCR_CURRENT_THREAD]
632 mov edx, [ebp+KTRAP_FRAME_EDX]
633 mov [ebx+KTHREAD_TRAP_FRAME], edx
635 /* Set up stack frame */
638 /* Save the parameters */
642 /* Call KiContinue */
648 /* Check if we failed (bad context record) */
652 /* Check if test alert was requested */
653 cmp dword ptr [ebp+12], 0
656 /* Test alert for the thread */
657 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
659 call _KeTestAlertThread@4
662 /* Return to previous context */
673 /* EXCEPTION DISPATCHERS *****************************************************/
675 .func CommonDispatchException
676 _CommonDispatchException:
678 /* Make space for an exception record */
679 sub esp, EXCEPTION_RECORD_LENGTH
682 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
684 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
685 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
686 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
687 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
689 /* Check parameter count */
693 /* Get information */
694 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
701 /* Set the record in ECX and check if this was V86 */
703 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
712 /* Calculate the previous mode */
713 mov eax, [ebp+KTRAP_FRAME_CS]
717 /* Dispatch the exception */
723 call _KiDispatchException@20
726 jmp _Kei386EoiHelper@0
729 .func DispatchNoParam
731 /* Call the common dispatcher */
733 call _CommonDispatchException
736 .func DispatchOneParam
738 /* Call the common dispatcher */
741 call _CommonDispatchException
744 .func DispatchTwoParam
746 /* Call the common dispatcher */
749 call _CommonDispatchException
752 /* HARDWARE TRAP HANDLERS ****************************************************/
756 /* Push error code */
763 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
766 /* Check if the frame was from kernelmode */
767 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
770 /* Check the old mode */
771 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
775 /* Re-enable interrupts for user-mode and send the exception */
777 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
778 mov ebx, [ebp+KTRAP_FRAME_EIP]
782 /* Check if this is a VDM process */
783 mov ebx, [fs:KPCR_CURRENT_THREAD]
784 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
785 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
788 /* We don't support this yet! */
795 /* Push error code */
802 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
805 /* Check if the frame was from kernelmode */
806 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
809 /* Check the old mode */
810 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
814 /* Enable interrupts for user-mode */
818 /* Prepare the exception */
819 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
820 mov ebx, [ebp+KTRAP_FRAME_EIP]
821 mov eax, STATUS_SINGLE_STEP
825 /* Check if this is a VDM process */
826 mov ebx, [fs:KPCR_CURRENT_THREAD]
827 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
828 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
831 /* We don't support VDM! */
838 /* FIXME: This is an NMI, nothing like a normal exception */
840 jmp _KiSystemFatalException
845 /* Push error code */
852 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
855 /* Check if the frame was from kernelmode */
856 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
859 /* Check the old mode */
860 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
864 /* Enable interrupts for user-mode */
868 /* Prepare the exception */
873 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
874 mov ebx, [ebp+KTRAP_FRAME_EIP]
876 mov eax, STATUS_BREAKPOINT
878 call _CommonDispatchException
881 /* Check if this is a VDM process */
882 mov ebx, [fs:KPCR_CURRENT_THREAD]
883 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
884 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
887 /* We don't support VDM! */
893 /* Push error code */
900 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
903 /* Check if the frame was from kernelmode */
904 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
907 /* Check the old mode */
908 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
912 /* Re-enable interrupts for user-mode and send the exception */
914 mov eax, STATUS_INTEGER_OVERFLOW
915 mov ebx, [ebp+KTRAP_FRAME_EIP]
920 /* Check if this is a VDM process */
921 mov ebx, [fs:KPCR_CURRENT_THREAD]
922 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
923 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
926 /* We don't support this yet! */
933 /* Push error code */
940 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
943 /* Check if the frame was from kernelmode */
944 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
947 /* It did, and this should never happen */
949 jmp _KiSystemFatalException
951 /* Check the old mode */
953 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
956 /* Re-enable interrupts for user-mode and send the exception */
959 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
960 mov ebx, [ebp+KTRAP_FRAME_EIP]
964 /* Check if this is a VDM process */
965 mov ebx, [fs:KPCR_CURRENT_THREAD]
966 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
967 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
970 /* We don't support this yet! */
977 /* Push error code */
983 /* Call the C exception handler */
989 /* Check for v86 recovery */
992 /* Return to caller */
993 jne _Kei386EoiHelper@0
999 /* Push error code */
1005 /* Get the current thread and stack */
1007 mov eax, [fs:KPCR_CURRENT_THREAD]
1008 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1009 sub ecx, NPX_FRAME_LENGTH
1011 /* Check if emulation is enabled */
1012 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1013 jnz EmulationEnabled
1016 /* Check if the NPX state is loaded */
1017 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1022 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1025 /* Check the NPX thread */
1026 mov edx, [fs:KPCR_NPX_THREAD]
1030 /* Get the NPX Stack */
1031 mov esi, [edx+KTHREAD_INITIAL_STACK]
1032 sub esi, NPX_FRAME_LENGTH
1034 /* Check if we have FXSR and check which operand to use */
1035 test byte ptr _KeI386FxsrPresent, 1
1044 /* Set the thread's state to dirty */
1045 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1048 /* Check if we have FXSR and choose which operand to use */
1049 test byte ptr _KeI386FxsrPresent, 1
1058 /* Set state loaded */
1059 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1060 mov [fs:KPCR_NPX_THREAD], eax
1062 /* Enable interrupts to happen now */
1066 /* Check if CR0 needs to be reloaded due to a context switch */
1067 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1068 jz _Kei386EoiHelper@0
1070 /* We have to reload CR0... disable interrupts */
1073 /* Get CR0 and update it */
1075 or ebx, [ecx+FN_CR0_NPX_STATE]
1078 /* Restore interrupts and check if TS is back on */
1081 jz _Kei386EoiHelper@0
1083 /* Clear TS, and loop handling again */
1089 /* Check if TS is set */
1091 jnz TsSetOnLoadedState
1093 /* Check if the trap came from user-mode */
1097 /* Did this come from kernel-mode? */
1098 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1101 /* It came from user-mode, so this would only be valid inside a VDM */
1102 /* Since we don't actually have VDMs in ROS, bugcheck. */
1106 /* TS shouldn't be set, unless this we don't have a Math Processor */
1110 /* Strange that we got a trap at all, but ignore and continue */
1112 jmp _Kei386EoiHelper@0
1115 /* Cause a bugcheck */
1121 push TRAP_CAUSE_UNKNOWN
1122 call _KeBugCheckEx@20
1125 /* Cause a bugcheck */
1130 push TRAP_CAUSE_UNKNOWN
1131 call _KeBugCheckEx@20
1138 /* Can't really do too much */
1140 jmp _KiSystemFatalException
1145 /* Push error code */
1151 /* Enable interrupts and bugcheck */
1154 jmp _KiSystemFatalException
1163 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1166 /* Check if the frame was from kernelmode */
1167 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1171 /* Check if OF was set during iretd */
1172 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1176 /* It was, just mask it out */
1177 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1178 jmp _Kei386EoiHelper@0
1181 /* TSS failure for some other reason: crash */
1183 jmp _KiSystemFatalException
1191 /* FIXME: ROS Doesn't handle segment faults yet */
1193 jmp _KiSystemFatalException
1201 /* FIXME: ROS Doesn't handle stack faults yet */
1203 jmp _KiSystemFatalException
1211 /* Call the C exception handler */
1217 /* Check for v86 recovery */
1220 /* Return to caller */
1221 jne _Kei386EoiHelper@0
1230 /* Call the C exception handler */
1233 call _KiPageFaultHandler
1236 /* Return to caller */
1237 jmp _Kei386EoiHelper@0
1242 /* Push error code */
1249 /* Raise a fatal exception */
1251 jmp _KiSystemFatalException
1256 /* Push error code */
1262 /* FIXME: ROS Doesn't handle FPU faults yet */
1264 jmp _KiSystemFatalException
1269 /* Push error code */
1275 /* FIXME: ROS Doesn't handle alignment faults yet */
1277 jmp _KiSystemFatalException
1280 .func KiSystemFatalException
1281 _KiSystemFatalException:
1283 /* Push the trap frame */
1286 /* Push empty parameters */
1291 /* Push trap number and bugcheck code */
1293 push UNEXPECTED_KERNEL_MODE_TRAP
1294 call _KeBugCheckWithTf@24
1298 /* INTERRUPT HANDLERS ********************************************************/
1300 .globl _KiStartUnexpected
1303 GENERATE_INT_HANDLERS
1306 jmp _KiUnexpectedInterruptTail
1308 .func KiUnexpectedInterruptTail
1309 _KiUnexpectedInterruptTail:
1311 /* Enter interrupt trap */
1312 INT_PROLOG kui, DoNotPushFakeErrorCode
1314 /* Increase interrupt count */
1315 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1317 /* Put vector in EBX and make space for KIRQL */
1321 /* Begin interrupt */
1325 call _HalBeginSystemInterrupt@12
1327 /* Check if it was spurious or not */
1331 /* Spurious, ignore it */
1333 jmp _Kei386EoiHelper2ndEntry
1336 /* Unexpected, exit the interrupt */
1339 call _HalEndSystemInterrupt@8
1340 jmp _Kei386EoiHelper@0
1343 .globl _KiUnexpectedInterrupt
1344 _KiUnexpectedInterrupt:
1346 /* Bugcheck with invalid interrupt code */