- Don't do fast system calls with the wrong DS/ES selectors.
[reactos.git] / reactos / ntoskrnl / ke / i386 / trap.s
1 /*
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.
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <asm.h>
12 #include <internal/i386/asmmacro.S>
13 .intel_syntax noprefix
14
15 /* GLOBALS *******************************************************************/
16
17 .globl _KiIdt
18 _KiIdt:
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) */
40 .rept 22
41 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
42 .endr
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 */
50
51 /* System call entrypoints: */
52 .globl _KiFastCallEntry
53 .globl _KiSystemService
54
55 /* And special system-defined software traps: */
56 .globl _NtRaiseException@12
57 .globl _NtContinue@8
58
59 /* Interrupt template entrypoints */
60 .globl _KiInterruptTemplate
61 .globl _KiInterruptTemplateObject
62 .globl _KiInterruptTemplateDispatch
63
64 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
65 .globl _KiChainedDispatch2ndLvl@0
66 .globl _KiInterruptDispatch@0
67 .globl _KiChainedDispatch@0
68
69 /* We implement the following trap exit points: */
70 .globl _KiServiceExit /* Exit from syscall */
71 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
72 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
73 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
74
75 .globl _KiIdtDescriptor
76 _KiIdtDescriptor:
77 .short 0x800
78 .long _KiIdt
79
80 .globl _KiUnexpectedEntrySize
81 _KiUnexpectedEntrySize:
82 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
83
84 _UnexpectedMsg:
85 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
86
87 Broken:
88 .asciz "\n\x7\x7!!! Broken TrapFrame. Magic: %08lx MagicB: %08lx!!!\n"
89
90 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
91
92 _KiGetTickCount:
93 _KiCallbackReturn:
94 _KiRaiseAssertion:
95 int 3
96
97 .func KiSystemService
98 _KiSystemService:
99
100 /* Enter the shared system call prolog */
101 SYSCALL_PROLOG
102
103 /* Jump to the actual handler */
104 jmp SharedCode
105 .endfunc
106
107 .func KiFastCallEntry
108 _KiFastCallEntry:
109
110 /* Set FS to PCR */
111 mov ecx, KGDT_R0_PCR
112 mov fs, cx
113
114 /* Set DS/ES to User Selector */
115 mov ecx, KGDT_R3_DATA | RPL_MASK
116 mov ds, cx
117 mov es, cx
118
119 /* Set the current stack to Kernel Stack */
120 mov ecx, [fs:KPCR_TSS]
121 mov esp, ss:[ecx+KTSS_ESP0]
122
123 /* Set up a fake INT Stack. */
124 push KGDT_R3_DATA + RPL_MASK
125 push edx /* Ring 3 SS:ESP */
126 pushf /* Ring 3 EFLAGS */
127 push 2 /* Ring 0 EFLAGS */
128 add edx, 8 /* Skip user parameter list */
129 popf /* Set our EFLAGS */
130 or dword ptr [esp], EFLAGS_INTERRUPT_MASK /* Re-enable IRQs in EFLAGS, to fake INT */
131 push KGDT_R3_CODE + RPL_MASK
132 push KUSER_SHARED_SYSCALL_RET
133
134 /* Setup the Trap Frame stack */
135 push 0
136 push ebp
137 push ebx
138 push esi
139 push edi
140 push KGDT_R3_TEB + RPL_MASK
141
142 /* Save pointer to our PCR */
143 mov ebx, [fs:KPCR_SELF]
144
145 /* Get a pointer to the current thread */
146 mov esi, [ebx+KPCR_CURRENT_THREAD]
147
148 /* Set the exception handler chain terminator */
149 push [ebx+KPCR_EXCEPTION_LIST]
150 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
151
152 /* Use the thread's stack */
153 mov ebp, [esi+KTHREAD_INITIAL_STACK]
154
155 /* Push previous mode */
156 push UserMode
157
158 /* Skip the other registers */
159 sub esp, 0x48
160
161 /* Make space for us on the stack */
162 sub ebp, 0x29C
163
164 /* Write the previous mode */
165 mov byte ptr [esi+KTHREAD_PREVIOUS_MODE], UserMode
166
167 /* Sanity check */
168 cmp ebp, esp
169 jnz BadStack
170
171 /* Flush DR7 */
172 and dword ptr [ebp+KTRAP_FRAME_DR7], 0
173
174 /* Check if the thread was being debugged */
175 test byte ptr [esi+KTHREAD_DEBUG_ACTIVE], 0xFF
176
177 /* Set the thread's trap frame */
178 mov [esi+KTHREAD_TRAP_FRAME], ebp
179
180 /* Save DR registers if needed */
181 //jnz Dr_FastCallDrSave
182
183 /* Set the trap frame debug header */
184 SET_TF_DEBUG_HEADER
185
186 /* Enable interrupts */
187 sti
188
189 SharedCode:
190
191 /*
192 * Find out which table offset to use. Converts 0x1124 into 0x10.
193 * The offset is related to the Table Index as such: Offset = TableIndex x 10
194 */
195 mov edi, eax
196 shr edi, SERVICE_TABLE_SHIFT
197 and edi, SERVICE_TABLE_MASK
198 mov ecx, edi
199
200 /* Now add the thread's base system table to the offset */
201 add edi, [esi+KTHREAD_SERVICE_TABLE]
202
203 /* Get the true syscall ID and check it */
204 mov ebx, eax
205 and eax, SERVICE_NUMBER_MASK
206 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
207
208 /* Invalid ID, try to load Win32K Table */
209 jnb KiBBTUnexpectedRange
210
211 /* Check if this was Win32K */
212 cmp ecx, SERVICE_TABLE_TEST
213 jnz NotWin32K
214
215 /* Get the TEB */
216 mov ecx, [fs:KPCR_TEB]
217
218 /* Check if we should flush the User Batch */
219 xor ebx, ebx
220 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
221 jz NotWin32K
222
223 /* Flush it */
224 push edx
225 push eax
226 //call [_KeGdiFlushUserBatch]
227 pop eax
228 pop edx
229
230 NotWin32K:
231 /* Increase total syscall count */
232 inc dword ptr fs:[KPCR_SYSTEM_CALLS]
233
234 #ifdef DBG
235 /* Increase per-syscall count */
236 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
237 jecxz NoCountTable
238 inc dword ptr [ecx+eax*4]
239 #endif
240
241 /* Users's current stack frame pointer is source */
242 NoCountTable:
243 mov esi, edx
244
245 /* Allocate room for argument list from kernel stack */
246 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
247 xor ecx, ecx
248 mov cl, [eax+ebx]
249
250 /* Get pointer to function */
251 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
252 mov ebx, [edi+eax*4]
253
254 /* Allocate space on our stack */
255 sub esp, ecx
256
257 /* Set the size of the arguments and the destination */
258 shr ecx, 2
259 mov edi, esp
260
261 /* Make sure we're within the User Probe Address */
262 cmp esi, _MmUserProbeAddress
263 jnb AccessViolation
264
265 CopyParams:
266 /* Copy the parameters */
267 rep movsd
268
269 #ifdef DBG
270 /*
271 * The following lines are for the benefit of GDB. It will see the return
272 * address of the "call ebx" below, find the last label before it and
273 * thinks that that's the start of the function. It will then check to see
274 * if it starts with a standard function prolog (push ebp, mov ebp,esp1).
275 * When that standard function prolog is not found, it will stop the
276 * stack backtrace. Since we do want to backtrace into usermode, let's
277 * make GDB happy and create a standard prolog.
278 */
279 KiSystemService:
280 push ebp
281 mov ebp,esp
282 pop ebp
283 #endif
284
285 /* Do the System Call */
286 call ebx
287
288 AfterSysCall:
289 #ifdef DBG
290 /* Make sure the user-mode call didn't return at elevated IRQL */
291 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
292 jz SkipCheck
293 mov esi, eax /* We need to save the syscall's return val */
294 call _KeGetCurrentIrql@0
295 or al, al
296 jnz InvalidIrql
297 mov eax, esi /* Restore it */
298
299 /* Get our temporary current thread pointer for sanity check */
300 mov ecx, fs:[KPCR_CURRENT_THREAD]
301
302 /* Make sure that we are not attached and that APCs are not disabled */
303 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
304 or dl, dl
305 jnz InvalidIndex
306 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
307 or edx, edx
308 jnz InvalidIndex
309 #endif
310
311 SkipCheck:
312
313 /* Deallocate the kernel stack frame */
314 mov esp, ebp
315
316 KeReturnFromSystemCall:
317
318 /* Get the Current Thread */
319 mov ecx, [fs:KPCR_CURRENT_THREAD]
320
321 /* Restore the old trap frame pointer */
322 mov edx, [ebp+KTRAP_FRAME_EDX]
323 mov [ecx+KTHREAD_TRAP_FRAME], edx
324 .endfunc
325
326 .func KiServiceExit
327 _KiServiceExit:
328 /* Disable interrupts */
329 cli
330
331 /* Check for, and deliver, User-Mode APCs if needed */
332 CHECK_FOR_APC_DELIVER 1
333
334 /* Exit and cleanup */
335 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
336 .endfunc
337
338 KiBBTUnexpectedRange:
339
340 /* If this isn't a Win32K call, fail */
341 cmp ecx, SERVICE_TABLE_TEST
342 jne InvalidCall
343
344 /* Set up Win32K Table */
345 push edx
346 push ebx
347 call _PsConvertToGuiThread@0
348
349 /* Check return code */
350 or eax, eax
351
352 /* Restore registers */
353 pop eax
354 pop edx
355
356 /* Reset trap frame address */
357 mov ebp, esp
358 mov [esi+KTHREAD_TRAP_FRAME], ebp
359
360 /* Try the Call again, if we suceeded */
361 jz SharedCode
362
363 /*
364 * The Shadow Table should have a special byte table which tells us
365 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
366 */
367
368 /* Get the table limit and base */
369 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
370 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
371 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
372
373 /* Get the table address and add our index into the array */
374 lea edx, [edx+ecx*4]
375 and eax, SERVICE_NUMBER_MASK
376 add edx, eax
377
378 /* Find out what we should return */
379 movsx eax, byte ptr [edx]
380 or eax, eax
381
382 /* Return either 0 or -1, we've set it in EAX */
383 jle KeReturnFromSystemCall
384
385 /* Set STATUS_INVALID_SYSTEM_SERVICE */
386 mov eax, STATUS_INVALID_SYSTEM_SERVICE
387 jmp KeReturnFromSystemCall
388
389 InvalidCall:
390
391 /* Invalid System Call */
392 mov eax, STATUS_INVALID_SYSTEM_SERVICE
393 jmp KeReturnFromSystemCall
394
395 AccessViolation:
396
397 /* Check if this came from kernel-mode */
398 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
399
400 /* It's fine, go ahead with it */
401 jz CopyParams
402
403 /* Caller sent invalid parameters, fail here */
404 mov eax, STATUS_ACCESS_VIOLATION
405 jmp AfterSysCall
406
407 BadStack:
408
409 /* Restore ESP0 stack */
410 mov ecx, [fs:KPCR_TSS]
411 mov esp, ss:[ecx+KTSS_ESP0]
412
413 /* Generate V86M Stack for Trap 6 */
414 push 0
415 push 0
416 push 0
417 push 0
418
419 /* Generate interrupt stack for Trap 6 */
420 push KGDT_R3_DATA + RPL_MASK
421 push 0
422 push 0x20202
423 push KGDT_R3_CODE + RPL_MASK
424 push 0
425 jmp _KiTrap6
426
427 #ifdef DBG
428 InvalidIrql:
429 /* Save current IRQL */
430 push fs:[KPCR_IRQL]
431
432 /* Set us at passive */
433 mov dword ptr fs:[KPCR_IRQL], 0
434 cli
435
436 /* Bugcheck */
437 push 0
438 push 0
439 push eax
440 push ebx
441 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
442 call _KeBugCheckEx@20
443
444 InvalidIndex:
445
446 /* Get the index and APC state */
447 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
448 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
449
450 /* Bugcheck */
451 push 0
452 push edx
453 push eax
454 push ebx
455 push APC_INDEX_MISMATCH
456 call _KeBugCheckEx@20
457 ret
458 #endif
459
460 .func KiServiceExit2
461 _KiServiceExit2:
462
463 /* Disable interrupts */
464 cli
465
466 /* Check for, and deliver, User-Mode APCs if needed */
467 CHECK_FOR_APC_DELIVER 0
468
469 /* Exit and cleanup */
470 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
471 .endfunc
472
473 .func Kei386EoiHelper@0
474 _Kei386EoiHelper@0:
475
476 /* Disable interrupts */
477 cli
478
479 /* Check for, and deliver, User-Mode APCs if needed */
480 CHECK_FOR_APC_DELIVER 0
481
482 /* Exit and cleanup */
483 _Kei386EoiHelper2ndEntry:
484 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
485 .endfunc
486
487 V86_Exit:
488 /* Move to EDX position */
489 add esp, KTRAP_FRAME_EDX
490
491 /* Restore volatiles */
492 pop edx
493 pop ecx
494 pop eax
495
496 /* Move to non-volatiles */
497 lea esp, [ebp+KTRAP_FRAME_EDI]
498 pop edi
499 pop esi
500 pop ebx
501 pop ebp
502
503 /* Skip error code and return */
504 add esp, 4
505 iret
506
507 AbiosExit:
508 /* Not yet supported */
509 int 3
510
511 .func KiDebugService
512 _KiDebugService:
513
514 /* Push error code */
515 push 0
516
517 /* Enter trap */
518 TRAP_PROLOG(kids)
519
520 /* Increase EIP so we skip the INT3 */
521 //inc dword ptr [ebp+KTRAP_FRAME_EIP]
522
523 /* Call debug service dispatcher */
524 mov eax, [ebp+KTRAP_FRAME_EAX]
525 mov ecx, [ebp+KTRAP_FRAME_ECX]
526 mov edx, [ebp+KTRAP_FRAME_EAX]
527
528 /* Check for V86 mode */
529 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
530 jnz NotUserMode
531
532 /* Check if this is kernel or user-mode */
533 test byte ptr [ebp+KTRAP_FRAME_CS], 1
534 jz CallDispatch
535 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
536 jnz NotUserMode
537
538 /* Re-enable interrupts */
539 VdmProc:
540 sti
541
542 /* Call the debug routine */
543 CallDispatch:
544 mov esi, ecx
545 mov edi, edx
546 mov edx, eax
547 mov ecx, 3
548 push edi
549 push esi
550 push edx
551 call _KdpServiceDispatcher@12
552
553 NotUserMode:
554
555 /* Get the current process */
556 mov ebx, [fs:KPCR_CURRENT_THREAD]
557 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
558
559 /* Check if this is a VDM Process */
560 //cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
561 //jz VdmProc
562
563 /* Exit through common routine */
564 jmp _Kei386EoiHelper@0
565 .endfunc
566
567 .func NtRaiseException@12
568 _NtRaiseException@12:
569
570 /* NOTE: We -must- be called by Zw* to have the right frame! */
571 /* Push the stack frame */
572 push ebp
573
574 /* Get the current thread and restore its trap frame */
575 mov ebx, [fs:KPCR_CURRENT_THREAD]
576 mov edx, [ebp+KTRAP_FRAME_EDX]
577 mov [ebx+KTHREAD_TRAP_FRAME], edx
578
579 /* Set up stack frame */
580 mov ebp, esp
581
582 /* Get the Trap Frame in EBX */
583 mov ebx, [ebp+0]
584
585 /* Get the exception list and restore */
586 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
587 mov [fs:KPCR_EXCEPTION_LIST], eax
588
589 /* Get the parameters */
590 mov edx, [ebp+16] /* Search frames */
591 mov ecx, [ebp+12] /* Context */
592 mov eax, [ebp+8] /* Exception Record */
593
594 /* Raise the exception */
595 push edx
596 push ebx
597 push 0
598 push ecx
599 push eax
600 call _KiRaiseException@20
601
602 /* Restore trap frame in EBP */
603 pop ebp
604 mov esp, ebp
605
606 /* Check the result */
607 or eax, eax
608 jz _KiServiceExit2
609
610 /* Restore debug registers too */
611 jmp _KiServiceExit
612 .endfunc
613
614 .func NtContinue@8
615 _NtContinue@8:
616
617 /* NOTE: We -must- be called by Zw* to have the right frame! */
618 /* Push the stack frame */
619 push ebp
620
621 /* Get the current thread and restore its trap frame */
622 mov ebx, [fs:KPCR_CURRENT_THREAD]
623 mov edx, [ebp+KTRAP_FRAME_EDX]
624 mov [ebx+KTHREAD_TRAP_FRAME], edx
625
626 /* Set up stack frame */
627 mov ebp, esp
628
629 /* Save the parameters */
630 mov eax, [ebp+0]
631 mov ecx, [ebp+8]
632
633 /* Call KiContinue */
634 push eax
635 push 0
636 push ecx
637 call _KiContinue@12
638
639 /* Check if we failed (bad context record) */
640 or eax, eax
641 jnz Error
642
643 /* Check if test alert was requested */
644 cmp dword ptr [ebp+12], 0
645 je DontTest
646
647 /* Test alert for the thread */
648 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
649 push eax
650 call _KeTestAlertThread@4
651
652 DontTest:
653 /* Return to previous context */
654 pop ebp
655 mov esp, ebp
656 jmp _KiServiceExit2
657
658 Error:
659 pop ebp
660 mov esp, ebp
661 jmp _KiServiceExit
662 .endfunc
663
664 /* EXCEPTION DISPATCHERS *****************************************************/
665
666 .func CommonDispatchException
667 _CommonDispatchException:
668
669 /* Make space for an exception record */
670 sub esp, EXCEPTION_RECORD_LENGTH
671
672 /* Set it up */
673 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
674 xor eax, eax
675 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
676 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
677 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
678 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
679
680 /* Check parameter count */
681 cmp eax, 0
682 jz NoParams
683
684 /* Get information */
685 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
686 mov [ebx], edx
687 mov [ebx+4], esi
688 mov [ebx+8], edi
689
690 NoParams:
691
692 /* Set the record in ECX and check if this was V86 */
693 mov ecx, esp
694 test dword ptr [esp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
695 jz SetPreviousMode
696
697 /* Set V86 mode */
698 mov eax, 0xFFFF
699 jmp MaskMode
700
701 SetPreviousMode:
702
703 /* Calculate the previous mode */
704 mov eax, [ebp+KTRAP_FRAME_CS]
705 MaskMode:
706 and eax, MODE_MASK
707
708 /* Dispatch the exception */
709 push 1
710 push eax
711 push ebp
712 push 0
713 push ecx
714 call _KiDispatchException@20
715
716 /* End the trap */
717 mov esp, ebp
718 jmp _Kei386EoiHelper@0
719 .endfunc
720
721 .func DispatchNoParam
722 _DispatchNoParam:
723 /* Call the common dispatcher */
724 xor ecx, ecx
725 call _CommonDispatchException
726 .endfunc
727
728 .func DispatchOneParam
729 _DispatchOneParam:
730 /* Call the common dispatcher */
731 xor edx, edx
732 mov ecx, 1
733 call _CommonDispatchException
734 .endfunc
735
736 .func DispatchTwoParam
737 _DispatchTwoParam:
738 /* Call the common dispatcher */
739 xor edx, edx
740 mov ecx, 2
741 call _CommonDispatchException
742 .endfunc
743
744 /* HARDWARE TRAP HANDLERS ****************************************************/
745
746 .func KiTrap0
747 _KiTrap0:
748 /* Push error code */
749 push 0
750
751 /* Enter trap */
752 TRAP_PROLOG(0)
753
754 /* Check for V86 */
755 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
756 jnz V86Int0
757
758 /* Check if the frame was from kernelmode */
759 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
760 jz SendException
761
762 /* Check the old mode */
763 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
764 jne VdmCheck
765
766 SendException:
767 /* Re-enable interrupts for user-mode and send the exception */
768 sti
769 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
770 mov ebx, [ebp+KTRAP_FRAME_EIP]
771 jmp _DispatchNoParam
772
773 VdmCheck:
774 /* Check if this is a VDM process */
775 mov ebx, [fs:KPCR_CURRENT_THREAD]
776 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
777 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
778 jz SendException
779
780 /* We don't support this yet! */
781 V86Int0:
782 int 3
783 .endfunc
784
785 .func KiTrap1
786 _KiTrap1:
787 /* Push error code */
788 push 0
789
790 /* Enter trap */
791 TRAP_PROLOG(1)
792
793 /* Check for V86 */
794 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
795 jnz V86Int1
796
797 /* Check if the frame was from kernelmode */
798 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
799 jz PrepInt1
800
801 /* Check the old mode */
802 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
803 jne V86Int1
804
805 EnableInterrupts:
806 /* Enable interrupts for user-mode */
807 sti
808
809 PrepInt1:
810 /* Prepare the exception */
811 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
812 mov ebx, [ebp+KTRAP_FRAME_EIP]
813 mov eax, STATUS_SINGLE_STEP
814 jmp _DispatchNoParam
815
816 V86Int1:
817 /* Check if this is a VDM process */
818 mov ebx, [fs:KPCR_CURRENT_THREAD]
819 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
820 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
821 jz EnableInterrupts
822
823 /* We don't support VDM! */
824 int 3
825 .endfunc
826
827 .func KiTrap2
828 _KiTrap2:
829
830 /* FIXME: This is an NMI, nothing like a normal exception */
831 mov eax, 2
832 jmp _KiSystemFatalException
833 .endfunc
834
835 .func KiTrap3
836 _KiTrap3:
837 /* Push error code */
838 push 0
839
840 /* Enter trap */
841 TRAP_PROLOG(3)
842
843 /* Check for V86 */
844 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
845 jnz V86Int3
846
847 /* Check if the frame was from kernelmode */
848 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
849 jz PrepInt3
850
851 /* Check the old mode */
852 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
853 jne V86Int3
854
855 EnableInterrupts3:
856 /* Enable interrupts for user-mode */
857 sti
858
859 PrepInt3:
860 /* Prepare the exception */
861 mov esi, ecx
862 mov edi, edx
863 mov edx, eax
864
865 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
866 mov ebx, [ebp+KTRAP_FRAME_EIP]
867 dec ebx
868 mov eax, STATUS_BREAKPOINT
869 mov ecx, 3
870 call _CommonDispatchException
871
872 V86Int3:
873 /* Check if this is a VDM process */
874 mov ebx, [fs:KPCR_CURRENT_THREAD]
875 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
876 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
877 jz EnableInterrupts3
878
879 /* We don't support VDM! */
880 int 3
881 .endfunc
882
883 .func KiTrap4
884 _KiTrap4:
885 /* Push error code */
886 push 0
887
888 /* Enter trap */
889 TRAP_PROLOG(4)
890
891 /* Check for V86 */
892 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
893 jnz V86Int4
894
895 /* Check if the frame was from kernelmode */
896 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
897 jz SendException4
898
899 /* Check the old mode */
900 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
901 jne VdmCheck4
902
903 SendException4:
904 /* Re-enable interrupts for user-mode and send the exception */
905 sti
906 mov eax, STATUS_INTEGER_OVERFLOW
907 mov ebx, [ebp+KTRAP_FRAME_EIP]
908 dec ebx
909 jmp _DispatchNoParam
910
911 VdmCheck4:
912 /* Check if this is a VDM process */
913 mov ebx, [fs:KPCR_CURRENT_THREAD]
914 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
915 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
916 jz SendException4
917
918 /* We don't support this yet! */
919 V86Int4:
920 int 3
921 .endfunc
922
923 .func KiTrap5
924 _KiTrap5:
925 /* Push error code */
926 push 0
927
928 /* Enter trap */
929 TRAP_PROLOG(5)
930
931 /* Check for V86 */
932 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
933 jnz V86Int5
934
935 /* Check if the frame was from kernelmode */
936 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
937 jnz CheckMode
938
939 /* It did, and this should never happen */
940 mov eax, 5
941 jmp _KiSystemFatalException
942
943 /* Check the old mode */
944 CheckMode:
945 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
946 jne VdmCheck5
947
948 /* Re-enable interrupts for user-mode and send the exception */
949 SendException5:
950 sti
951 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
952 mov ebx, [ebp+KTRAP_FRAME_EIP]
953 jmp _DispatchNoParam
954
955 VdmCheck5:
956 /* Check if this is a VDM process */
957 mov ebx, [fs:KPCR_CURRENT_THREAD]
958 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
959 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
960 jz SendException5
961
962 /* We don't support this yet! */
963 V86Int5:
964 int 3
965 .endfunc
966
967 .func KiTrap6
968 _KiTrap6:
969 /* Push error code */
970 push 0
971
972 /* Enter trap */
973 TRAP_PROLOG(6)
974
975 /* Not yet supported */
976 int 3
977 jmp $
978
979 /* Return to caller */
980 jmp _Kei386EoiHelper@0
981 .endfunc
982
983 .func KiTrap7
984 _KiTrap7:
985 /* Push error code */
986 push 0
987
988 /* Enter trap */
989 TRAP_PROLOG(7)
990
991 /* Get the current thread and stack */
992 StartTrapHandle:
993 mov eax, [fs:KPCR_CURRENT_THREAD]
994 mov ecx, [eax+KTHREAD_INITIAL_STACK]
995 sub ecx, NPX_FRAME_LENGTH
996
997 /* Check if emulation is enabled */
998 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
999 jnz EmulationEnabled
1000
1001 CheckState:
1002 /* Check if the NPX state is loaded */
1003 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1004 mov ebx, cr0
1005 jz IsLoaded
1006
1007 /* Remove flags */
1008 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1009 mov cr0, ebx
1010
1011 /* Check the NPX thread */
1012 mov edx, [fs:KPCR_NPX_THREAD]
1013 or edx, edx
1014 jz NoNpxThread
1015
1016 /* Get the NPX Stack */
1017 mov esi, [edx+KTHREAD_INITIAL_STACK]
1018 sub esi, NPX_FRAME_LENGTH
1019
1020 /* Check if we have FXSR and check which operand to use */
1021 test byte ptr _KeI386FxsrPresent, 1
1022 jz FnSave
1023 fxsave [esi]
1024 jmp AfterSave
1025
1026 FnSave:
1027 fnsave [esi]
1028
1029 AfterSave:
1030 /* Set the thread's state to dirty */
1031 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1032
1033 NoNpxThread:
1034 /* Check if we have FXSR and choose which operand to use */
1035 test byte ptr _KeI386FxsrPresent, 1
1036 jz FrRestore
1037 fxrstor [ecx]
1038 jmp AfterRestore
1039
1040 FrRestore:
1041 frstor [esi]
1042
1043 AfterRestore:
1044 /* Set state loaded */
1045 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1046 mov [fs:KPCR_NPX_THREAD], eax
1047
1048 /* Enable interrupts to happen now */
1049 sti
1050 nop
1051
1052 /* Check if CR0 needs to be reloaded due to a context switch */
1053 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1054 jz _Kei386EoiHelper@0
1055
1056 /* We have to reload CR0... disable interrupts */
1057 cli
1058
1059 /* Get CR0 and update it */
1060 mov ebx, cr0
1061 or ebx, [ecx+FN_CR0_NPX_STATE]
1062 mov cr0, ebx
1063
1064 /* Restore interrupts and check if TS is back on */
1065 sti
1066 test bl, CR0_TS
1067 jz _Kei386EoiHelper@0
1068
1069 /* Clear TS, and loop handling again */
1070 clts
1071 cli
1072 jmp StartTrapHandle
1073
1074 IsLoaded:
1075 /* Check if TS is set */
1076 test bl, CR0_TS
1077 jnz TsSetOnLoadedState
1078
1079 /* Check if the trap came from user-mode */
1080 int 3
1081
1082 EmulationEnabled:
1083 /* Did this come from kernel-mode? */
1084 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1085 jz CheckState
1086
1087 /* It came from user-mode, so this would only be valid inside a VDM */
1088 /* Since we don't actually have VDMs in ROS, bugcheck. */
1089 jmp BogusTrap2
1090
1091 TsSetOnLoadedState:
1092 /* TS shouldn't be set, unless this we don't have a Math Processor */
1093 test bl, CR0_MP
1094 jnz BogusTrap
1095
1096 /* Strange that we got a trap at all, but ignore and continue */
1097 clts
1098 jmp _Kei386EoiHelper@0
1099
1100 BogusTrap2:
1101 /* Cause a bugcheck */
1102 sti
1103 push 0
1104 push 0
1105 push eax
1106 push 1
1107 push TRAP_CAUSE_UNKNOWN
1108 call _KeBugCheckEx@20
1109
1110 BogusTrap:
1111 /* Cause a bugcheck */
1112 push 0
1113 push 0
1114 push ebx
1115 push 2
1116 push TRAP_CAUSE_UNKNOWN
1117 call _KeBugCheckEx@20
1118 .endfunc
1119
1120 .globl _KiTrap8
1121 .func KiTrap8
1122 _KiTrap8:
1123
1124 /* Can't really do too much */
1125 mov eax, 8
1126 jmp _KiSystemFatalException
1127 .endfunc
1128
1129 .func KiTrap9
1130 _KiTrap9:
1131 /* Push error code */
1132 push 0
1133
1134 /* Enter trap */
1135 TRAP_PROLOG(9)
1136
1137 /* Enable interrupts and bugcheck */
1138 sti
1139 mov eax, 9
1140 jmp _KiSystemFatalException
1141 .endfunc
1142
1143 .func KiTrap10
1144 _KiTrap10:
1145 /* Enter trap */
1146 TRAP_PROLOG(10)
1147
1148 /* Check for V86 */
1149 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1150 jnz V86IntA
1151
1152 /* Check if the frame was from kernelmode */
1153 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1154 jz Fatal
1155
1156 V86IntA:
1157 /* Check if OF was set during iretd */
1158 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1159 sti
1160 jz Fatal
1161
1162 /* It was, just mask it out */
1163 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1164 jmp _Kei386EoiHelper@0
1165
1166 Fatal:
1167 /* TSS failure for some other reason: crash */
1168 mov eax, 10
1169 jmp _KiSystemFatalException
1170 .endfunc
1171
1172 .func KiTrap11
1173 _KiTrap11:
1174 /* Enter trap */
1175 TRAP_PROLOG(11)
1176
1177 /* FIXME: ROS Doesn't handle segment faults yet */
1178 mov eax, 11
1179 jmp _KiSystemFatalException
1180 .endfunc
1181
1182 .func KiTrap12
1183 _KiTrap12:
1184 /* Enter trap */
1185 TRAP_PROLOG(12)
1186
1187 /* FIXME: ROS Doesn't handle stack faults yet */
1188 mov eax, 12
1189 jmp _KiSystemFatalException
1190 .endfunc
1191
1192 .func KiTrap13
1193 _KiTrap13:
1194
1195 /* It this a V86 GPF? */
1196 test dword ptr [esp+12], EFLAGS_V86_MASK
1197 jz NotV86
1198
1199 /* Enter V86 Trap */
1200 V86_TRAP_PROLOG kitd
1201
1202 /* Make sure that this is a V86 process */
1203 mov ecx, [fs:KPCR_CURRENT_THREAD]
1204 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1205 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1206 jnz RaiseIrql
1207
1208 /* Otherwise, something is very wrong, raise an exception */
1209 sti
1210 mov ebx, [ebp+KTRAP_FRAME_EIP]
1211 mov esi, -1
1212 mov eax, STATUS_ACCESS_VIOLATION
1213 jmp _DispatchTwoParam
1214
1215 RaiseIrql:
1216
1217 /* Go to APC level */
1218 mov ecx, APC_LEVEL
1219 call @KfRaiseIrql@4
1220
1221 /* Save old IRQL and enable interrupts */
1222 push eax
1223 sti
1224
1225 /* Handle the opcode */
1226 call _Ki386HandleOpcodeV86@0
1227
1228 /* Check if this was VDM */
1229 test al, 0xFF
1230 jnz NoReflect
1231
1232 /* FIXME: TODO */
1233 int 3
1234
1235 NoReflect:
1236
1237 /* Lower IRQL and disable interrupts */
1238 pop ecx
1239 call @KfLowerIrql@4
1240 cli
1241
1242 /* Check if this was a V86 trap */
1243 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1244 jz NotV86Trap
1245
1246 /* Exit the V86 Trap */
1247 V86_TRAP_EPILOG
1248
1249 NotV86Trap:
1250
1251 /* Either this wasn't V86, or it was, but an APC interrupted us */
1252 jmp _Kei386EoiHelper@0
1253
1254 NotV86:
1255 /* Enter trap */
1256 TRAP_PROLOG(13)
1257
1258 /* Check if this was from kernel-mode */
1259 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1260 jnz UserModeGpf
1261
1262 /* FIXME: Check for GPF during GPF */
1263
1264 /* Get the opcode and trap frame */
1265 mov eax, [ebp+KTRAP_FRAME_EIP]
1266 mov eax, [eax]
1267 mov edx, [ebp+KTRAP_FRAME_EBP]
1268
1269 /* We want to check if this was POP [DS/ES/FS/GS] */
1270 add edx, KTRAP_FRAME_DS
1271 cmp al, 0x1F
1272 jz SegPopGpf
1273 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1274 cmp al, 7
1275 jz SegPopGpf
1276 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1277 cmp ax, 0xA10F
1278 jz SegPopGpf
1279 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1280 cmp ax, 0xA90F
1281 jz SegPopGpf
1282
1283 /* It isn't, was it IRETD? */
1284 cmp al, 0xCF
1285 jne NotIretGpf
1286
1287 /* Get error code */
1288 lea edx, [ebp+KTRAP_FRAME_ESP]
1289 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1290 and ax, ~RPL_MASK
1291
1292 /* Get CS */
1293 mov cx, word ptr [edx+4]
1294 and cx, ~RPL_MASK
1295 cmp cx, ax
1296 jnz NotCsGpf
1297
1298 /* This should be a Ki386CallBios return */
1299 mov eax, offset _Ki386BiosCallReturnAddress
1300 cmp eax, [edx]
1301 jne NotBiosGpf
1302 mov eax, [edx+4]
1303 cmp ax, KGDT_R0_CODE + RPL_MASK
1304 jne NotBiosGpf
1305
1306 /* Jump to return address */
1307 jmp _Ki386BiosCallReturnAddress
1308
1309 NotBiosGpf:
1310 /* Check if the thread was in kernel mode */
1311 mov ebx, [fs:KPCR_CURRENT_THREAD]
1312 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1313 jz UserModeGpf
1314
1315 /* Set RPL_MASK for check below */
1316 or word ptr [edx+4], RPL_MASK
1317
1318 NotCsGpf:
1319 /* Check if the IRET goes to user-mode */
1320 test dword ptr [edx+4], RPL_MASK
1321 jz UserModeGpf
1322
1323 /* Setup trap frame to copy */
1324 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1325 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1326
1327 TrapCopy:
1328
1329 /* Copy each field */
1330 mov eax, [edx]
1331 mov [edx+12], eax
1332 sub edx, 4
1333 loop TrapCopy
1334
1335 /* Enable interrupts and adjust stack */
1336 sti
1337 add esp, 12
1338 add ebp, 12
1339
1340 /* Setup exception record */
1341 mov ebx, [ebp+KTRAP_FRAME_EIP]
1342 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1343 and esi, 0xFFFF
1344 mov eax, STATUS_ACCESS_VIOLATION
1345 jmp _DispatchTwoParam
1346
1347 MsrCheck:
1348
1349 /* FIXME: Handle RDMSR/WRMSR */
1350 int 3
1351 jmp $
1352
1353 NotIretGpf:
1354
1355 /* Check if this was an MSR opcode */
1356 cmp al, 0xF
1357 jz MsrCheck
1358
1359 /* Check if DS is Ring 3 */
1360 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1361 jz CheckEs
1362
1363 /* Otherwise, fix it up */
1364 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1365 jmp ExitGpfTrap
1366
1367 CheckEs:
1368
1369 /* Check if ES is Ring 3 */
1370 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1371 jz UserModeGpf
1372
1373 /* Otherwise, fix it up */
1374 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1375 jmp ExitGpfTrap
1376
1377 SegPopGpf:
1378
1379 /* Sanity check */
1380 lea eax, [ebp+KTRAP_FRAME_ESP]
1381 cmp edx, eax
1382 jz HandleSegPop
1383 int 3
1384
1385 /* Handle segment POP fault by setting it to 0 */
1386 HandleSegPop:
1387 xor eax, eax
1388 mov dword ptr [edx], eax
1389
1390 ExitGpfTrap:
1391
1392 /* Do a trap exit */
1393 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1394
1395 UserModeGpf:
1396
1397 /* FIXME: Unhandled */
1398 int 3
1399 jmp $
1400 .endfunc
1401
1402 .func KiTrap14
1403 _KiTrap14:
1404 /* Enter trap */
1405 TRAP_PROLOG(14)
1406
1407 /* Call the C exception handler */
1408 push 14
1409 push ebp
1410 call _KiPageFaultHandler
1411 add esp, 8
1412
1413 /* Return to caller */
1414 jmp _Kei386EoiHelper@0
1415 .endfunc
1416
1417 .func KiTrap0F
1418 _KiTrap0F:
1419 /* Push error code */
1420 push 0
1421
1422 /* Enter trap */
1423 TRAP_PROLOG(15)
1424 sti
1425
1426 /* Raise a fatal exception */
1427 mov eax, 15
1428 jmp _KiSystemFatalException
1429 .endfunc
1430
1431 .func KiTrap16
1432 _KiTrap16:
1433 /* Push error code */
1434 push 0
1435
1436 /* Enter trap */
1437 TRAP_PROLOG(16)
1438
1439 /* FIXME: ROS Doesn't handle FPU faults yet */
1440 mov eax, 16
1441 jmp _KiSystemFatalException
1442 .endfunc
1443
1444 .func KiTrap17
1445 _KiTrap17:
1446 /* Push error code */
1447 push 0
1448
1449 /* Enter trap */
1450 TRAP_PROLOG(17)
1451
1452 /* FIXME: ROS Doesn't handle alignment faults yet */
1453 mov eax, 17
1454 jmp _KiSystemFatalException
1455 .endfunc
1456
1457 .func KiSystemFatalException
1458 _KiSystemFatalException:
1459
1460 /* Push the trap frame */
1461 push ebp
1462
1463 /* Push empty parameters */
1464 push 0
1465 push 0
1466 push 0
1467
1468 /* Push trap number and bugcheck code */
1469 push eax
1470 push UNEXPECTED_KERNEL_MODE_TRAP
1471 call _KeBugCheckWithTf@24
1472 ret
1473 .endfunc
1474
1475 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
1476
1477 .globl _KiStartUnexpectedRange@0
1478 _KiStartUnexpectedRange@0:
1479
1480 GENERATE_INT_HANDLERS
1481
1482 .globl _KiEndUnexpectedRange@0
1483 _KiEndUnexpectedRange@0:
1484 jmp _KiUnexpectedInterruptTail
1485
1486 .func KiUnexpectedInterruptTail
1487 _KiUnexpectedInterruptTail:
1488
1489 /* Enter interrupt trap */
1490 INT_PROLOG kui, DoNotPushFakeErrorCode
1491
1492 /* Increase interrupt count */
1493 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1494
1495 /* Put vector in EBX and make space for KIRQL */
1496 mov ebx, [esp]
1497 sub esp, 4
1498
1499 /* Begin interrupt */
1500 push esp
1501 push ebx
1502 push HIGH_LEVEL
1503 call _HalBeginSystemInterrupt@12
1504
1505 /* Check if it was spurious or not */
1506 or al, al
1507 jnz Handled
1508
1509 /* Spurious, ignore it */
1510 add esp, 8
1511 jmp _Kei386EoiHelper2ndEntry
1512
1513 Handled:
1514 /* Unexpected interrupt, print a message on debug builds */
1515 #if DBG
1516 push [esp+4]
1517 push offset _UnexpectedMsg
1518 call _DbgPrint
1519 add esp, 8
1520 #endif
1521
1522 /* Exit the interrupt */
1523 mov esi, $
1524 cli
1525 call _HalEndSystemInterrupt@8
1526 jmp _Kei386EoiHelper@0
1527 .endfunc
1528
1529 .globl _KiUnexpectedInterrupt
1530 _KiUnexpectedInterrupt:
1531
1532 /* Bugcheck with invalid interrupt code */
1533 push 0x12
1534 call _KeBugCheck@4
1535
1536 /* INTERRUPT HANDLERS ********************************************************/
1537
1538 .func KiInterruptTemplate
1539 _KiInterruptTemplate:
1540
1541 /* Enter interrupt trap */
1542 INT_PROLOG kit, DoPushFakeErrorCode
1543 .endfunc
1544
1545 _KiInterruptTemplate2ndDispatch:
1546 /* Dummy code, will be replaced by the address of the KINTERRUPT */
1547 mov edi, 0
1548
1549 _KiInterruptTemplateObject:
1550 /* Dummy jump, will be replaced by the actual jump */
1551 jmp _KeSynchronizeExecution@12
1552
1553 _KiInterruptTemplateDispatch:
1554 /* Marks the end of the template so that the jump above can be edited */
1555
1556 .func KiChainedDispatch2ndLvl@0
1557 _KiChainedDispatch2ndLvl@0:
1558
1559 /* Not yet supported */
1560 int 3
1561 .endfunc
1562
1563 .func KiChainedDispatch@0
1564 _KiChainedDispatch@0:
1565
1566 /* Increase interrupt count */
1567 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1568
1569 /* Save trap frame */
1570 mov ebp, esp
1571
1572 /* Save vector and IRQL */
1573 mov eax, [edi+KINTERRUPT_VECTOR]
1574 mov ecx, [edi+KINTERRUPT_IRQL]
1575
1576 /* Save old irql */
1577 push eax
1578 sub esp, 4
1579
1580 /* Begin interrupt */
1581 push esp
1582 push eax
1583 push ecx
1584 call _HalBeginSystemInterrupt@12
1585
1586 /* Check if it was handled */
1587 or al, al
1588 jz SpuriousInt
1589
1590 /* Call the 2nd-level handler */
1591 call _KiChainedDispatch2ndLvl@0
1592
1593 /* Exit the interrupt */
1594 mov esi, $
1595 cli
1596 call _HalEndSystemInterrupt@8
1597 jmp _Kei386EoiHelper@0
1598 .endfunc
1599
1600 .func KiInterruptDispatch@0
1601 _KiInterruptDispatch@0:
1602
1603 /* Increase interrupt count */
1604 inc dword ptr [fs:KPCR_PRCB_INTERRUPT_COUNT]
1605
1606 /* Save trap frame */
1607 mov ebp, esp
1608
1609 /* Save vector and IRQL */
1610 mov eax, [edi+KINTERRUPT_VECTOR]
1611 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
1612
1613 /* Save old irql */
1614 push eax
1615 sub esp, 4
1616
1617 /* Begin interrupt */
1618 push esp
1619 push eax
1620 push ecx
1621 call _HalBeginSystemInterrupt@12
1622
1623 /* Check if it was handled */
1624 or al, al
1625 jz SpuriousInt
1626
1627 /* Acquire the lock */
1628 GetIntLock:
1629 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
1630 ACQUIRE_SPINLOCK(esi, IntSpin)
1631
1632 /* Call the ISR */
1633 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
1634 push eax
1635 push edi
1636 call [edi+KINTERRUPT_SERVICE_ROUTINE]
1637
1638 /* Release the lock */
1639 RELEASE_SPINLOCK(esi)
1640
1641 /* Exit the interrupt */
1642 mov esi, $
1643 cli
1644 call _HalEndSystemInterrupt@8
1645 jmp _Kei386EoiHelper@0
1646
1647 SpuriousInt:
1648 /* Exit the interrupt */
1649 add esp, 8
1650 mov esi, $
1651 jmp _Kei386EoiHelper@0
1652
1653 #ifdef CONFIG_SMP
1654 IntSpin:
1655 SPIN_ON_LOCK esi, GetIntLock
1656 #endif
1657 .endfunc