- Fix an important bug which was causing us to incorrectly set the DPC Stack in the...
[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 #define Running 2
16 #define WrDispatchInt 0x1F
17
18 /* GLOBALS *******************************************************************/
19
20 .data
21 .globl _KiIdt
22 _KiIdt:
23 /* This is the Software Interrupt Table that we handle in this file: */
24 idt _KiTrap0, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
25 idt _KiTrap1, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
26 idt _KiTrap2, INT_32_DPL0 /* INT 02: NMI Interrupt */
27 idt _KiTrap3, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
28 idt _KiTrap4, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
29 idt _KiTrap5, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
30 idt _KiTrap6, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
31 idt _KiTrap7, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
32 idt _KiTrap8, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
33 idt _KiTrap9, INT_32_DPL0 /* INT 09: RESERVED */
34 idt _KiTrap10, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
35 idt _KiTrap11, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
36 idt _KiTrap12, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
37 idt _KiTrap13, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
38 idt _KiTrap14, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
39 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
40 idt _KiTrap16, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
41 idt _KiTrap17, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
42 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
43 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
44 .rept 22
45 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
46 .endr
47 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
48 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
49 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
50 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
51 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
52 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
53 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
54
55 /* System call entrypoints: */
56 .globl _KiFastCallEntry
57 .globl _KiSystemService
58
59 /* And special system-defined software traps: */
60 .globl _NtRaiseException@12
61 .globl _NtContinue@8
62 .globl _KiCoprocessorError@0
63 .globl _KiDispatchInterrupt@0
64
65 /* Interrupt template entrypoints */
66 .globl _KiInterruptTemplate
67 .globl _KiInterruptTemplateObject
68 .globl _KiInterruptTemplateDispatch
69
70 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
71 .globl _KiChainedDispatch2ndLvl@0
72 .globl _KiInterruptDispatch@0
73 .globl _KiChainedDispatch@0
74
75 /* We implement the following trap exit points: */
76 .globl _KiServiceExit /* Exit from syscall */
77 .globl _KiServiceExit2 /* Exit from syscall with complete frame*/
78 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
79 .globl _Kei386EoiHelper2ndEntry /* Exit from unexpected interrupt */
80
81 .globl _KiIdtDescriptor
82 _KiIdtDescriptor:
83 .short 0x800
84 .long _KiIdt
85
86 .globl _KiUnexpectedEntrySize
87 _KiUnexpectedEntrySize:
88 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
89
90 _UnexpectedMsg:
91 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
92
93 _UnhandledMsg:
94 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
95
96 _IsrTimeoutMsg:
97 .asciz "\n*** ISR at %lx took over .5 second\n"
98
99 _IsrOverflowMsg:
100 .asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
101
102 _KiTrapPrefixTable:
103 .byte 0xF2 /* REP */
104 .byte 0xF3 /* REP INS/OUTS */
105 .byte 0x67 /* ADDR */
106 .byte 0xF0 /* LOCK */
107 .byte 0x66 /* OP */
108 .byte 0x2E /* SEG */
109 .byte 0x3E /* DS */
110 .byte 0x26 /* ES */
111 .byte 0x64 /* FS */
112 .byte 0x65 /* GS */
113 .byte 0x36 /* SS */
114
115 _KiTrapIoTable:
116 .byte 0xE4 /* IN */
117 .byte 0xE5 /* IN */
118 .byte 0xEC /* IN */
119 .byte 0xED /* IN */
120 .byte 0x6C /* INS */
121 .byte 0x6D /* INS */
122 .byte 0xE6 /* OUT */
123 .byte 0xE7 /* OUT */
124 .byte 0xEE /* OUT */
125 .byte 0xEF /* OUT */
126 .byte 0x6E /* OUTS */
127 .byte 0x6F /* OUTS */
128
129 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
130 .text
131
132 _KiGetTickCount:
133 _KiCallbackReturn:
134 _KiRaiseAssertion:
135 /* FIXME: TODO */
136 UNHANDLED_PATH
137
138 .func KiSystemService
139 TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
140 _KiSystemService:
141
142 /* Enter the shared system call prolog */
143 SYSCALL_PROLOG kss_a, kss_t
144
145 /* Jump to the actual handler */
146 jmp SharedCode
147 .endfunc
148
149 .func KiFastCallEntry
150 TRAP_FIXUPS FastCallDrSave, FastCallDrReturn, DoNotFixupV86, DoNotFixupAbios
151 _KiFastCallEntry:
152
153 /* Enter the fast system call prolog */
154 FASTCALL_PROLOG FastCallDrSave, FastCallDrReturn
155
156 SharedCode:
157
158 /*
159 * Find out which table offset to use. Converts 0x1124 into 0x10.
160 * The offset is related to the Table Index as such: Offset = TableIndex x 10
161 */
162 mov edi, eax
163 shr edi, SERVICE_TABLE_SHIFT
164 and edi, SERVICE_TABLE_MASK
165 mov ecx, edi
166
167 /* Now add the thread's base system table to the offset */
168 add edi, [esi+KTHREAD_SERVICE_TABLE]
169
170 /* Get the true syscall ID and check it */
171 mov ebx, eax
172 and eax, SERVICE_NUMBER_MASK
173 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
174
175 /* Invalid ID, try to load Win32K Table */
176 jnb KiBBTUnexpectedRange
177
178 /* Check if this was Win32K */
179 cmp ecx, SERVICE_TABLE_TEST
180 jnz NotWin32K
181
182 /* Get the TEB */
183 mov ecx, PCR[KPCR_TEB]
184
185 /* Check if we should flush the User Batch */
186 xor ebx, ebx
187 ReadBatch:
188 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
189 jz NotWin32K
190
191 /* Flush it */
192 push edx
193 push eax
194 //call [_KeGdiFlushUserBatch]
195 pop eax
196 pop edx
197
198 NotWin32K:
199 /* Increase total syscall count */
200 inc dword ptr PCR[KPCR_SYSTEM_CALLS]
201
202 #ifdef DBG
203 /* Increase per-syscall count */
204 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
205 jecxz NoCountTable
206 inc dword ptr [ecx+eax*4]
207 #endif
208
209 /* Users's current stack frame pointer is source */
210 NoCountTable:
211 mov esi, edx
212
213 /* Allocate room for argument list from kernel stack */
214 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
215 xor ecx, ecx
216 mov cl, [eax+ebx]
217
218 /* Get pointer to function */
219 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
220 mov ebx, [edi+eax*4]
221
222 /* Allocate space on our stack */
223 sub esp, ecx
224
225 /* Set the size of the arguments and the destination */
226 shr ecx, 2
227 mov edi, esp
228
229 /* Make sure we're within the User Probe Address */
230 cmp esi, _MmUserProbeAddress
231 jnb AccessViolation
232
233 CopyParams:
234 /* Copy the parameters */
235 rep movsd
236
237 /* Do the System Call */
238 call ebx
239
240 AfterSysCall:
241 #ifdef DBG
242 /* Make sure the user-mode call didn't return at elevated IRQL */
243 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
244 jz SkipCheck
245 mov esi, eax /* We need to save the syscall's return val */
246 call _KeGetCurrentIrql@0
247 or al, al
248 jnz InvalidIrql
249 mov eax, esi /* Restore it */
250
251 /* Get our temporary current thread pointer for sanity check */
252 mov ecx, PCR[KPCR_CURRENT_THREAD]
253
254 /* Make sure that we are not attached and that APCs are not disabled */
255 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
256 or dl, dl
257 jnz InvalidIndex
258 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
259 or edx, edx
260 jnz InvalidIndex
261 #endif
262
263 SkipCheck:
264
265 /* Deallocate the kernel stack frame */
266 mov esp, ebp
267
268 KeReturnFromSystemCall:
269
270 /* Get the Current Thread */
271 mov ecx, PCR[KPCR_CURRENT_THREAD]
272
273 /* Restore the old trap frame pointer */
274 mov edx, [ebp+KTRAP_FRAME_EDX]
275 mov [ecx+KTHREAD_TRAP_FRAME], edx
276 .endfunc
277
278 .func KiServiceExit
279 _KiServiceExit:
280 /* Disable interrupts */
281 cli
282
283 /* Check for, and deliver, User-Mode APCs if needed */
284 CHECK_FOR_APC_DELIVER 1
285
286 /* Exit and cleanup */
287 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
288 .endfunc
289
290 KiBBTUnexpectedRange:
291
292 /* If this isn't a Win32K call, fail */
293 cmp ecx, SERVICE_TABLE_TEST
294 jne InvalidCall
295
296 /* Set up Win32K Table */
297 push edx
298 push ebx
299 call _PsConvertToGuiThread@0
300
301 /* Check return code */
302 or eax, eax
303
304 /* Restore registers */
305 pop eax
306 pop edx
307
308 /* Reset trap frame address */
309 mov ebp, esp
310 mov [esi+KTHREAD_TRAP_FRAME], ebp
311
312 /* Try the Call again, if we suceeded */
313 jz SharedCode
314
315 /*
316 * The Shadow Table should have a special byte table which tells us
317 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
318 */
319
320 /* Get the table limit and base */
321 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
322 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
323 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
324
325 /* Get the table address and add our index into the array */
326 lea edx, [edx+ecx*4]
327 and eax, SERVICE_NUMBER_MASK
328 add edx, eax
329
330 /* Find out what we should return */
331 movsx eax, byte ptr [edx]
332 or eax, eax
333
334 /* Return either 0 or -1, we've set it in EAX */
335 jle KeReturnFromSystemCall
336
337 /* Set STATUS_INVALID_SYSTEM_SERVICE */
338 mov eax, STATUS_INVALID_SYSTEM_SERVICE
339 jmp KeReturnFromSystemCall
340
341 InvalidCall:
342
343 /* Invalid System Call */
344 mov eax, STATUS_INVALID_SYSTEM_SERVICE
345 jmp KeReturnFromSystemCall
346
347 AccessViolation:
348
349 /* Check if this came from kernel-mode */
350 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
351
352 /* It's fine, go ahead with it */
353 jz CopyParams
354
355 /* Caller sent invalid parameters, fail here */
356 mov eax, STATUS_ACCESS_VIOLATION
357 jmp AfterSysCall
358
359 BadStack:
360
361 /* Restore ESP0 stack */
362 mov ecx, PCR[KPCR_TSS]
363 mov esp, ss:[ecx+KTSS_ESP0]
364
365 /* Generate V86M Stack for Trap 6 */
366 push 0
367 push 0
368 push 0
369 push 0
370
371 /* Generate interrupt stack for Trap 6 */
372 push KGDT_R3_DATA + RPL_MASK
373 push 0
374 push 0x20202
375 push KGDT_R3_CODE + RPL_MASK
376 push 0
377 jmp _KiTrap6
378
379 #ifdef DBG
380 InvalidIrql:
381 /* Save current IRQL */
382 push PCR[KPCR_IRQL]
383
384 /* Set us at passive */
385 mov dword ptr PCR[KPCR_IRQL], 0
386 cli
387
388 /* Bugcheck */
389 push 0
390 push 0
391 push eax
392 push ebx
393 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
394 call _KeBugCheckEx@20
395
396 InvalidIndex:
397
398 /* Get the index and APC state */
399 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
400 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
401
402 /* Bugcheck */
403 push 0
404 push edx
405 push eax
406 push ebx
407 push APC_INDEX_MISMATCH
408 call _KeBugCheckEx@20
409 ret
410 #endif
411
412 .func KiServiceExit2
413 _KiServiceExit2:
414
415 /* Disable interrupts */
416 cli
417
418 /* Check for, and deliver, User-Mode APCs if needed */
419 CHECK_FOR_APC_DELIVER 0
420
421 /* Exit and cleanup */
422 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
423 .endfunc
424
425 .func Kei386EoiHelper@0
426 _Kei386EoiHelper@0:
427
428 /* Disable interrupts */
429 cli
430
431 /* Check for, and deliver, User-Mode APCs if needed */
432 CHECK_FOR_APC_DELIVER 0
433
434 /* Exit and cleanup */
435 _Kei386EoiHelper2ndEntry:
436 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
437 .endfunc
438
439 V86_Exit:
440 /* Move to EDX position */
441 add esp, KTRAP_FRAME_EDX
442
443 /* Restore volatiles */
444 pop edx
445 pop ecx
446 pop eax
447
448 /* Move to non-volatiles */
449 lea esp, [ebp+KTRAP_FRAME_EDI]
450 pop edi
451 pop esi
452 pop ebx
453 pop ebp
454
455 /* Skip error code and return */
456 add esp, 4
457 iret
458
459 AbiosExit:
460 /* FIXME: TODO */
461 UNHANDLED_PATH
462
463 .func KiDebugService
464 TRAP_FIXUPS kids_a, kids_t, DoFixupV86, DoFixupAbios
465 _KiDebugService:
466
467 /* Push error code */
468 push 0
469
470 /* Enter trap */
471 TRAP_PROLOG kids_a, kids_t
472
473 /* Increase EIP so we skip the INT3 */
474 inc dword ptr [ebp+KTRAP_FRAME_EIP]
475
476 /* Call debug service dispatcher */
477 mov eax, [ebp+KTRAP_FRAME_EAX]
478 mov ecx, [ebp+KTRAP_FRAME_ECX]
479 mov edx, [ebp+KTRAP_FRAME_EDX]
480
481 /* Jump to INT3 handler */
482 jmp PrepareInt3
483 .endfunc
484
485 .func NtRaiseException@12
486 _NtRaiseException@12:
487
488 /* NOTE: We -must- be called by Zw* to have the right frame! */
489 /* Push the stack frame */
490 push ebp
491
492 /* Get the current thread and restore its trap frame */
493 mov ebx, PCR[KPCR_CURRENT_THREAD]
494 mov edx, [ebp+KTRAP_FRAME_EDX]
495 mov [ebx+KTHREAD_TRAP_FRAME], edx
496
497 /* Set up stack frame */
498 mov ebp, esp
499
500 /* Get the Trap Frame in EBX */
501 mov ebx, [ebp+0]
502
503 /* Get the exception list and restore */
504 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
505 mov PCR[KPCR_EXCEPTION_LIST], eax
506
507 /* Get the parameters */
508 mov edx, [ebp+16] /* Search frames */
509 mov ecx, [ebp+12] /* Context */
510 mov eax, [ebp+8] /* Exception Record */
511
512 /* Raise the exception */
513 push edx
514 push ebx
515 push 0
516 push ecx
517 push eax
518 call _KiRaiseException@20
519
520 /* Restore trap frame in EBP */
521 pop ebp
522 mov esp, ebp
523
524 /* Check the result */
525 or eax, eax
526 jz _KiServiceExit2
527
528 /* Restore debug registers too */
529 jmp _KiServiceExit
530 .endfunc
531
532 .func NtContinue@8
533 _NtContinue@8:
534
535 /* NOTE: We -must- be called by Zw* to have the right frame! */
536 /* Push the stack frame */
537 push ebp
538
539 /* Get the current thread and restore its trap frame */
540 mov ebx, PCR[KPCR_CURRENT_THREAD]
541 mov edx, [ebp+KTRAP_FRAME_EDX]
542 mov [ebx+KTHREAD_TRAP_FRAME], edx
543
544 /* Set up stack frame */
545 mov ebp, esp
546
547 /* Save the parameters */
548 mov eax, [ebp+0]
549 mov ecx, [ebp+8]
550
551 /* Call KiContinue */
552 push eax
553 push 0
554 push ecx
555 call _KiContinue@12
556
557 /* Check if we failed (bad context record) */
558 or eax, eax
559 jnz Error
560
561 /* Check if test alert was requested */
562 cmp dword ptr [ebp+12], 0
563 je DontTest
564
565 /* Test alert for the thread */
566 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
567 push eax
568 call _KeTestAlertThread@4
569
570 DontTest:
571 /* Return to previous context */
572 pop ebp
573 mov esp, ebp
574 jmp _KiServiceExit2
575
576 Error:
577 pop ebp
578 mov esp, ebp
579 jmp _KiServiceExit
580 .endfunc
581
582 /* EXCEPTION DISPATCHERS *****************************************************/
583
584 .func CommonDispatchException
585 _CommonDispatchException:
586
587 /* Make space for an exception record */
588 sub esp, EXCEPTION_RECORD_LENGTH
589
590 /* Set it up */
591 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
592 xor eax, eax
593 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
594 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
595 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
596 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
597
598 /* Check parameter count */
599 cmp ecx, 0
600 jz NoParams
601
602 /* Get information */
603 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
604 mov [ebx], edx
605 mov [ebx+4], esi
606 mov [ebx+8], edi
607
608 NoParams:
609
610 /* Set the record in ECX and check if this was V86 */
611 mov ecx, esp
612 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
613 jz SetPreviousMode
614
615 /* Set V86 mode */
616 mov eax, 0xFFFF
617 jmp MaskMode
618
619 SetPreviousMode:
620
621 /* Get the caller's CS */
622 mov eax, [ebp+KTRAP_FRAME_CS]
623
624 MaskMode:
625 /* Check if it was user-mode or kernel-mode */
626 and eax, MODE_MASK
627
628 /* Dispatch the exception */
629 push 1
630 push eax
631 push ebp
632 push 0
633 push ecx
634 call _KiDispatchException@20
635
636 /* End the trap */
637 mov esp, ebp
638 jmp _Kei386EoiHelper@0
639 .endfunc
640
641 .func DispatchNoParam
642 _DispatchNoParam:
643 /* Call the common dispatcher */
644 xor ecx, ecx
645 call _CommonDispatchException
646 .endfunc
647
648 .func DispatchOneParam
649 _DispatchOneParam:
650 /* Call the common dispatcher */
651 xor edx, edx
652 mov ecx, 1
653 call _CommonDispatchException
654 .endfunc
655
656 .func DispatchTwoParam
657 _DispatchTwoParam:
658 /* Call the common dispatcher */
659 xor edx, edx
660 mov ecx, 2
661 call _CommonDispatchException
662 .endfunc
663
664 /* HARDWARE TRAP HANDLERS ****************************************************/
665
666 .func KiFixupFrame
667 _KiFixupFrame:
668
669 /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
670 UNHANDLED_PATH
671 .endfunc
672
673 .func KiTrap0
674 TRAP_FIXUPS kit0_a, kit0_t, DoFixupV86, DoNotFixupAbios
675 _KiTrap0:
676 /* Push error code */
677 push 0
678
679 /* Enter trap */
680 TRAP_PROLOG kit0_a, kit0_t
681
682 /* Check for V86 */
683 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
684 jnz V86Int0
685
686 /* Check if the frame was from kernelmode */
687 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
688 jz SendException
689
690 /* Check the old mode */
691 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
692 jne VdmCheck
693
694 SendException:
695 /* Re-enable interrupts for user-mode and send the exception */
696 sti
697 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
698 mov ebx, [ebp+KTRAP_FRAME_EIP]
699 jmp _DispatchNoParam
700
701 VdmCheck:
702 /* Check if this is a VDM process */
703 mov ebx, PCR[KPCR_CURRENT_THREAD]
704 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
705 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
706 jz SendException
707
708 /* We don't support this yet! */
709 V86Int0:
710 /* FIXME: TODO */
711 UNHANDLED_PATH
712 .endfunc
713
714 .func KiTrap1
715 TRAP_FIXUPS kit1_a, kit1_t, DoFixupV86, DoNotFixupAbios
716 _KiTrap1:
717 /* Push error code */
718 push 0
719
720 /* Enter trap */
721 TRAP_PROLOG kit1_a, kit1_t
722
723 /* Check for V86 */
724 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
725 jnz V86Int1
726
727 /* Check if the frame was from kernelmode */
728 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
729 jz PrepInt1
730
731 /* Check the old mode */
732 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
733 jne V86Int1
734
735 EnableInterrupts:
736 /* Enable interrupts for user-mode */
737 sti
738
739 PrepInt1:
740 /* Prepare the exception */
741 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
742 mov ebx, [ebp+KTRAP_FRAME_EIP]
743 mov eax, STATUS_SINGLE_STEP
744 jmp _DispatchNoParam
745
746 V86Int1:
747 /* Check if this is a VDM process */
748 mov ebx, PCR[KPCR_CURRENT_THREAD]
749 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
750 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
751 jz EnableInterrupts
752
753 /* We don't support VDM! */
754 UNHANDLED_PATH
755 .endfunc
756
757 .globl _KiTrap2
758 .func KiTrap2
759 _KiTrap2:
760
761 /* FIXME: This is an NMI, nothing like a normal exception */
762 mov eax, 2
763 jmp _KiSystemFatalException
764 .endfunc
765
766 .func KiTrap3
767 TRAP_FIXUPS kit3_a, kit3_t, DoFixupV86, DoNotFixupAbios
768 _KiTrap3:
769 /* Push error code */
770 push 0
771
772 /* Enter trap */
773 TRAP_PROLOG kit3_a, kit3_t
774
775 /* Set status code */
776 mov eax, 0 //STATUS_SUCCESS
777
778 /* Check for V86 */
779 PrepareInt3:
780 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
781 jnz V86Int3
782
783 /* Check if the frame was from kernelmode */
784 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
785 jz PrepInt3
786
787 /* Check the old mode */
788 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
789 jne V86Int3
790
791 EnableInterrupts3:
792 /* Enable interrupts for user-mode */
793 sti
794
795 PrepInt3:
796
797 /* Prepare the exception */
798 mov esi, ecx
799 mov edi, edx
800 mov edx, eax
801
802 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
803 mov ebx, [ebp+KTRAP_FRAME_EIP]
804 dec ebx
805 mov ecx, 3
806 mov eax, STATUS_BREAKPOINT
807 call _CommonDispatchException
808
809 V86Int3:
810 /* Check if this is a VDM process */
811 mov ebx, PCR[KPCR_CURRENT_THREAD]
812 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
813 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
814 jz EnableInterrupts3
815
816 /* We don't support VDM! */
817 UNHANDLED_PATH
818 .endfunc
819
820 .func KiTrap4
821 TRAP_FIXUPS kit4_a, kit4_t, DoFixupV86, DoNotFixupAbios
822 _KiTrap4:
823 /* Push error code */
824 push 0
825
826 /* Enter trap */
827 TRAP_PROLOG kit4_a, kit4_t
828
829 /* Check for V86 */
830 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
831 jnz V86Int4
832
833 /* Check if the frame was from kernelmode */
834 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
835 jz SendException4
836
837 /* Check the old mode */
838 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
839 jne VdmCheck4
840
841 SendException4:
842 /* Re-enable interrupts for user-mode and send the exception */
843 sti
844 mov eax, STATUS_INTEGER_OVERFLOW
845 mov ebx, [ebp+KTRAP_FRAME_EIP]
846 dec ebx
847 jmp _DispatchNoParam
848
849 VdmCheck4:
850 /* Check if this is a VDM process */
851 mov ebx, PCR[KPCR_CURRENT_THREAD]
852 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
853 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
854 jz SendException4
855
856 /* We don't support this yet! */
857 V86Int4:
858 UNHANDLED_PATH
859 .endfunc
860
861 .func KiTrap5
862 TRAP_FIXUPS kit5_a, kit5_t, DoFixupV86, DoNotFixupAbios
863 _KiTrap5:
864 /* Push error code */
865 push 0
866
867 /* Enter trap */
868 TRAP_PROLOG kit5_a, kit5_t
869
870 /* Check for V86 */
871 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
872 jnz V86Int5
873
874 /* Check if the frame was from kernelmode */
875 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
876 jnz CheckMode
877
878 /* It did, and this should never happen */
879 mov eax, 5
880 jmp _KiSystemFatalException
881
882 /* Check the old mode */
883 CheckMode:
884 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
885 jne VdmCheck5
886
887 /* Re-enable interrupts for user-mode and send the exception */
888 SendException5:
889 sti
890 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
891 mov ebx, [ebp+KTRAP_FRAME_EIP]
892 jmp _DispatchNoParam
893
894 VdmCheck5:
895 /* Check if this is a VDM process */
896 mov ebx, PCR[KPCR_CURRENT_THREAD]
897 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
898 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
899 jz SendException5
900
901 /* We don't support this yet! */
902 V86Int5:
903 UNHANDLED_PATH
904 .endfunc
905
906 .func KiTrap6
907 TRAP_FIXUPS kit6_a, kit6_t, DoFixupV86, DoNotFixupAbios
908 _KiTrap6:
909
910 /* It this a V86 GPF? */
911 test dword ptr [esp+8], EFLAGS_V86_MASK
912 jz NotV86UD
913
914 /* Enter V86 Trap */
915 V86_TRAP_PROLOG kit6_a, kit6_v
916
917 /* Not yet supported (Invalid OPCODE from V86) */
918 UNHANDLED_PATH
919
920 NotV86UD:
921 /* Push error code */
922 push 0
923
924 /* Enter trap */
925 TRAP_PROLOG kit6_a, kit6_t
926
927 /* Check if this happened in kernel mode */
928 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
929 jz KmodeOpcode
930
931 /* Check for VDM */
932 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
933 jz UmodeOpcode
934
935 /* Check if the process is vDM */
936 mov ebx, PCR[KPCR_CURRENT_THREAD]
937 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
938 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
939 jnz IsVdmOpcode
940
941 UmodeOpcode:
942 /* Get EIP and enable interrupts at this point */
943 mov esi, [ebp+KTRAP_FRAME_EIP]
944 sti
945
946 /* Set intruction prefix length */
947 mov ecx, 4
948
949 /* Setup a SEH frame */
950 push ebp
951 push OpcodeSEH
952 push PCR[KPCR_EXCEPTION_LIST]
953 mov PCR[KPCR_EXCEPTION_LIST], esp
954
955 OpcodeLoop:
956 /* Get the instruction and check if it's LOCK */
957 mov al, [esi]
958 cmp al, 0xF0
959 jz LockCrash
960
961 /* Keep moving */
962 add esi, 1
963 loop OpcodeLoop
964
965 /* Undo SEH frame */
966 pop PCR[KPCR_EXCEPTION_LIST]
967 add esp, 8
968
969 KmodeOpcode:
970
971 /* Re-enable interrupts */
972 sti
973
974 /* Setup illegal instruction exception and dispatch it */
975 mov ebx, [ebp+KTRAP_FRAME_EIP]
976 mov eax, STATUS_ILLEGAL_INSTRUCTION
977 jmp _DispatchNoParam
978
979 LockCrash:
980
981 /* Undo SEH Frame */
982 pop PCR[KPCR_EXCEPTION_LIST]
983 add esp, 8
984
985 /* Setup invalid lock exception and dispatch it */
986 mov ebx, [ebp+KTRAP_FRAME_EIP]
987 mov eax, STATUS_INVALID_LOCK_SEQUENCE
988 jmp _DispatchNoParam
989
990 IsVdmOpcode:
991
992 /* Unhandled yet */
993 UNHANDLED_PATH
994
995 /* Return to caller */
996 jmp _Kei386EoiHelper@0
997
998 OpcodeSEH:
999
1000 /* Get SEH frame */
1001 mov esp, [esp+8]
1002 pop PCR[KPCR_EXCEPTION_LIST]
1003 add esp, 4
1004 pop ebp
1005
1006 /* Check if this was user mode */
1007 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1008 jnz KmodeOpcode
1009
1010 /* Do a bugcheck */
1011 push ebp
1012 push 0
1013 push 0
1014 push 0
1015 push 0
1016 push KMODE_EXCEPTION_NOT_HANDLED
1017 call _KeBugCheckWithTf@24
1018 .endfunc
1019
1020 .func KiTrap7
1021 TRAP_FIXUPS kit7_a, kit7_t, DoFixupV86, DoNotFixupAbios
1022 _KiTrap7:
1023 /* Push error code */
1024 push 0
1025
1026 /* Enter trap */
1027 TRAP_PROLOG kit7_a, kit7_t
1028
1029 /* Get the current thread and stack */
1030 StartTrapHandle:
1031 mov eax, PCR[KPCR_CURRENT_THREAD]
1032 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1033 sub ecx, NPX_FRAME_LENGTH
1034
1035 /* Check if emulation is enabled */
1036 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1037 jnz EmulationEnabled
1038
1039 CheckState:
1040 /* Check if the NPX state is loaded */
1041 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1042 mov ebx, cr0
1043 jz IsLoaded
1044
1045 /* Remove flags */
1046 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1047 mov cr0, ebx
1048
1049 /* Check the NPX thread */
1050 mov edx, PCR[KPCR_NPX_THREAD]
1051 or edx, edx
1052 jz NoNpxThread
1053
1054 /* Get the NPX Stack */
1055 mov esi, [edx+KTHREAD_INITIAL_STACK]
1056 sub esi, NPX_FRAME_LENGTH
1057
1058 /* Check if we have FXSR and check which operand to use */
1059 test byte ptr _KeI386FxsrPresent, 1
1060 jz FnSave
1061 fxsave [esi]
1062 jmp AfterSave
1063
1064 FnSave:
1065 fnsave [esi]
1066
1067 AfterSave:
1068 /* Set the thread's state to dirty */
1069 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1070
1071 NoNpxThread:
1072 /* Check if we have FXSR and choose which operand to use */
1073 test byte ptr _KeI386FxsrPresent, 1
1074 jz FrRestore
1075 fxrstor [ecx]
1076 jmp AfterRestore
1077
1078 FrRestore:
1079 frstor [esi]
1080
1081 AfterRestore:
1082 /* Set state loaded */
1083 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1084 mov PCR[KPCR_NPX_THREAD], eax
1085
1086 /* Enable interrupts to happen now */
1087 sti
1088 nop
1089
1090 /* Check if CR0 needs to be reloaded due to a context switch */
1091 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1092 jz _Kei386EoiHelper@0
1093
1094 /* We have to reload CR0... disable interrupts */
1095 cli
1096
1097 /* Get CR0 and update it */
1098 mov ebx, cr0
1099 or ebx, [ecx+FN_CR0_NPX_STATE]
1100 mov cr0, ebx
1101
1102 /* Restore interrupts and check if TS is back on */
1103 sti
1104 test bl, CR0_TS
1105 jz _Kei386EoiHelper@0
1106
1107 /* Clear TS, and loop handling again */
1108 clts
1109 cli
1110 jmp StartTrapHandle
1111
1112 KernelNpx:
1113
1114 /* Set delayed error */
1115 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1116
1117 /* Check if this happened during restore */
1118 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1119 jnz UserNpx
1120
1121 /* Skip instruction and dispatch the exception */
1122 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1123 jmp _Kei386EoiHelper@0
1124
1125 IsLoaded:
1126 /* Check if TS is set */
1127 test bl, CR0_TS
1128 jnz TsSetOnLoadedState
1129
1130 HandleNpxFault:
1131 /* Check if the trap came from V86 mode */
1132 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1133 jnz V86Npx
1134
1135 /* Check if it came from kernel mode */
1136 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1137 jz KernelNpx
1138
1139 /* Check if it came from a VDM */
1140 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1141 jne V86Npx
1142
1143 UserNpx:
1144 /* Get the current thread */
1145 mov eax, PCR[KPCR_CURRENT_THREAD]
1146
1147 /* Check NPX state */
1148 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1149
1150 /* Get the NPX save area */
1151 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1152 lea ecx, [ecx-NPX_FRAME_LENGTH]
1153 jz NoSaveRestore
1154
1155 HandleUserNpx:
1156
1157 /* Set new CR0 */
1158 mov ebx, cr0
1159 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1160 mov cr0, ebx
1161
1162 /* Check if we have FX support */
1163 test byte ptr _KeI386FxsrPresent, 1
1164 jz FnSave2
1165
1166 /* Save the state */
1167 fxsave [ecx]
1168 jmp MakeCr0Dirty
1169 FnSave2:
1170 fnsave [ecx]
1171 wait
1172
1173 MakeCr0Dirty:
1174 /* Make CR0 state not loaded */
1175 or ebx, NPX_STATE_NOT_LOADED
1176 or ebx, [ecx+FN_CR0_NPX_STATE]
1177 mov cr0, ebx
1178
1179 /* Update NPX state */
1180 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1181 mov dword ptr PCR[KPCR_NPX_THREAD], 0
1182
1183 NoSaveRestore:
1184 /* Clear the TS bit and re-enable interrupts */
1185 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1186 sti
1187
1188 /* Check if we have FX support */
1189 test byte ptr _KeI386FxsrPresent, 1
1190 jz FnError
1191
1192 /* Get error offset, control and status words */
1193 mov ebx, [ecx+FX_ERROR_OFFSET]
1194 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
1195 movzx edx, word ptr [ecx+FX_STATUS_WORD]
1196
1197 /* Get the faulting opcode */
1198 mov esi, [ecx+FX_DATA_OFFSET]
1199 jmp CheckError
1200
1201 FnError:
1202 /* Get error offset, control and status words */
1203 mov ebx, [ecx+FP_ERROR_OFFSET]
1204 movzx eax, word ptr [ecx+FP_CONTROL_WORD]
1205 movzx edx, word ptr [ecx+FP_STATUS_WORD]
1206
1207 /* Get the faulting opcode */
1208 mov esi, [ecx+FP_DATA_OFFSET]
1209
1210 CheckError:
1211 /* Mask exceptions */
1212 and eax, 0x3F
1213 not eax
1214 and eax, edx
1215
1216 /* Check if what's left is invalid */
1217 test al, 1
1218 jz ValidNpxOpcode
1219
1220 /* Check if it was a stack fault */
1221 test al, 64
1222 jnz InvalidStack
1223
1224 /* Raise exception */
1225 mov eax, STATUS_FLOAT_INVALID_OPERATION
1226 jmp _DispatchOneParam
1227
1228 InvalidStack:
1229
1230 /* Raise exception */
1231 mov eax, STATUS_FLOAT_STACK_CHECK
1232 jmp _DispatchTwoParam
1233
1234 ValidNpxOpcode:
1235
1236 /* Check for divide by 0 */
1237 test al, 4
1238 jz 1f
1239
1240 /* Raise exception */
1241 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1242 jmp _DispatchOneParam
1243
1244 1:
1245 /* Check for denormal */
1246 test al, 2
1247 jz 1f
1248
1249 /* Raise exception */
1250 mov eax, STATUS_FLOAT_INVALID_OPERATION
1251 jmp _DispatchOneParam
1252
1253 1:
1254 /* Check for overflow */
1255 test al, 8
1256 jz 1f
1257
1258 /* Raise exception */
1259 mov eax, STATUS_FLOAT_OVERFLOW
1260 jmp _DispatchOneParam
1261
1262 1:
1263 /* Check for underflow */
1264 test al, 16
1265 jz 1f
1266
1267 /* Raise exception */
1268 mov eax, STATUS_FLOAT_UNDERFLOW
1269 jmp _DispatchOneParam
1270
1271 1:
1272 /* Check for precision fault */
1273 test al, 32
1274 jz UnexpectedNpx
1275
1276 /* Raise exception */
1277 mov eax, STATUS_FLOAT_INEXACT_RESULT
1278 jmp _DispatchOneParam
1279
1280 UnexpectedNpx:
1281
1282 /* Strange result, bugcheck the OS */
1283 sti
1284 push ebp
1285 push 0
1286 push 0
1287 push eax
1288 push 1
1289 push TRAP_CAUSE_UNKNOWN
1290 call _KeBugCheckWithTf@24
1291
1292 V86Npx:
1293 /* Check if this is a VDM */
1294 mov eax, PCR[KPCR_CURRENT_THREAD]
1295 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
1296 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1297 jz HandleUserNpx
1298
1299 /* V86 NPX not handled */
1300 UNHANDLED_PATH
1301
1302 EmulationEnabled:
1303 /* Did this come from kernel-mode? */
1304 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1305 jz CheckState
1306
1307 /* It came from user-mode, so this would only be valid inside a VDM */
1308 /* Since we don't actually have VDMs in ROS, bugcheck. */
1309 jmp UnexpectedNpx
1310
1311 TsSetOnLoadedState:
1312 /* TS shouldn't be set, unless this we don't have a Math Processor */
1313 test bl, CR0_MP
1314 jnz BogusTrap
1315
1316 /* Strange that we got a trap at all, but ignore and continue */
1317 clts
1318 jmp _Kei386EoiHelper@0
1319
1320 BogusTrap:
1321 /* Cause a bugcheck */
1322 push 0
1323 push 0
1324 push ebx
1325 push 2
1326 push TRAP_CAUSE_UNKNOWN
1327 call _KeBugCheckEx@20
1328 .endfunc
1329
1330 .globl _KiTrap8
1331 .func KiTrap8
1332 _KiTrap8:
1333
1334 /* Can't really do too much */
1335 mov eax, 8
1336 jmp _KiSystemFatalException
1337 .endfunc
1338
1339 .func KiTrap9
1340 TRAP_FIXUPS kit9_a, kit9_t, DoFixupV86, DoNotFixupAbios
1341 _KiTrap9:
1342 /* Push error code */
1343 push 0
1344
1345 /* Enter trap */
1346 TRAP_PROLOG kit9_a, kit9_t
1347
1348 /* Enable interrupts and bugcheck */
1349 sti
1350 mov eax, 9
1351 jmp _KiSystemFatalException
1352 .endfunc
1353
1354 .func KiTrap10
1355 TRAP_FIXUPS kita_a, kita_t, DoFixupV86, DoNotFixupAbios
1356 _KiTrap10:
1357 /* Enter trap */
1358 TRAP_PROLOG kita_a, kita_t
1359
1360 /* Check for V86 */
1361 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1362 jnz V86IntA
1363
1364 /* Check if the frame was from kernelmode */
1365 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1366 jz Fatal
1367
1368 V86IntA:
1369 /* Check if OF was set during iretd */
1370 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1371 sti
1372 jz Fatal
1373
1374 /* It was, just mask it out */
1375 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1376 jmp _Kei386EoiHelper@0
1377
1378 Fatal:
1379 /* TSS failure for some other reason: crash */
1380 mov eax, 10
1381 jmp _KiSystemFatalException
1382 .endfunc
1383
1384 .func KiTrap11
1385 TRAP_FIXUPS kitb_a, kitb_t, DoFixupV86, DoNotFixupAbios
1386 _KiTrap11:
1387 /* Enter trap */
1388 TRAP_PROLOG kitb_a, kitb_t
1389
1390 /* FIXME: ROS Doesn't handle segment faults yet */
1391 mov eax, 11
1392 jmp _KiSystemFatalException
1393 .endfunc
1394
1395 .func KiTrap12
1396 TRAP_FIXUPS kitc_a, kitc_t, DoFixupV86, DoNotFixupAbios
1397 _KiTrap12:
1398 /* Enter trap */
1399 TRAP_PROLOG kitc_a, kitc_t
1400
1401 /* FIXME: ROS Doesn't handle stack faults yet */
1402 mov eax, 12
1403 jmp _KiSystemFatalException
1404 .endfunc
1405
1406 .func KiTrapExceptHandler
1407 _KiTrapExceptHandler:
1408
1409 /* Setup SEH handler frame */
1410 mov esp, [esp+8]
1411 pop PCR[KPCR_EXCEPTION_LIST]
1412 add esp, 4
1413 pop ebp
1414
1415 /* Check if the fault came from user mode */
1416 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1417 jnz SetException
1418
1419 /* Kernel fault, bugcheck */
1420 push ebp
1421 push 0
1422 push 0
1423 push 0
1424 push 0
1425 push KMODE_EXCEPTION_NOT_HANDLED
1426 call _KeBugCheckWithTf@24
1427 .endfunc
1428
1429 .func KiTrap13
1430 TRAP_FIXUPS kitd_a, kitd_t, DoFixupV86, DoNotFixupAbios
1431 _KiTrap13:
1432
1433 /* It this a V86 GPF? */
1434 test dword ptr [esp+12], EFLAGS_V86_MASK
1435 jz NotV86
1436
1437 /* Enter V86 Trap */
1438 V86_TRAP_PROLOG kitd_a, kitd_v
1439
1440 /* Make sure that this is a V86 process */
1441 mov ecx, PCR[KPCR_CURRENT_THREAD]
1442 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1443 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1444 jnz RaiseIrql
1445
1446 /* Otherwise, something is very wrong, raise an exception */
1447 sti
1448 mov ebx, [ebp+KTRAP_FRAME_EIP]
1449 mov esi, -1
1450 mov eax, STATUS_ACCESS_VIOLATION
1451 jmp _DispatchTwoParam
1452
1453 RaiseIrql:
1454
1455 /* Go to APC level */
1456 mov ecx, APC_LEVEL
1457 call @KfRaiseIrql@4
1458
1459 /* Save old IRQL and enable interrupts */
1460 push eax
1461 sti
1462
1463 /* Handle the opcode */
1464 call _Ki386HandleOpcodeV86@0
1465
1466 /* Check if this was VDM */
1467 test al, 0xFF
1468 jnz NoReflect
1469
1470 /* FIXME: TODO */
1471 UNHANDLED_PATH
1472
1473 NoReflect:
1474
1475 /* Lower IRQL and disable interrupts */
1476 pop ecx
1477 call @KfLowerIrql@4
1478 cli
1479
1480 /* Check if this was a V86 trap */
1481 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1482 jz NotV86Trap
1483
1484 /* Exit the V86 Trap */
1485 V86_TRAP_EPILOG
1486
1487 NotV86Trap:
1488
1489 /* Either this wasn't V86, or it was, but an APC interrupted us */
1490 jmp _Kei386EoiHelper@0
1491
1492 NotV86:
1493 /* Enter trap */
1494 TRAP_PROLOG kitd_a, kitd_t
1495
1496 /* Check if this was from kernel-mode */
1497 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1498 jnz UserModeGpf
1499
1500 /* Check if we have a VDM alert */
1501 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1502 jnz VdmAlertGpf
1503
1504 /* Check for GPF during GPF */
1505 mov eax, [ebp+KTRAP_FRAME_EIP]
1506 cmp eax, offset CheckPrivilegedInstruction
1507 jbe KmodeGpf
1508 cmp eax, offset CheckPrivilegedInstruction2
1509
1510 /* FIXME: TODO */
1511 UNHANDLED_PATH
1512
1513 /* Get the opcode and trap frame */
1514 KmodeGpf:
1515 mov eax, [ebp+KTRAP_FRAME_EIP]
1516 mov eax, [eax]
1517 mov edx, [ebp+KTRAP_FRAME_EBP]
1518
1519 /* We want to check if this was POP [DS/ES/FS/GS] */
1520 add edx, KTRAP_FRAME_DS
1521 cmp al, 0x1F
1522 jz SegPopGpf
1523 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1524 cmp al, 7
1525 jz SegPopGpf
1526 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1527 cmp ax, 0xA10F
1528 jz SegPopGpf
1529 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1530 cmp ax, 0xA90F
1531 jz SegPopGpf
1532
1533 /* It isn't, was it IRETD? */
1534 cmp al, 0xCF
1535 jne NotIretGpf
1536
1537 /* Get error code */
1538 lea edx, [ebp+KTRAP_FRAME_ESP]
1539 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1540 and ax, ~RPL_MASK
1541
1542 /* Get CS */
1543 mov cx, word ptr [edx+4]
1544 and cx, ~RPL_MASK
1545 cmp cx, ax
1546 jnz NotCsGpf
1547
1548 /* This should be a Ki386CallBios return */
1549 mov eax, offset _Ki386BiosCallReturnAddress
1550 cmp eax, [edx]
1551 jne NotBiosGpf
1552 mov eax, [edx+4]
1553 cmp ax, KGDT_R0_CODE + RPL_MASK
1554 jne NotBiosGpf
1555
1556 /* Jump to return address */
1557 jmp _Ki386BiosCallReturnAddress
1558
1559 NotBiosGpf:
1560 /* Check if the thread was in kernel mode */
1561 mov ebx, PCR[KPCR_CURRENT_THREAD]
1562 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1563 jz UserModeGpf
1564
1565 /* Set RPL_MASK for check below */
1566 or word ptr [edx+4], RPL_MASK
1567
1568 NotCsGpf:
1569 /* Check if the IRET goes to user-mode */
1570 test dword ptr [edx+4], RPL_MASK
1571 jz UserModeGpf
1572
1573 /* Setup trap frame to copy */
1574 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1575 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1576
1577 TrapCopy:
1578
1579 /* Copy each field */
1580 mov eax, [edx]
1581 mov [edx+12], eax
1582 sub edx, 4
1583 loop TrapCopy
1584
1585 /* Enable interrupts and adjust stack */
1586 sti
1587 add esp, 12
1588 add ebp, 12
1589
1590 /* Setup exception record */
1591 mov ebx, [ebp+KTRAP_FRAME_EIP]
1592 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1593 and esi, 0xFFFF
1594 mov eax, STATUS_ACCESS_VIOLATION
1595 jmp _DispatchTwoParam
1596
1597 MsrCheck:
1598
1599 /* FIXME: Handle RDMSR/WRMSR */
1600 UNHANDLED_PATH
1601
1602 NotIretGpf:
1603
1604 /* Check if this was an MSR opcode */
1605 cmp al, 0xF
1606 jz MsrCheck
1607
1608 /* Check if DS is Ring 3 */
1609 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1610 jz CheckEs
1611
1612 /* Otherwise, fix it up */
1613 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1614 jmp ExitGpfTrap
1615
1616 CheckEs:
1617
1618 /* Check if ES is Ring 3 */
1619 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1620 jz UserModeGpf
1621
1622 /* Otherwise, fix it up */
1623 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1624 jmp ExitGpfTrap
1625
1626 SegPopGpf:
1627
1628 /* Sanity check */
1629 lea eax, [ebp+KTRAP_FRAME_ESP]
1630 cmp edx, eax
1631 jz HandleSegPop
1632 int 3
1633
1634 /* Handle segment POP fault by setting it to 0 */
1635 HandleSegPop:
1636 xor eax, eax
1637 mov dword ptr [edx], eax
1638
1639 ExitGpfTrap:
1640
1641 /* Do a trap exit */
1642 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1643
1644 UserModeGpf:
1645
1646 /* If the previous mode was kernel, raise a fatal exception */
1647 mov eax, 13
1648 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1649 jz _KiSystemFatalException
1650
1651 /* Get the process and check which CS this came from */
1652 mov ebx, PCR[KPCR_CURRENT_THREAD]
1653 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1654 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1655 jz CheckVdmGpf
1656
1657 /* Check if this is a VDM */
1658 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1659 jnz DispatchV86Gpf
1660
1661 /* Enable interrupts and check if we have an error code */
1662 sti
1663 cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
1664 jnz SetException
1665 jmp CheckPrivilegedInstruction
1666
1667 HandleSegPop2:
1668 /* Update EIP (will be updated below again) */
1669 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1670
1671 HandleEsPop:
1672 /* Clear the segment, update EIP and ESP */
1673 mov dword ptr [edx], 0
1674 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1675 add dword ptr [ebp+KTRAP_FRAME_ESP], 4
1676 jmp _Kei386EoiHelper@0
1677
1678 CheckVdmGpf:
1679 /* Check if this is a VDM */
1680 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1681 jz CheckPrivilegedInstruction
1682
1683 /* Bring interrupts back */
1684 sti
1685
1686 /* Check what kind of instruction this is */
1687 mov eax, [ebp+KTRAP_FRAME_EIP]
1688 mov eax, [eax]
1689
1690 /* FIXME: Check for BOP4 */
1691
1692 /* Check if this is POP ES */
1693 mov edx, ebp
1694 add edx, KTRAP_FRAME_ES
1695 cmp al, 0x07
1696 jz HandleEsPop
1697
1698 /* Check if this is POP FS */
1699 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1700 cmp ax, 0xA10F
1701 jz HandleSegPop2
1702
1703 /* Check if this is POP GS */
1704 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1705 cmp ax, 0xA90F
1706 jz HandleSegPop2
1707
1708 CheckPrivilegedInstruction:
1709 /* Bring interrupts back */
1710 sti
1711
1712 /* Setup a SEH handler */
1713 push ebp
1714 push offset _KiTrapExceptHandler
1715 push PCR[KPCR_EXCEPTION_LIST]
1716 mov PCR[KPCR_EXCEPTION_LIST], esp
1717
1718 /* Get EIP */
1719 mov esi, [ebp+KTRAP_FRAME_EIP]
1720
1721 /* Setup loop count */
1722 mov ecx, 15
1723
1724 InstLoop:
1725 /* Save loop count */
1726 push ecx
1727
1728 /* Get the instruction */
1729 lods byte ptr [esi]
1730
1731 /* Now lookup in the prefix table */
1732 mov ecx, 11
1733 mov edi, offset _KiTrapPrefixTable
1734 repnz scasb
1735
1736 /* Restore loop count */
1737 pop ecx
1738
1739 /* If it's not a prefix byte, check other instructions */
1740 jnz NotPrefixByte
1741
1742 /* FIXME */
1743 UNHANDLED_PATH
1744
1745 NotPrefixByte:
1746 /* FIXME: Check if it's a HLT */
1747
1748 /* Check if the instruction has two bytes */
1749 cmp al, 0xF
1750 jne CheckRing3Io
1751
1752 /* FIXME */
1753 UNHANDLED_PATH
1754
1755 CheckRing3Io:
1756 /* Get EFLAGS and IOPL */
1757 mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
1758 and ebx, 0x3000
1759 shr ebx, 12
1760
1761 /* Check the CS's RPL mask */
1762 mov ecx, [ebp+KTRAP_FRAME_CS]
1763 and ecx, RPL_MASK
1764 cmp ebx, ecx
1765 jge NotIoViolation
1766
1767 CheckPrivilegedInstruction2:
1768 /* Check if this is a CLI or STI */
1769 cmp al, 0xFA
1770 je IsPrivInstruction
1771 cmp al, 0xFB
1772 je IsPrivInstruction
1773
1774 /* Setup I/O table lookup */
1775 mov ecx, 13
1776 mov edi, offset _KiTrapIoTable
1777
1778 /* Loopup in the table */
1779 repnz scasb
1780 jnz NotIoViolation
1781
1782 /* FIXME: Check IOPM!!! */
1783
1784 IsPrivInstruction:
1785 /* Cleanup the SEH frame */
1786 pop PCR[KPCR_EXCEPTION_LIST]
1787 add esp, 8
1788
1789 /* Setup the exception */
1790 mov ebx, [ebp+KTRAP_FRAME_EIP]
1791 mov eax, STATUS_PRIVILEGED_INSTRUCTION
1792 jmp _DispatchNoParam
1793
1794 NotIoViolation:
1795 /* Cleanup the SEH frame */
1796 pop PCR[KPCR_EXCEPTION_LIST]
1797 add esp, 8
1798
1799 SetException:
1800 /* Setup the exception */
1801 mov ebx, [ebp+KTRAP_FRAME_EIP]
1802 mov esi, -1
1803 mov eax, STATUS_ACCESS_VIOLATION
1804 jmp _DispatchTwoParam
1805
1806 DispatchV86Gpf:
1807 /* FIXME */
1808 UNHANDLED_PATH
1809 .endfunc
1810
1811 .func KiTrap14
1812 TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
1813 _KiTrap14:
1814
1815 /* Enter trap */
1816 TRAP_PROLOG kite_a, kite_t
1817
1818 /* Check if we have a VDM alert */
1819 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1820 jnz VdmAlertGpf
1821
1822 /* Get the current thread */
1823 mov edi, PCR[KPCR_CURRENT_THREAD]
1824
1825 /* Get the stack address of the frame */
1826 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
1827 sub eax, [edi+KTHREAD_INITIAL_STACK]
1828 jz NoFixUp
1829
1830 /* This isn't the base frame, check if it's the second */
1831 cmp eax, -KTRAP_FRAME_EFLAGS
1832 jb NoFixUp
1833
1834 /* Check if we have a TEB */
1835 mov eax, PCR[KPCR_TEB]
1836 or eax, eax
1837 jle NoFixUp
1838
1839 /* Fixup the frame */
1840 call _KiFixupFrame
1841
1842 /* Save CR2 */
1843 NoFixUp:
1844 mov edi, cr2
1845
1846 /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
1847 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1848 je HandlePf
1849
1850 /* Enable interrupts and check if we got here with interrupts disabled */
1851 sti
1852 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1853 jz IllegalState
1854
1855 HandlePf:
1856 /* Send trap frame and check if this is kernel-mode or usermode */
1857 push ebp
1858 mov eax, [ebp+KTRAP_FRAME_CS]
1859 and eax, MODE_MASK
1860 push eax
1861
1862 /* Send faulting address and check if this is read or write */
1863 push edi
1864 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
1865 and eax, 1
1866 push eax
1867
1868 /* Call the access fault handler */
1869 call _MmAccessFault@16
1870 test eax, eax
1871 jl AccessFail
1872
1873 /* Access fault handled, return to caller */
1874 jmp _Kei386EoiHelper@0
1875
1876 AccessFail:
1877 /* First check if this is a fault in the S-LIST functions */
1878 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
1879 cmp [ebp+KTRAP_FRAME_EIP], ecx
1880 jz SlistFault
1881
1882 /* Check if this is a fault in the syscall handler */
1883 mov ecx, offset CopyParams
1884 cmp [ebp+KTRAP_FRAME_EIP], ecx
1885 jz SysCallCopyFault
1886 mov ecx, offset ReadBatch
1887 cmp [ebp+KTRAP_FRAME_EIP], ecx
1888 jnz CheckVdmPf
1889
1890 /* FIXME: TODO */
1891 UNHANDLED_PATH
1892 jmp _Kei386EoiHelper@0
1893
1894 SysCallCopyFault:
1895 /* FIXME: TODO */
1896 UNHANDLED_PATH
1897 jmp _Kei386EoiHelper@0
1898
1899 /* Check if the fault occured in a V86 mode */
1900 CheckVdmPf:
1901 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
1902 and ecx, 1
1903 shr ecx, 1
1904 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1905 jnz VdmPF
1906
1907 /* Check if the fault occured in a VDM */
1908 mov esi, PCR[KPCR_CURRENT_THREAD]
1909 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
1910 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
1911 jz CheckStatus
1912
1913 /* Check if we this was in kernel-mode */
1914 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1915 jz CheckStatus
1916 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1917 jz CheckStatus
1918
1919 VdmPF:
1920 /* FIXME: TODO */
1921 UNHANDLED_PATH
1922
1923 /* Save EIP and check what kind of status failure we got */
1924 CheckStatus:
1925 mov esi, [ebp+KTRAP_FRAME_EIP]
1926 cmp eax, STATUS_ACCESS_VIOLATION
1927 je AccessViol
1928 cmp eax, STATUS_GUARD_PAGE_VIOLATION
1929 je SpecialCode
1930 cmp eax, STATUS_STACK_OVERFLOW
1931 je SpecialCode
1932
1933 /* Setup an in-page exception to dispatch */
1934 mov edx, ecx
1935 mov ebx, esi
1936 mov esi, edi
1937 mov ecx, 3
1938 mov edi, eax
1939 mov eax, STATUS_IN_PAGE_ERROR
1940 call _CommonDispatchException
1941
1942 AccessViol:
1943 /* Use more proper status code */
1944 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
1945
1946 SpecialCode:
1947 /* Setup a normal page fault exception */
1948 mov ebx, esi
1949 mov edx, ecx
1950 mov esi, edi
1951 jmp _DispatchTwoParam
1952
1953 SlistFault:
1954 /* FIXME: TODO */
1955 UNHANDLED_PATH
1956
1957 IllegalState:
1958
1959 /* This is completely illegal, bugcheck the system */
1960 push ebp
1961 push esi
1962 push ecx
1963 push eax
1964 push edi
1965 push IRQL_NOT_LESS_OR_EQUAL
1966 call _KeBugCheckWithTf@24
1967
1968 VdmAlertGpf:
1969
1970 /* FIXME: NOT SUPPORTED */
1971 UNHANDLED_PATH
1972 .endfunc
1973
1974 .func KiTrap0F
1975 TRAP_FIXUPS kitf_a, kitf_t, DoFixupV86, DoNotFixupAbios
1976 _KiTrap0F:
1977 /* Push error code */
1978 push 0
1979
1980 /* Enter trap */
1981 TRAP_PROLOG kitf_a, kitf_t
1982 sti
1983
1984 /* Raise a fatal exception */
1985 mov eax, 15
1986 jmp _KiSystemFatalException
1987 .endfunc
1988
1989 .func KiTrap16
1990 TRAP_FIXUPS kit10_a, kit10_t, DoFixupV86, DoNotFixupAbios
1991 _KiTrap16:
1992 /* Push error code */
1993 push 0
1994
1995 /* Enter trap */
1996 TRAP_PROLOG kit10_a, kit10_t
1997
1998 /* Check if this is the NPX Thread */
1999 mov eax, PCR[KPCR_CURRENT_THREAD]
2000 cmp eax, PCR[KPCR_NPX_THREAD]
2001
2002 /* Get the initial stack and NPX frame */
2003 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2004 lea ecx, [ecx-NPX_FRAME_LENGTH]
2005
2006 /* If this is a valid fault, handle it */
2007 jz HandleNpxFault
2008
2009 /* Otherwise, re-enable interrupts and set delayed error */
2010 sti
2011 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
2012 jmp _Kei386EoiHelper@0
2013 .endfunc
2014
2015 .func KiTrap17
2016 TRAP_FIXUPS kit11_a, kit11_t, DoFixupV86, DoNotFixupAbios
2017 _KiTrap17:
2018 /* Push error code */
2019 push 0
2020
2021 /* Enter trap */
2022 TRAP_PROLOG kit11_a, kit11_t
2023
2024 /* FIXME: ROS Doesn't handle alignment faults yet */
2025 mov eax, 17
2026 jmp _KiSystemFatalException
2027 .endfunc
2028
2029 .func KiSystemFatalException
2030 _KiSystemFatalException:
2031
2032 /* Push the trap frame */
2033 push ebp
2034
2035 /* Push empty parameters */
2036 push 0
2037 push 0
2038 push 0
2039
2040 /* Push trap number and bugcheck code */
2041 push eax
2042 push UNEXPECTED_KERNEL_MODE_TRAP
2043 call _KeBugCheckWithTf@24
2044 ret
2045 .endfunc
2046
2047 .func KiCoprocessorError@0
2048 _KiCoprocessorError@0:
2049
2050 /* Get the NPX Thread's Initial stack */
2051 mov eax, PCR[KPCR_NPX_THREAD]
2052 mov eax, [eax+KTHREAD_INITIAL_STACK]
2053
2054 /* Make space for the FPU Save area */
2055 sub eax, SIZEOF_FX_SAVE_AREA
2056
2057 /* Set the CR0 State */
2058 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
2059
2060 /* Update it */
2061 mov eax, cr0
2062 or eax, 8
2063 mov cr0, eax
2064
2065 /* Return to caller */
2066 ret
2067 .endfunc
2068
2069 .func Ki16BitStackException
2070 _Ki16BitStackException:
2071
2072 /* Save stack */
2073 push ss
2074 push esp
2075
2076 /* Go to kernel mode thread stack */
2077 mov eax, PCR[KPCR_CURRENT_THREAD]
2078 add esp, [eax+KTHREAD_INITIAL_STACK]
2079
2080 /* Switch to good stack segment */
2081 UNHANDLED_PATH
2082 .endfunc
2083
2084 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
2085
2086 .globl _KiStartUnexpectedRange@0
2087 _KiStartUnexpectedRange@0:
2088
2089 GENERATE_INT_HANDLERS
2090
2091 .globl _KiEndUnexpectedRange@0
2092 _KiEndUnexpectedRange@0:
2093 jmp _KiUnexpectedInterruptTail
2094
2095 .func KiUnexpectedInterruptTail
2096 TRAP_FIXUPS kui_a, kui_t, DoFixupV86, DoFixupAbios
2097 _KiUnexpectedInterruptTail:
2098
2099 /* Enter interrupt trap */
2100 INT_PROLOG kui_a, kui_t, DoNotPushFakeErrorCode
2101
2102 /* Increase interrupt count */
2103 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2104
2105 /* Put vector in EBX and make space for KIRQL */
2106 mov ebx, [esp]
2107 sub esp, 4
2108
2109 /* Begin interrupt */
2110 push esp
2111 push ebx
2112 push HIGH_LEVEL
2113 call _HalBeginSystemInterrupt@12
2114
2115 /* Check if it was spurious or not */
2116 or al, al
2117 jnz Handled
2118
2119 /* Spurious, ignore it */
2120 add esp, 8
2121 jmp _Kei386EoiHelper2ndEntry
2122
2123 Handled:
2124 /* Unexpected interrupt, print a message on debug builds */
2125 #if DBG
2126 push [esp+4]
2127 push offset _UnexpectedMsg
2128 call _DbgPrint
2129 add esp, 8
2130 #endif
2131
2132 /* Exit the interrupt */
2133 mov esi, $
2134 cli
2135 call _HalEndSystemInterrupt@8
2136 jmp _Kei386EoiHelper@0
2137 .endfunc
2138
2139 .globl _KiUnexpectedInterrupt
2140 _KiUnexpectedInterrupt:
2141
2142 /* Bugcheck with invalid interrupt code */
2143 push TRAP_CAUSE_UNKNOWN
2144 call _KeBugCheck@4
2145
2146 /* INTERRUPT HANDLERS ********************************************************/
2147
2148 .func KiDispatchInterrupt@0
2149 _KiDispatchInterrupt@0:
2150
2151 /* Get the PCR and disable interrupts */
2152 mov ebx, PCR[KPCR_SELF]
2153 cli
2154
2155 /* Check if we have to deliver DPCs, timers, or deferred threads */
2156 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
2157 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
2158 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
2159 jz CheckQuantum
2160
2161 /* Save stack pointer and exception list, then clear it */
2162 push ebp
2163 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
2164 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
2165
2166 /* Save the stack and switch to the DPC Stack */
2167 mov edx, esp
2168 mov esp, [ebx+KPCR_PRCB_DPC_STACK]
2169 push edx
2170
2171 /* Deliver DPCs */
2172 mov ecx, [ebx+KPCR_PRCB]
2173 call @KiRetireDpcList@4
2174
2175 /* Restore stack and exception list */
2176 pop esp
2177 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
2178 pop ebp
2179
2180 CheckQuantum:
2181
2182 /* Re-enable interrupts */
2183 sti
2184
2185 /* Check if we have quantum end */
2186 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2187 jnz QuantumEnd
2188
2189 /* Check if we have a thread to swap to */
2190 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2191 je Return
2192
2193 /* Make space on the stack to save registers */
2194 sub esp, 3 * 4
2195 mov [esp+8], esi
2196 mov [esp+4], edi
2197 mov [esp+0], ebp
2198
2199 /* Get the current thread */
2200 mov edi, [ebx+KPCR_CURRENT_THREAD]
2201
2202 #ifdef CONFIG_SMP
2203 #error SMP Interrupt not handled!
2204 #endif
2205
2206 /* Get the next thread and clear it */
2207 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
2208 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2209
2210 /* Set us as the current running thread */
2211 mov [ebx+KPCR_CURRENT_THREAD], esi
2212 mov byte ptr [esi+KTHREAD_STATE], Running
2213 mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
2214
2215 /* Put thread in ECX and get the PRCB in EDX */
2216 mov ecx, edi
2217 lea edx, [ebx+KPCR_PRCB_DATA]
2218 call @KiQueueReadyThread@8
2219
2220 /* Set APC_LEVEL and do the swap */
2221 mov cl, APC_LEVEL
2222 call @KiSwapContextInternal@0
2223
2224 /* Restore registers */
2225 mov ebp, [esp+0]
2226 mov edi, [esp+4]
2227 mov esi, [esp+8]
2228 add esp, 3*4
2229
2230 Return:
2231 /* All done */
2232 ret
2233
2234 QuantumEnd:
2235 /* Disable quantum end and process it */
2236 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2237 call _KiQuantumEnd@0
2238 ret
2239 .endfunc
2240
2241 .func KiInterruptTemplate
2242 _KiInterruptTemplate:
2243
2244 /* Enter interrupt trap */
2245 INT_PROLOG kit_a, kit_t, DoPushFakeErrorCode
2246
2247 _KiInterruptTemplate2ndDispatch:
2248 /* Dummy code, will be replaced by the address of the KINTERRUPT */
2249 mov edi, 0
2250
2251 _KiInterruptTemplateObject:
2252 /* Dummy jump, will be replaced by the actual jump */
2253 jmp _KeSynchronizeExecution@12
2254
2255 _KiInterruptTemplateDispatch:
2256 /* Marks the end of the template so that the jump above can be edited */
2257
2258 TRAP_FIXUPS kit_a, kit_t, DoFixupV86, DoFixupAbios
2259 .endfunc
2260
2261 .func KiChainedDispatch2ndLvl@0
2262 _KiChainedDispatch2ndLvl@0:
2263
2264 /* Not yet supported */
2265 UNHANDLED_PATH
2266 .endfunc
2267
2268 .func KiChainedDispatch@0
2269 _KiChainedDispatch@0:
2270
2271 /* Increase interrupt count */
2272 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2273
2274 /* Save trap frame */
2275 mov ebp, esp
2276
2277 /* Save vector and IRQL */
2278 mov eax, [edi+KINTERRUPT_VECTOR]
2279 mov ecx, [edi+KINTERRUPT_IRQL]
2280
2281 /* Save old irql */
2282 push eax
2283 sub esp, 4
2284
2285 /* Begin interrupt */
2286 push esp
2287 push eax
2288 push ecx
2289 call _HalBeginSystemInterrupt@12
2290
2291 /* Check if it was handled */
2292 or al, al
2293 jz SpuriousInt
2294
2295 /* Call the 2nd-level handler */
2296 call _KiChainedDispatch2ndLvl@0
2297
2298 /* Exit the interrupt */
2299 INT_EPILOG 0
2300 .endfunc
2301
2302 .func KiInterruptDispatch@0
2303 _KiInterruptDispatch@0:
2304
2305 /* Increase interrupt count */
2306 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2307
2308 /* Save trap frame */
2309 mov ebp, esp
2310
2311 /* Save vector and IRQL */
2312 mov eax, [edi+KINTERRUPT_VECTOR]
2313 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2314
2315 /* Save old irql */
2316 push eax
2317 sub esp, 4
2318
2319 /* Begin interrupt */
2320 push esp
2321 push eax
2322 push ecx
2323 call _HalBeginSystemInterrupt@12
2324
2325 /* Check if it was handled */
2326 or al, al
2327 jz SpuriousInt
2328
2329 /* Acquire the lock */
2330 GetIntLock:
2331 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2332 ACQUIRE_SPINLOCK(esi, IntSpin)
2333
2334 /* Make sure that this interrupt isn't storming */
2335 VERIFY_INT kid
2336
2337 /* Save the tick count */
2338 mov ebx, _KeTickCount
2339
2340 /* Call the ISR */
2341 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2342 push eax
2343 push edi
2344 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2345
2346 /* Check if the ISR timed out */
2347 add ebx, _KiISRTimeout
2348 cmp _KeTickCount, ebx
2349 jnc IsrTimeout
2350
2351 ReleaseLock:
2352 /* Release the lock */
2353 RELEASE_SPINLOCK(esi)
2354
2355 /* Exit the interrupt */
2356 INT_EPILOG 0
2357
2358 SpuriousInt:
2359 /* Exit the interrupt */
2360 add esp, 8
2361 INT_EPILOG 1
2362
2363 #ifdef CONFIG_SMP
2364 IntSpin:
2365 SPIN_ON_LOCK esi, GetIntLock
2366 #endif
2367
2368 IsrTimeout:
2369 /* Print warning message */
2370 push [edi+KINTERRUPT_SERVICE_ROUTINE]
2371 push offset _IsrTimeoutMsg
2372 call _DbgPrint
2373 add esp,8
2374
2375 /* Break into debugger, then continue */
2376 int 3
2377 jmp ReleaseLock
2378
2379 /* Cleanup verification */
2380 VERIFY_INT_END kid, 0
2381 .endfunc