- New ISR Timeout detection code.
[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 Dr_kss: DR_TRAP_FIXUP
140 _KiSystemService:
141
142 /* Enter the shared system call prolog */
143 SYSCALL_PROLOG kss
144
145 /* Jump to the actual handler */
146 jmp SharedCode
147 .endfunc
148
149 .func KiFastCallEntry
150 Dr_FastCallDrSave: DR_TRAP_FIXUP
151 _KiFastCallEntry:
152
153 /* Enter the fast system call prolog */
154 FASTCALL_PROLOG FastCallDrSave
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 Dr_kids: DR_TRAP_FIXUP
465 V86_kids: V86_TRAP_FIXUP
466 _KiDebugService:
467
468 /* Push error code */
469 push 0
470
471 /* Enter trap */
472 TRAP_PROLOG kids
473
474 /* Increase EIP so we skip the INT3 */
475 inc dword ptr [ebp+KTRAP_FRAME_EIP]
476
477 /* Call debug service dispatcher */
478 mov eax, [ebp+KTRAP_FRAME_EAX]
479 mov ecx, [ebp+KTRAP_FRAME_ECX]
480 mov edx, [ebp+KTRAP_FRAME_EDX]
481
482 /* Jump to INT3 handler */
483 jmp PrepareInt3
484 .endfunc
485
486 .func NtRaiseException@12
487 _NtRaiseException@12:
488
489 /* NOTE: We -must- be called by Zw* to have the right frame! */
490 /* Push the stack frame */
491 push ebp
492
493 /* Get the current thread and restore its trap frame */
494 mov ebx, PCR[KPCR_CURRENT_THREAD]
495 mov edx, [ebp+KTRAP_FRAME_EDX]
496 mov [ebx+KTHREAD_TRAP_FRAME], edx
497
498 /* Set up stack frame */
499 mov ebp, esp
500
501 /* Get the Trap Frame in EBX */
502 mov ebx, [ebp+0]
503
504 /* Get the exception list and restore */
505 mov eax, [ebx+KTRAP_FRAME_EXCEPTION_LIST]
506 mov PCR[KPCR_EXCEPTION_LIST], eax
507
508 /* Get the parameters */
509 mov edx, [ebp+16] /* Search frames */
510 mov ecx, [ebp+12] /* Context */
511 mov eax, [ebp+8] /* Exception Record */
512
513 /* Raise the exception */
514 push edx
515 push ebx
516 push 0
517 push ecx
518 push eax
519 call _KiRaiseException@20
520
521 /* Restore trap frame in EBP */
522 pop ebp
523 mov esp, ebp
524
525 /* Check the result */
526 or eax, eax
527 jz _KiServiceExit2
528
529 /* Restore debug registers too */
530 jmp _KiServiceExit
531 .endfunc
532
533 .func NtContinue@8
534 _NtContinue@8:
535
536 /* NOTE: We -must- be called by Zw* to have the right frame! */
537 /* Push the stack frame */
538 push ebp
539
540 /* Get the current thread and restore its trap frame */
541 mov ebx, PCR[KPCR_CURRENT_THREAD]
542 mov edx, [ebp+KTRAP_FRAME_EDX]
543 mov [ebx+KTHREAD_TRAP_FRAME], edx
544
545 /* Set up stack frame */
546 mov ebp, esp
547
548 /* Save the parameters */
549 mov eax, [ebp+0]
550 mov ecx, [ebp+8]
551
552 /* Call KiContinue */
553 push eax
554 push 0
555 push ecx
556 call _KiContinue@12
557
558 /* Check if we failed (bad context record) */
559 or eax, eax
560 jnz Error
561
562 /* Check if test alert was requested */
563 cmp dword ptr [ebp+12], 0
564 je DontTest
565
566 /* Test alert for the thread */
567 mov al, [ebx+KTHREAD_PREVIOUS_MODE]
568 push eax
569 call _KeTestAlertThread@4
570
571 DontTest:
572 /* Return to previous context */
573 pop ebp
574 mov esp, ebp
575 jmp _KiServiceExit2
576
577 Error:
578 pop ebp
579 mov esp, ebp
580 jmp _KiServiceExit
581 .endfunc
582
583 /* EXCEPTION DISPATCHERS *****************************************************/
584
585 .func CommonDispatchException
586 _CommonDispatchException:
587
588 /* Make space for an exception record */
589 sub esp, EXCEPTION_RECORD_LENGTH
590
591 /* Set it up */
592 mov [esp+EXCEPTION_RECORD_EXCEPTION_CODE], eax
593 xor eax, eax
594 mov [esp+EXCEPTION_RECORD_EXCEPTION_FLAGS], eax
595 mov [esp+EXCEPTION_RECORD_EXCEPTION_RECORD], eax
596 mov [esp+EXCEPTION_RECORD_EXCEPTION_ADDRESS], ebx
597 mov [esp+EXCEPTION_RECORD_NUMBER_PARAMETERS], ecx
598
599 /* Check parameter count */
600 cmp ecx, 0
601 jz NoParams
602
603 /* Get information */
604 lea ebx, [esp+SIZEOF_EXCEPTION_RECORD]
605 mov [ebx], edx
606 mov [ebx+4], esi
607 mov [ebx+8], edi
608
609 NoParams:
610
611 /* Set the record in ECX and check if this was V86 */
612 mov ecx, esp
613 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
614 jz SetPreviousMode
615
616 /* Set V86 mode */
617 mov eax, 0xFFFF
618 jmp MaskMode
619
620 SetPreviousMode:
621
622 /* Get the caller's CS */
623 mov eax, [ebp+KTRAP_FRAME_CS]
624
625 MaskMode:
626 /* Check if it was user-mode or kernel-mode */
627 and eax, MODE_MASK
628
629 /* Dispatch the exception */
630 push 1
631 push eax
632 push ebp
633 push 0
634 push ecx
635 call _KiDispatchException@20
636
637 /* End the trap */
638 mov esp, ebp
639 jmp _Kei386EoiHelper@0
640 .endfunc
641
642 .func DispatchNoParam
643 _DispatchNoParam:
644 /* Call the common dispatcher */
645 xor ecx, ecx
646 call _CommonDispatchException
647 .endfunc
648
649 .func DispatchOneParam
650 _DispatchOneParam:
651 /* Call the common dispatcher */
652 xor edx, edx
653 mov ecx, 1
654 call _CommonDispatchException
655 .endfunc
656
657 .func DispatchTwoParam
658 _DispatchTwoParam:
659 /* Call the common dispatcher */
660 xor edx, edx
661 mov ecx, 2
662 call _CommonDispatchException
663 .endfunc
664
665 /* HARDWARE TRAP HANDLERS ****************************************************/
666
667 .func KiFixupFrame
668 _KiFixupFrame:
669
670 /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
671 UNHANDLED_PATH
672 .endfunc
673
674 .func KiTrap0
675 Dr_kit0: DR_TRAP_FIXUP
676 V86_kit0: V86_TRAP_FIXUP
677 _KiTrap0:
678 /* Push error code */
679 push 0
680
681 /* Enter trap */
682 TRAP_PROLOG kit0
683
684 /* Check for V86 */
685 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
686 jnz V86Int0
687
688 /* Check if the frame was from kernelmode */
689 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
690 jz SendException
691
692 /* Check the old mode */
693 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
694 jne VdmCheck
695
696 SendException:
697 /* Re-enable interrupts for user-mode and send the exception */
698 sti
699 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
700 mov ebx, [ebp+KTRAP_FRAME_EIP]
701 jmp _DispatchNoParam
702
703 VdmCheck:
704 /* Check if this is a VDM process */
705 mov ebx, PCR[KPCR_CURRENT_THREAD]
706 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
707 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
708 jz SendException
709
710 /* We don't support this yet! */
711 V86Int0:
712 /* FIXME: TODO */
713 UNHANDLED_PATH
714 .endfunc
715
716 .func KiTrap1
717 Dr_kit1: DR_TRAP_FIXUP
718 V86_kit1: V86_TRAP_FIXUP
719 _KiTrap1:
720 /* Push error code */
721 push 0
722
723 /* Enter trap */
724 TRAP_PROLOG kit1
725
726 /* Check for V86 */
727 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
728 jnz V86Int1
729
730 /* Check if the frame was from kernelmode */
731 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
732 jz PrepInt1
733
734 /* Check the old mode */
735 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
736 jne V86Int1
737
738 EnableInterrupts:
739 /* Enable interrupts for user-mode */
740 sti
741
742 PrepInt1:
743 /* Prepare the exception */
744 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
745 mov ebx, [ebp+KTRAP_FRAME_EIP]
746 mov eax, STATUS_SINGLE_STEP
747 jmp _DispatchNoParam
748
749 V86Int1:
750 /* Check if this is a VDM process */
751 mov ebx, PCR[KPCR_CURRENT_THREAD]
752 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
753 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
754 jz EnableInterrupts
755
756 /* We don't support VDM! */
757 UNHANDLED_PATH
758 .endfunc
759
760 .globl _KiTrap2
761 .func KiTrap2
762 _KiTrap2:
763
764 /* FIXME: This is an NMI, nothing like a normal exception */
765 mov eax, 2
766 jmp _KiSystemFatalException
767 .endfunc
768
769 .func KiTrap3
770 Dr_kit3: DR_TRAP_FIXUP
771 V86_kit3: V86_TRAP_FIXUP
772 _KiTrap3:
773 /* Push error code */
774 push 0
775
776 /* Enter trap */
777 TRAP_PROLOG kit3
778
779 /* Set status code */
780 mov eax, 0 //STATUS_SUCCESS
781
782 /* Check for V86 */
783 PrepareInt3:
784 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
785 jnz V86Int3
786
787 /* Check if the frame was from kernelmode */
788 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
789 jz PrepInt3
790
791 /* Check the old mode */
792 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
793 jne V86Int3
794
795 EnableInterrupts3:
796 /* Enable interrupts for user-mode */
797 sti
798
799 PrepInt3:
800
801 /* Prepare the exception */
802 mov esi, ecx
803 mov edi, edx
804 mov edx, eax
805
806 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
807 mov ebx, [ebp+KTRAP_FRAME_EIP]
808 dec ebx
809 mov ecx, 3
810 mov eax, STATUS_BREAKPOINT
811 call _CommonDispatchException
812
813 V86Int3:
814 /* Check if this is a VDM process */
815 mov ebx, PCR[KPCR_CURRENT_THREAD]
816 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
817 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
818 jz EnableInterrupts3
819
820 /* We don't support VDM! */
821 UNHANDLED_PATH
822 .endfunc
823
824 .func KiTrap4
825 Dr_kit4: DR_TRAP_FIXUP
826 V86_kit4: V86_TRAP_FIXUP
827 _KiTrap4:
828 /* Push error code */
829 push 0
830
831 /* Enter trap */
832 TRAP_PROLOG kit4
833
834 /* Check for V86 */
835 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
836 jnz V86Int4
837
838 /* Check if the frame was from kernelmode */
839 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
840 jz SendException4
841
842 /* Check the old mode */
843 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
844 jne VdmCheck4
845
846 SendException4:
847 /* Re-enable interrupts for user-mode and send the exception */
848 sti
849 mov eax, STATUS_INTEGER_OVERFLOW
850 mov ebx, [ebp+KTRAP_FRAME_EIP]
851 dec ebx
852 jmp _DispatchNoParam
853
854 VdmCheck4:
855 /* Check if this is a VDM process */
856 mov ebx, PCR[KPCR_CURRENT_THREAD]
857 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
858 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
859 jz SendException4
860
861 /* We don't support this yet! */
862 V86Int4:
863 UNHANDLED_PATH
864 .endfunc
865
866 .func KiTrap5
867 Dr_kit5: DR_TRAP_FIXUP
868 V86_kit5: V86_TRAP_FIXUP
869 _KiTrap5:
870 /* Push error code */
871 push 0
872
873 /* Enter trap */
874 TRAP_PROLOG kit5
875
876 /* Check for V86 */
877 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
878 jnz V86Int5
879
880 /* Check if the frame was from kernelmode */
881 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
882 jnz CheckMode
883
884 /* It did, and this should never happen */
885 mov eax, 5
886 jmp _KiSystemFatalException
887
888 /* Check the old mode */
889 CheckMode:
890 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
891 jne VdmCheck5
892
893 /* Re-enable interrupts for user-mode and send the exception */
894 SendException5:
895 sti
896 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
897 mov ebx, [ebp+KTRAP_FRAME_EIP]
898 jmp _DispatchNoParam
899
900 VdmCheck5:
901 /* Check if this is a VDM process */
902 mov ebx, PCR[KPCR_CURRENT_THREAD]
903 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
904 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
905 jz SendException5
906
907 /* We don't support this yet! */
908 V86Int5:
909 UNHANDLED_PATH
910 .endfunc
911
912 .func KiTrap6
913 Dr_kit6: DR_TRAP_FIXUP
914 V86_kit6: V86_TRAP_FIXUP
915 _KiTrap6:
916
917 /* It this a V86 GPF? */
918 test dword ptr [esp+8], EFLAGS_V86_MASK
919 jz NotV86UD
920
921 /* Enter V86 Trap */
922 V86_TRAP_PROLOG kit6
923
924 /* Not yet supported (Invalid OPCODE from V86) */
925 UNHANDLED_PATH
926
927 NotV86UD:
928 /* Push error code */
929 push 0
930
931 /* Enter trap */
932 TRAP_PROLOG kit6
933
934 /* Check if this happened in kernel mode */
935 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
936 jz KmodeOpcode
937
938 /* Check for VDM */
939 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
940 jz UmodeOpcode
941
942 /* Check if the process is vDM */
943 mov ebx, PCR[KPCR_CURRENT_THREAD]
944 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
945 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
946 jnz IsVdmOpcode
947
948 UmodeOpcode:
949 /* Get EIP and enable interrupts at this point */
950 mov esi, [ebp+KTRAP_FRAME_EIP]
951 sti
952
953 /* Set intruction prefix length */
954 mov ecx, 4
955
956 /* Setup a SEH frame */
957 push ebp
958 push OpcodeSEH
959 push PCR[KPCR_EXCEPTION_LIST]
960 mov PCR[KPCR_EXCEPTION_LIST], esp
961
962 OpcodeLoop:
963 /* Get the instruction and check if it's LOCK */
964 mov al, [esi]
965 cmp al, 0xF0
966 jz LockCrash
967
968 /* Keep moving */
969 add esi, 1
970 loop OpcodeLoop
971
972 /* Undo SEH frame */
973 pop PCR[KPCR_EXCEPTION_LIST]
974 add esp, 8
975
976 KmodeOpcode:
977
978 /* Re-enable interrupts */
979 sti
980
981 /* Setup illegal instruction exception and dispatch it */
982 mov ebx, [ebp+KTRAP_FRAME_EIP]
983 mov eax, STATUS_ILLEGAL_INSTRUCTION
984 jmp _DispatchNoParam
985
986 LockCrash:
987
988 /* Undo SEH Frame */
989 pop PCR[KPCR_EXCEPTION_LIST]
990 add esp, 8
991
992 /* Setup invalid lock exception and dispatch it */
993 mov ebx, [ebp+KTRAP_FRAME_EIP]
994 mov eax, STATUS_INVALID_LOCK_SEQUENCE
995 jmp _DispatchNoParam
996
997 IsVdmOpcode:
998
999 /* Unhandled yet */
1000 UNHANDLED_PATH
1001
1002 /* Return to caller */
1003 jmp _Kei386EoiHelper@0
1004
1005 OpcodeSEH:
1006
1007 /* Get SEH frame */
1008 mov esp, [esp+8]
1009 pop PCR[KPCR_EXCEPTION_LIST]
1010 add esp, 4
1011 pop ebp
1012
1013 /* Check if this was user mode */
1014 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1015 jnz KmodeOpcode
1016
1017 /* Do a bugcheck */
1018 push ebp
1019 push 0
1020 push 0
1021 push 0
1022 push 0
1023 push KMODE_EXCEPTION_NOT_HANDLED
1024 call _KeBugCheckWithTf@24
1025 .endfunc
1026
1027 .func KiTrap7
1028 Dr_kit7: DR_TRAP_FIXUP
1029 V86_kit7: V86_TRAP_FIXUP
1030 _KiTrap7:
1031 /* Push error code */
1032 push 0
1033
1034 /* Enter trap */
1035 TRAP_PROLOG kit7
1036
1037 /* Get the current thread and stack */
1038 StartTrapHandle:
1039 mov eax, PCR[KPCR_CURRENT_THREAD]
1040 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1041 sub ecx, NPX_FRAME_LENGTH
1042
1043 /* Check if emulation is enabled */
1044 test dword ptr [ecx+FN_CR0_NPX_STATE], CR0_EM
1045 jnz EmulationEnabled
1046
1047 CheckState:
1048 /* Check if the NPX state is loaded */
1049 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1050 mov ebx, cr0
1051 jz IsLoaded
1052
1053 /* Remove flags */
1054 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
1055 mov cr0, ebx
1056
1057 /* Check the NPX thread */
1058 mov edx, PCR[KPCR_NPX_THREAD]
1059 or edx, edx
1060 jz NoNpxThread
1061
1062 /* Get the NPX Stack */
1063 mov esi, [edx+KTHREAD_INITIAL_STACK]
1064 sub esi, NPX_FRAME_LENGTH
1065
1066 /* Check if we have FXSR and check which operand to use */
1067 test byte ptr _KeI386FxsrPresent, 1
1068 jz FnSave
1069 fxsave [esi]
1070 jmp AfterSave
1071
1072 FnSave:
1073 fnsave [esi]
1074
1075 AfterSave:
1076 /* Set the thread's state to dirty */
1077 mov byte ptr [edx+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1078
1079 NoNpxThread:
1080 /* Check if we have FXSR and choose which operand to use */
1081 test byte ptr _KeI386FxsrPresent, 1
1082 jz FrRestore
1083 fxrstor [ecx]
1084 jmp AfterRestore
1085
1086 FrRestore:
1087 frstor [esi]
1088
1089 AfterRestore:
1090 /* Set state loaded */
1091 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_LOADED
1092 mov PCR[KPCR_NPX_THREAD], eax
1093
1094 /* Enable interrupts to happen now */
1095 sti
1096 nop
1097
1098 /* Check if CR0 needs to be reloaded due to a context switch */
1099 cmp dword ptr [ecx+FN_CR0_NPX_STATE], 0
1100 jz _Kei386EoiHelper@0
1101
1102 /* We have to reload CR0... disable interrupts */
1103 cli
1104
1105 /* Get CR0 and update it */
1106 mov ebx, cr0
1107 or ebx, [ecx+FN_CR0_NPX_STATE]
1108 mov cr0, ebx
1109
1110 /* Restore interrupts and check if TS is back on */
1111 sti
1112 test bl, CR0_TS
1113 jz _Kei386EoiHelper@0
1114
1115 /* Clear TS, and loop handling again */
1116 clts
1117 cli
1118 jmp StartTrapHandle
1119
1120 KernelNpx:
1121
1122 /* Set delayed error */
1123 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
1124
1125 /* Check if this happened during restore */
1126 cmp dword ptr [ebp+KTRAP_FRAME_EIP], offset FrRestore
1127 jnz UserNpx
1128
1129 /* Skip instruction and dispatch the exception */
1130 add dword ptr [ebp+KTRAP_FRAME_EIP], 3
1131 jmp _Kei386EoiHelper@0
1132
1133 IsLoaded:
1134 /* Check if TS is set */
1135 test bl, CR0_TS
1136 jnz TsSetOnLoadedState
1137
1138 HandleNpxFault:
1139 /* Check if the trap came from V86 mode */
1140 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1141 jnz V86Npx
1142
1143 /* Check if it came from kernel mode */
1144 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1145 jz KernelNpx
1146
1147 /* Check if it came from a VDM */
1148 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1149 jne V86Npx
1150
1151 UserNpx:
1152 /* Get the current thread */
1153 mov eax, PCR[KPCR_CURRENT_THREAD]
1154
1155 /* Check NPX state */
1156 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1157
1158 /* Get the NPX save area */
1159 mov ecx, [eax+KTHREAD_INITIAL_STACK]
1160 lea ecx, [ecx-NPX_FRAME_LENGTH]
1161 jz NoSaveRestore
1162
1163 HandleUserNpx:
1164
1165 /* Set new CR0 */
1166 mov ebx, cr0
1167 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
1168 mov cr0, ebx
1169
1170 /* Check if we have FX support */
1171 test byte ptr _KeI386FxsrPresent, 1
1172 jz FnSave2
1173
1174 /* Save the state */
1175 fxsave [ecx]
1176 jmp MakeCr0Dirty
1177 FnSave2:
1178 fnsave [ecx]
1179 wait
1180
1181 MakeCr0Dirty:
1182 /* Make CR0 state not loaded */
1183 or ebx, NPX_STATE_NOT_LOADED
1184 or ebx, [ecx+FN_CR0_NPX_STATE]
1185 mov cr0, ebx
1186
1187 /* Update NPX state */
1188 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
1189 mov dword ptr PCR[KPCR_NPX_THREAD], 0
1190
1191 NoSaveRestore:
1192 /* Clear the TS bit and re-enable interrupts */
1193 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
1194 sti
1195
1196 /* Check if we have FX support */
1197 test byte ptr _KeI386FxsrPresent, 1
1198 jz FnError
1199
1200 /* Get error offset, control and status words */
1201 mov ebx, [ecx+FX_ERROR_OFFSET]
1202 movzx eax, word ptr [ecx+FX_CONTROL_WORD]
1203 movzx edx, word ptr [ecx+FX_STATUS_WORD]
1204
1205 /* Get the faulting opcode */
1206 mov esi, [ecx+FX_DATA_OFFSET]
1207 jmp CheckError
1208
1209 FnError:
1210 /* Get error offset, control and status words */
1211 mov ebx, [ecx+FP_ERROR_OFFSET]
1212 movzx eax, word ptr [ecx+FP_CONTROL_WORD]
1213 movzx edx, word ptr [ecx+FP_STATUS_WORD]
1214
1215 /* Get the faulting opcode */
1216 mov esi, [ecx+FP_DATA_OFFSET]
1217
1218 CheckError:
1219 /* Mask exceptions */
1220 and eax, 0x3F
1221 not eax
1222 and eax, edx
1223
1224 /* Check if what's left is invalid */
1225 test al, 1
1226 jz ValidNpxOpcode
1227
1228 /* Check if it was a stack fault */
1229 test al, 64
1230 jnz InvalidStack
1231
1232 /* Raise exception */
1233 mov eax, STATUS_FLOAT_INVALID_OPERATION
1234 jmp _DispatchOneParam
1235
1236 InvalidStack:
1237
1238 /* Raise exception */
1239 mov eax, STATUS_FLOAT_STACK_CHECK
1240 jmp _DispatchTwoParam
1241
1242 ValidNpxOpcode:
1243
1244 /* Check for divide by 0 */
1245 test al, 4
1246 jz 1f
1247
1248 /* Raise exception */
1249 mov eax, STATUS_FLOAT_DIVIDE_BY_ZERO
1250 jmp _DispatchOneParam
1251
1252 1:
1253 /* Check for denormal */
1254 test al, 2
1255 jz 1f
1256
1257 /* Raise exception */
1258 mov eax, STATUS_FLOAT_INVALID_OPERATION
1259 jmp _DispatchOneParam
1260
1261 1:
1262 /* Check for overflow */
1263 test al, 8
1264 jz 1f
1265
1266 /* Raise exception */
1267 mov eax, STATUS_FLOAT_OVERFLOW
1268 jmp _DispatchOneParam
1269
1270 1:
1271 /* Check for underflow */
1272 test al, 16
1273 jz 1f
1274
1275 /* Raise exception */
1276 mov eax, STATUS_FLOAT_UNDERFLOW
1277 jmp _DispatchOneParam
1278
1279 1:
1280 /* Check for precision fault */
1281 test al, 32
1282 jz UnexpectedNpx
1283
1284 /* Raise exception */
1285 mov eax, STATUS_FLOAT_INEXACT_RESULT
1286 jmp _DispatchOneParam
1287
1288 UnexpectedNpx:
1289
1290 /* Strange result, bugcheck the OS */
1291 sti
1292 push ebp
1293 push 0
1294 push 0
1295 push eax
1296 push 1
1297 push TRAP_CAUSE_UNKNOWN
1298 call _KeBugCheckWithTf@24
1299
1300 V86Npx:
1301 /* Check if this is a VDM */
1302 mov eax, PCR[KPCR_CURRENT_THREAD]
1303 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
1304 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1305 jz HandleUserNpx
1306
1307 /* V86 NPX not handled */
1308 UNHANDLED_PATH
1309
1310 EmulationEnabled:
1311 /* Did this come from kernel-mode? */
1312 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R0_CODE
1313 jz CheckState
1314
1315 /* It came from user-mode, so this would only be valid inside a VDM */
1316 /* Since we don't actually have VDMs in ROS, bugcheck. */
1317 jmp UnexpectedNpx
1318
1319 TsSetOnLoadedState:
1320 /* TS shouldn't be set, unless this we don't have a Math Processor */
1321 test bl, CR0_MP
1322 jnz BogusTrap
1323
1324 /* Strange that we got a trap at all, but ignore and continue */
1325 clts
1326 jmp _Kei386EoiHelper@0
1327
1328 BogusTrap:
1329 /* Cause a bugcheck */
1330 push 0
1331 push 0
1332 push ebx
1333 push 2
1334 push TRAP_CAUSE_UNKNOWN
1335 call _KeBugCheckEx@20
1336 .endfunc
1337
1338 .globl _KiTrap8
1339 .func KiTrap8
1340 _KiTrap8:
1341
1342 /* Can't really do too much */
1343 mov eax, 8
1344 jmp _KiSystemFatalException
1345 .endfunc
1346
1347 .func KiTrap9
1348 Dr_kit9: DR_TRAP_FIXUP
1349 V86_kit9: V86_TRAP_FIXUP
1350 _KiTrap9:
1351 /* Push error code */
1352 push 0
1353
1354 /* Enter trap */
1355 TRAP_PROLOG kit9
1356
1357 /* Enable interrupts and bugcheck */
1358 sti
1359 mov eax, 9
1360 jmp _KiSystemFatalException
1361 .endfunc
1362
1363 .func KiTrap10
1364 Dr_kit10: DR_TRAP_FIXUP
1365 V86_kit10: V86_TRAP_FIXUP
1366 _KiTrap10:
1367 /* Enter trap */
1368 TRAP_PROLOG kit10
1369
1370 /* Check for V86 */
1371 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1372 jnz V86IntA
1373
1374 /* Check if the frame was from kernelmode */
1375 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1376 jz Fatal
1377
1378 V86IntA:
1379 /* Check if OF was set during iretd */
1380 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1381 sti
1382 jz Fatal
1383
1384 /* It was, just mask it out */
1385 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1386 jmp _Kei386EoiHelper@0
1387
1388 Fatal:
1389 /* TSS failure for some other reason: crash */
1390 mov eax, 10
1391 jmp _KiSystemFatalException
1392 .endfunc
1393
1394 .func KiTrap11
1395 Dr_kit11: DR_TRAP_FIXUP
1396 V86_kit11: V86_TRAP_FIXUP
1397 _KiTrap11:
1398 /* Enter trap */
1399 TRAP_PROLOG kit11
1400
1401 /* FIXME: ROS Doesn't handle segment faults yet */
1402 mov eax, 11
1403 jmp _KiSystemFatalException
1404 .endfunc
1405
1406 .func KiTrap12
1407 Dr_kit12: DR_TRAP_FIXUP
1408 V86_kit12: V86_TRAP_FIXUP
1409 _KiTrap12:
1410 /* Enter trap */
1411 TRAP_PROLOG kit12
1412
1413 /* FIXME: ROS Doesn't handle stack faults yet */
1414 mov eax, 12
1415 jmp _KiSystemFatalException
1416 .endfunc
1417
1418 .func KiTrapExceptHandler
1419 _KiTrapExceptHandler:
1420
1421 /* Setup SEH handler frame */
1422 mov esp, [esp+8]
1423 pop PCR[KPCR_EXCEPTION_LIST]
1424 add esp, 4
1425 pop ebp
1426
1427 /* Check if the fault came from user mode */
1428 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1429 jnz SetException
1430
1431 /* Kernel fault, bugcheck */
1432 push ebp
1433 push 0
1434 push 0
1435 push 0
1436 push 0
1437 push KMODE_EXCEPTION_NOT_HANDLED
1438 call _KeBugCheckWithTf@24
1439 .endfunc
1440
1441 .func KiTrap13
1442 Dr_kitd: DR_TRAP_FIXUP
1443 V86_kitd: V86_TRAP_FIXUP
1444 _KiTrap13:
1445
1446 /* It this a V86 GPF? */
1447 test dword ptr [esp+12], EFLAGS_V86_MASK
1448 jz NotV86
1449
1450 /* Enter V86 Trap */
1451 V86_TRAP_PROLOG kitd
1452
1453 /* Make sure that this is a V86 process */
1454 mov ecx, PCR[KPCR_CURRENT_THREAD]
1455 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1456 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1457 jnz RaiseIrql
1458
1459 /* Otherwise, something is very wrong, raise an exception */
1460 sti
1461 mov ebx, [ebp+KTRAP_FRAME_EIP]
1462 mov esi, -1
1463 mov eax, STATUS_ACCESS_VIOLATION
1464 jmp _DispatchTwoParam
1465
1466 RaiseIrql:
1467
1468 /* Go to APC level */
1469 mov ecx, APC_LEVEL
1470 call @KfRaiseIrql@4
1471
1472 /* Save old IRQL and enable interrupts */
1473 push eax
1474 sti
1475
1476 /* Handle the opcode */
1477 call _Ki386HandleOpcodeV86@0
1478
1479 /* Check if this was VDM */
1480 test al, 0xFF
1481 jnz NoReflect
1482
1483 /* FIXME: TODO */
1484 UNHANDLED_PATH
1485
1486 NoReflect:
1487
1488 /* Lower IRQL and disable interrupts */
1489 pop ecx
1490 call @KfLowerIrql@4
1491 cli
1492
1493 /* Check if this was a V86 trap */
1494 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1495 jz NotV86Trap
1496
1497 /* Exit the V86 Trap */
1498 V86_TRAP_EPILOG
1499
1500 NotV86Trap:
1501
1502 /* Either this wasn't V86, or it was, but an APC interrupted us */
1503 jmp _Kei386EoiHelper@0
1504
1505 NotV86:
1506 /* Enter trap */
1507 TRAP_PROLOG kitd
1508
1509 /* Check if this was from kernel-mode */
1510 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1511 jnz UserModeGpf
1512
1513 /* Check if we have a VDM alert */
1514 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1515 jnz VdmAlertGpf
1516
1517 /* Check for GPF during GPF */
1518 mov eax, [ebp+KTRAP_FRAME_EIP]
1519 cmp eax, offset CheckPrivilegedInstruction
1520 jbe KmodeGpf
1521 cmp eax, offset CheckPrivilegedInstruction2
1522
1523 /* FIXME: TODO */
1524 UNHANDLED_PATH
1525
1526 /* Get the opcode and trap frame */
1527 KmodeGpf:
1528 mov eax, [ebp+KTRAP_FRAME_EIP]
1529 mov eax, [eax]
1530 mov edx, [ebp+KTRAP_FRAME_EBP]
1531
1532 /* We want to check if this was POP [DS/ES/FS/GS] */
1533 add edx, KTRAP_FRAME_DS
1534 cmp al, 0x1F
1535 jz SegPopGpf
1536 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1537 cmp al, 7
1538 jz SegPopGpf
1539 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1540 cmp ax, 0xA10F
1541 jz SegPopGpf
1542 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1543 cmp ax, 0xA90F
1544 jz SegPopGpf
1545
1546 /* It isn't, was it IRETD? */
1547 cmp al, 0xCF
1548 jne NotIretGpf
1549
1550 /* Get error code */
1551 lea edx, [ebp+KTRAP_FRAME_ESP]
1552 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1553 and ax, ~RPL_MASK
1554
1555 /* Get CS */
1556 mov cx, word ptr [edx+4]
1557 and cx, ~RPL_MASK
1558 cmp cx, ax
1559 jnz NotCsGpf
1560
1561 /* This should be a Ki386CallBios return */
1562 mov eax, offset _Ki386BiosCallReturnAddress
1563 cmp eax, [edx]
1564 jne NotBiosGpf
1565 mov eax, [edx+4]
1566 cmp ax, KGDT_R0_CODE + RPL_MASK
1567 jne NotBiosGpf
1568
1569 /* Jump to return address */
1570 jmp _Ki386BiosCallReturnAddress
1571
1572 NotBiosGpf:
1573 /* Check if the thread was in kernel mode */
1574 mov ebx, PCR[KPCR_CURRENT_THREAD]
1575 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1576 jz UserModeGpf
1577
1578 /* Set RPL_MASK for check below */
1579 or word ptr [edx+4], RPL_MASK
1580
1581 NotCsGpf:
1582 /* Check if the IRET goes to user-mode */
1583 test dword ptr [edx+4], RPL_MASK
1584 jz UserModeGpf
1585
1586 /* Setup trap frame to copy */
1587 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1588 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1589
1590 TrapCopy:
1591
1592 /* Copy each field */
1593 mov eax, [edx]
1594 mov [edx+12], eax
1595 sub edx, 4
1596 loop TrapCopy
1597
1598 /* Enable interrupts and adjust stack */
1599 sti
1600 add esp, 12
1601 add ebp, 12
1602
1603 /* Setup exception record */
1604 mov ebx, [ebp+KTRAP_FRAME_EIP]
1605 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1606 and esi, 0xFFFF
1607 mov eax, STATUS_ACCESS_VIOLATION
1608 jmp _DispatchTwoParam
1609
1610 MsrCheck:
1611
1612 /* FIXME: Handle RDMSR/WRMSR */
1613 UNHANDLED_PATH
1614
1615 NotIretGpf:
1616
1617 /* Check if this was an MSR opcode */
1618 cmp al, 0xF
1619 jz MsrCheck
1620
1621 /* Check if DS is Ring 3 */
1622 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1623 jz CheckEs
1624
1625 /* Otherwise, fix it up */
1626 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1627 jmp ExitGpfTrap
1628
1629 CheckEs:
1630
1631 /* Check if ES is Ring 3 */
1632 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1633 jz UserModeGpf
1634
1635 /* Otherwise, fix it up */
1636 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1637 jmp ExitGpfTrap
1638
1639 SegPopGpf:
1640
1641 /* Sanity check */
1642 lea eax, [ebp+KTRAP_FRAME_ESP]
1643 cmp edx, eax
1644 jz HandleSegPop
1645 int 3
1646
1647 /* Handle segment POP fault by setting it to 0 */
1648 HandleSegPop:
1649 xor eax, eax
1650 mov dword ptr [edx], eax
1651
1652 ExitGpfTrap:
1653
1654 /* Do a trap exit */
1655 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1656
1657 UserModeGpf:
1658
1659 /* If the previous mode was kernel, raise a fatal exception */
1660 mov eax, 13
1661 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1662 jz _KiSystemFatalException
1663
1664 /* Get the process and check which CS this came from */
1665 mov ebx, PCR[KPCR_CURRENT_THREAD]
1666 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1667 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1668 jz CheckVdmGpf
1669
1670 /* Check if this is a VDM */
1671 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1672 jnz DispatchV86Gpf
1673
1674 /* Enable interrupts and check if we have an error code */
1675 sti
1676 cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
1677 jnz SetException
1678 jmp CheckPrivilegedInstruction
1679
1680 HandleSegPop2:
1681 /* Update EIP (will be updated below again) */
1682 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1683
1684 HandleEsPop:
1685 /* Clear the segment, update EIP and ESP */
1686 mov dword ptr [edx], 0
1687 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1688 add dword ptr [ebp+KTRAP_FRAME_ESP], 4
1689 jmp _Kei386EoiHelper@0
1690
1691 CheckVdmGpf:
1692 /* Check if this is a VDM */
1693 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1694 jz CheckPrivilegedInstruction
1695
1696 /* Bring interrupts back */
1697 sti
1698
1699 /* Check what kind of instruction this is */
1700 mov eax, [ebp+KTRAP_FRAME_EIP]
1701 mov eax, [eax]
1702
1703 /* FIXME: Check for BOP4 */
1704
1705 /* Check if this is POP ES */
1706 mov edx, ebp
1707 add edx, KTRAP_FRAME_ES
1708 cmp al, 0x07
1709 jz HandleEsPop
1710
1711 /* Check if this is POP FS */
1712 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1713 cmp ax, 0xA10F
1714 jz HandleSegPop2
1715
1716 /* Check if this is POP GS */
1717 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1718 cmp ax, 0xA90F
1719 jz HandleSegPop2
1720
1721 CheckPrivilegedInstruction:
1722 /* Bring interrupts back */
1723 sti
1724
1725 /* Setup a SEH handler */
1726 push ebp
1727 push offset _KiTrapExceptHandler
1728 push PCR[KPCR_EXCEPTION_LIST]
1729 mov PCR[KPCR_EXCEPTION_LIST], esp
1730
1731 /* Get EIP */
1732 mov esi, [ebp+KTRAP_FRAME_EIP]
1733
1734 /* Setup loop count */
1735 mov ecx, 15
1736
1737 InstLoop:
1738 /* Save loop count */
1739 push ecx
1740
1741 /* Get the instruction */
1742 lods byte ptr [esi]
1743
1744 /* Now lookup in the prefix table */
1745 mov ecx, 11
1746 mov edi, offset _KiTrapPrefixTable
1747 repnz scasb
1748
1749 /* Restore loop count */
1750 pop ecx
1751
1752 /* If it's not a prefix byte, check other instructions */
1753 jnz NotPrefixByte
1754
1755 /* FIXME */
1756 UNHANDLED_PATH
1757
1758 NotPrefixByte:
1759 /* FIXME: Check if it's a HLT */
1760
1761 /* Check if the instruction has two bytes */
1762 cmp al, 0xF
1763 jne CheckRing3Io
1764
1765 /* FIXME */
1766 UNHANDLED_PATH
1767
1768 CheckRing3Io:
1769 /* Get EFLAGS and IOPL */
1770 mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
1771 and ebx, 0x3000
1772 shr ebx, 12
1773
1774 /* Check the CS's RPL mask */
1775 mov ecx, [ebp+KTRAP_FRAME_CS]
1776 and ecx, RPL_MASK
1777 cmp ebx, ecx
1778 jge NotIoViolation
1779
1780 CheckPrivilegedInstruction2:
1781 /* Check if this is a CLI or STI */
1782 cmp al, 0xFA
1783 je IsPrivInstruction
1784 cmp al, 0xFB
1785 je IsPrivInstruction
1786
1787 /* Setup I/O table lookup */
1788 mov ecx, 13
1789 mov edi, offset _KiTrapIoTable
1790
1791 /* Loopup in the table */
1792 repnz scasb
1793 jnz NotIoViolation
1794
1795 /* FIXME: Check IOPM!!! */
1796
1797 IsPrivInstruction:
1798 /* Cleanup the SEH frame */
1799 pop PCR[KPCR_EXCEPTION_LIST]
1800 add esp, 8
1801
1802 /* Setup the exception */
1803 mov ebx, [ebp+KTRAP_FRAME_EIP]
1804 mov eax, STATUS_PRIVILEGED_INSTRUCTION
1805 jmp _DispatchNoParam
1806
1807 NotIoViolation:
1808 /* Cleanup the SEH frame */
1809 pop PCR[KPCR_EXCEPTION_LIST]
1810 add esp, 8
1811
1812 SetException:
1813 /* Setup the exception */
1814 mov ebx, [ebp+KTRAP_FRAME_EIP]
1815 mov esi, -1
1816 mov eax, STATUS_ACCESS_VIOLATION
1817 jmp _DispatchTwoParam
1818
1819 DispatchV86Gpf:
1820 /* FIXME */
1821 UNHANDLED_PATH
1822 .endfunc
1823
1824 .func KiTrap14
1825 Dr_kit14: DR_TRAP_FIXUP
1826 V86_kit14: V86_TRAP_FIXUP
1827 _KiTrap14:
1828
1829 /* Enter trap */
1830 TRAP_PROLOG kit14
1831
1832 /* Check if we have a VDM alert */
1833 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1834 jnz VdmAlertGpf
1835
1836 /* Get the current thread */
1837 mov edi, PCR[KPCR_CURRENT_THREAD]
1838
1839 /* Get the stack address of the frame */
1840 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
1841 sub eax, [edi+KTHREAD_INITIAL_STACK]
1842 jz NoFixUp
1843
1844 /* This isn't the base frame, check if it's the second */
1845 cmp eax, -KTRAP_FRAME_EFLAGS
1846 jb NoFixUp
1847
1848 /* Check if we have a TEB */
1849 mov eax, PCR[KPCR_TEB]
1850 or eax, eax
1851 jle NoFixUp
1852
1853 /* Fixup the frame */
1854 call _KiFixupFrame
1855
1856 /* Save CR2 */
1857 NoFixUp:
1858 mov edi, cr2
1859
1860 /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
1861 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1862 je HandlePf
1863
1864 /* Enable interrupts and check if we got here with interrupts disabled */
1865 sti
1866 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1867 jz IllegalState
1868
1869 HandlePf:
1870 /* Send trap frame and check if this is kernel-mode or usermode */
1871 push ebp
1872 mov eax, [ebp+KTRAP_FRAME_CS]
1873 and eax, MODE_MASK
1874 push eax
1875
1876 /* Send faulting address and check if this is read or write */
1877 push edi
1878 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
1879 and eax, 1
1880 push eax
1881
1882 /* Call the access fault handler */
1883 call _MmAccessFault@16
1884 test eax, eax
1885 jl AccessFail
1886
1887 /* Access fault handled, return to caller */
1888 jmp _Kei386EoiHelper@0
1889
1890 AccessFail:
1891 /* First check if this is a fault in the S-LIST functions */
1892 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
1893 cmp [ebp+KTRAP_FRAME_EIP], ecx
1894 jz SlistFault
1895
1896 /* Check if this is a fault in the syscall handler */
1897 mov ecx, offset CopyParams
1898 cmp [ebp+KTRAP_FRAME_EIP], ecx
1899 jz SysCallCopyFault
1900 mov ecx, offset ReadBatch
1901 cmp [ebp+KTRAP_FRAME_EIP], ecx
1902 jnz CheckVdmPf
1903
1904 /* FIXME: TODO */
1905 UNHANDLED_PATH
1906 jmp _Kei386EoiHelper@0
1907
1908 SysCallCopyFault:
1909 /* FIXME: TODO */
1910 UNHANDLED_PATH
1911 jmp _Kei386EoiHelper@0
1912
1913 /* Check if the fault occured in a V86 mode */
1914 CheckVdmPf:
1915 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
1916 and ecx, 1
1917 shr ecx, 1
1918 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1919 jnz VdmPF
1920
1921 /* Check if the fault occured in a VDM */
1922 mov esi, PCR[KPCR_CURRENT_THREAD]
1923 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
1924 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
1925 jz CheckStatus
1926
1927 /* Check if we this was in kernel-mode */
1928 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1929 jz CheckStatus
1930 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1931 jz CheckStatus
1932
1933 VdmPF:
1934 /* FIXME: TODO */
1935 UNHANDLED_PATH
1936
1937 /* Save EIP and check what kind of status failure we got */
1938 CheckStatus:
1939 mov esi, [ebp+KTRAP_FRAME_EIP]
1940 cmp eax, STATUS_ACCESS_VIOLATION
1941 je AccessViol
1942 cmp eax, STATUS_GUARD_PAGE_VIOLATION
1943 je SpecialCode
1944 cmp eax, STATUS_STACK_OVERFLOW
1945 je SpecialCode
1946
1947 /* Setup an in-page exception to dispatch */
1948 mov edx, ecx
1949 mov ebx, esi
1950 mov esi, edi
1951 mov ecx, 3
1952 mov edi, eax
1953 mov eax, STATUS_IN_PAGE_ERROR
1954 call _CommonDispatchException
1955
1956 AccessViol:
1957 /* Use more proper status code */
1958 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
1959
1960 SpecialCode:
1961 /* Setup a normal page fault exception */
1962 mov ebx, esi
1963 mov edx, ecx
1964 mov esi, edi
1965 jmp _DispatchTwoParam
1966
1967 SlistFault:
1968 /* FIXME: TODO */
1969 UNHANDLED_PATH
1970
1971 IllegalState:
1972
1973 /* This is completely illegal, bugcheck the system */
1974 push ebp
1975 push esi
1976 push ecx
1977 push eax
1978 push edi
1979 push IRQL_NOT_LESS_OR_EQUAL
1980 call _KeBugCheckWithTf@24
1981
1982 VdmAlertGpf:
1983
1984 /* FIXME: NOT SUPPORTED */
1985 UNHANDLED_PATH
1986 .endfunc
1987
1988 .func KiTrap0F
1989 Dr_kit15: DR_TRAP_FIXUP
1990 V86_kit15: V86_TRAP_FIXUP
1991 _KiTrap0F:
1992 /* Push error code */
1993 push 0
1994
1995 /* Enter trap */
1996 TRAP_PROLOG kit15
1997 sti
1998
1999 /* Raise a fatal exception */
2000 mov eax, 15
2001 jmp _KiSystemFatalException
2002 .endfunc
2003
2004 .func KiTrap16
2005 Dr_kit16: DR_TRAP_FIXUP
2006 V86_kit16: V86_TRAP_FIXUP
2007 _KiTrap16:
2008 /* Push error code */
2009 push 0
2010
2011 /* Enter trap */
2012 TRAP_PROLOG kit16
2013
2014 /* Check if this is the NPX Thread */
2015 mov eax, PCR[KPCR_CURRENT_THREAD]
2016 cmp eax, PCR[KPCR_NPX_THREAD]
2017
2018 /* Get the initial stack and NPX frame */
2019 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2020 lea ecx, [ecx-NPX_FRAME_LENGTH]
2021
2022 /* If this is a valid fault, handle it */
2023 jz HandleNpxFault
2024
2025 /* Otherwise, re-enable interrupts and set delayed error */
2026 sti
2027 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
2028 jmp _Kei386EoiHelper@0
2029 .endfunc
2030
2031 .func KiTrap17
2032 Dr_kit17: DR_TRAP_FIXUP
2033 V86_kit17: V86_TRAP_FIXUP
2034 _KiTrap17:
2035 /* Push error code */
2036 push 0
2037
2038 /* Enter trap */
2039 TRAP_PROLOG kit17
2040
2041 /* FIXME: ROS Doesn't handle alignment faults yet */
2042 mov eax, 17
2043 jmp _KiSystemFatalException
2044 .endfunc
2045
2046 .func KiSystemFatalException
2047 _KiSystemFatalException:
2048
2049 /* Push the trap frame */
2050 push ebp
2051
2052 /* Push empty parameters */
2053 push 0
2054 push 0
2055 push 0
2056
2057 /* Push trap number and bugcheck code */
2058 push eax
2059 push UNEXPECTED_KERNEL_MODE_TRAP
2060 call _KeBugCheckWithTf@24
2061 ret
2062 .endfunc
2063
2064 .func KiCoprocessorError@0
2065 _KiCoprocessorError@0:
2066
2067 /* Get the NPX Thread's Initial stack */
2068 mov eax, PCR[KPCR_NPX_THREAD]
2069 mov eax, [eax+KTHREAD_INITIAL_STACK]
2070
2071 /* Make space for the FPU Save area */
2072 sub eax, SIZEOF_FX_SAVE_AREA
2073
2074 /* Set the CR0 State */
2075 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
2076
2077 /* Update it */
2078 mov eax, cr0
2079 or eax, 8
2080 mov cr0, eax
2081
2082 /* Return to caller */
2083 ret
2084 .endfunc
2085
2086 .func Ki16BitStackException
2087 _Ki16BitStackException:
2088
2089 /* Save stack */
2090 push ss
2091 push esp
2092
2093 /* Go to kernel mode thread stack */
2094 mov eax, PCR[KPCR_CURRENT_THREAD]
2095 add esp, [eax+KTHREAD_INITIAL_STACK]
2096
2097 /* Switch to good stack segment */
2098 UNHANDLED_PATH
2099 .endfunc
2100
2101 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
2102
2103 .globl _KiStartUnexpectedRange@0
2104 _KiStartUnexpectedRange@0:
2105
2106 GENERATE_INT_HANDLERS
2107
2108 .globl _KiEndUnexpectedRange@0
2109 _KiEndUnexpectedRange@0:
2110 jmp _KiUnexpectedInterruptTail
2111
2112 .func KiUnexpectedInterruptTail
2113 V86_kui: V86_TRAP_FIXUP
2114 Dr_kui: DR_TRAP_FIXUP
2115 _KiUnexpectedInterruptTail:
2116
2117 /* Enter interrupt trap */
2118 INT_PROLOG kui, DoNotPushFakeErrorCode
2119
2120 /* Increase interrupt count */
2121 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2122
2123 /* Put vector in EBX and make space for KIRQL */
2124 mov ebx, [esp]
2125 sub esp, 4
2126
2127 /* Begin interrupt */
2128 push esp
2129 push ebx
2130 push HIGH_LEVEL
2131 call _HalBeginSystemInterrupt@12
2132
2133 /* Check if it was spurious or not */
2134 or al, al
2135 jnz Handled
2136
2137 /* Spurious, ignore it */
2138 add esp, 8
2139 jmp _Kei386EoiHelper2ndEntry
2140
2141 Handled:
2142 /* Unexpected interrupt, print a message on debug builds */
2143 #if DBG
2144 push [esp+4]
2145 push offset _UnexpectedMsg
2146 call _DbgPrint
2147 add esp, 8
2148 #endif
2149
2150 /* Exit the interrupt */
2151 mov esi, $
2152 cli
2153 call _HalEndSystemInterrupt@8
2154 jmp _Kei386EoiHelper@0
2155 .endfunc
2156
2157 .globl _KiUnexpectedInterrupt
2158 _KiUnexpectedInterrupt:
2159
2160 /* Bugcheck with invalid interrupt code */
2161 push TRAP_CAUSE_UNKNOWN
2162 call _KeBugCheck@4
2163
2164 /* INTERRUPT HANDLERS ********************************************************/
2165
2166 .func KiDispatchInterrupt@0
2167 _KiDispatchInterrupt@0:
2168
2169 /* Get the PCR and disable interrupts */
2170 mov ebx, PCR[KPCR_SELF]
2171 cli
2172
2173 /* Check if we have to deliver DPCs, timers, or deferred threads */
2174 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
2175 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
2176 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
2177 jz CheckQuantum
2178
2179 /* Save stack pointer and exception list, then clear it */
2180 push ebp
2181 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
2182 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
2183
2184 /* Save the stack and switch to the DPC Stack */
2185 mov edx, esp
2186 //mov esp, [ebx+KPCR_PRCB_DPC_STACK]
2187 push edx
2188
2189 /* Deliver DPCs */
2190 mov ecx, [ebx+KPCR_PRCB]
2191 call @KiRetireDpcList@4
2192
2193 /* Restore stack and exception list */
2194 pop esp
2195 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
2196 pop ebp
2197
2198 CheckQuantum:
2199
2200 /* Re-enable interrupts */
2201 sti
2202
2203 /* Check if we have quantum end */
2204 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2205 jnz QuantumEnd
2206
2207 /* Check if we have a thread to swap to */
2208 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2209 je Return
2210
2211 /* Make space on the stack to save registers */
2212 sub esp, 3 * 4
2213 mov [esp+8], esi
2214 mov [esp+4], edi
2215 mov [esp+0], ebp
2216
2217 /* Get the current thread */
2218 mov edi, [ebx+KPCR_CURRENT_THREAD]
2219
2220 #ifdef CONFIG_SMP
2221 #error SMP Interrupt not handled!
2222 #endif
2223
2224 /* Get the next thread and clear it */
2225 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
2226 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2227
2228 /* Set us as the current running thread */
2229 mov [ebx+KPCR_CURRENT_THREAD], esi
2230 mov byte ptr [esi+KTHREAD_STATE], Running
2231 mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
2232
2233 /* Put thread in ECX and get the PRCB in EDX */
2234 mov ecx, edi
2235 lea edx, [ebx+KPCR_PRCB_DATA]
2236 call @KiQueueReadyThread@8
2237
2238 /* Set APC_LEVEL and do the swap */
2239 mov cl, APC_LEVEL
2240 call @KiSwapContextInternal@0
2241
2242 /* Restore registers */
2243 mov ebp, [esp+0]
2244 mov edi, [esp+4]
2245 mov esi, [esp+8]
2246 add esp, 3*4
2247
2248 Return:
2249 /* All done */
2250 ret
2251
2252 QuantumEnd:
2253 /* Disable quantum end and process it */
2254 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2255 call _KiQuantumEnd@0
2256 ret
2257 .endfunc
2258
2259 .func KiInterruptTemplate
2260 V86_kit: V86_TRAP_FIXUP
2261 Dr_kit: DR_TRAP_FIXUP
2262 _KiInterruptTemplate:
2263
2264 /* Enter interrupt trap */
2265 INT_PROLOG kit, DoPushFakeErrorCode
2266 .endfunc
2267
2268 _KiInterruptTemplate2ndDispatch:
2269 /* Dummy code, will be replaced by the address of the KINTERRUPT */
2270 mov edi, 0
2271
2272 _KiInterruptTemplateObject:
2273 /* Dummy jump, will be replaced by the actual jump */
2274 jmp _KeSynchronizeExecution@12
2275
2276 _KiInterruptTemplateDispatch:
2277 /* Marks the end of the template so that the jump above can be edited */
2278
2279 .func KiChainedDispatch2ndLvl@0
2280 _KiChainedDispatch2ndLvl@0:
2281
2282 /* Not yet supported */
2283 UNHANDLED_PATH
2284 .endfunc
2285
2286 .func KiChainedDispatch@0
2287 _KiChainedDispatch@0:
2288
2289 /* Increase interrupt count */
2290 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2291
2292 /* Save trap frame */
2293 mov ebp, esp
2294
2295 /* Save vector and IRQL */
2296 mov eax, [edi+KINTERRUPT_VECTOR]
2297 mov ecx, [edi+KINTERRUPT_IRQL]
2298
2299 /* Save old irql */
2300 push eax
2301 sub esp, 4
2302
2303 /* Begin interrupt */
2304 push esp
2305 push eax
2306 push ecx
2307 call _HalBeginSystemInterrupt@12
2308
2309 /* Check if it was handled */
2310 or al, al
2311 jz SpuriousInt
2312
2313 /* Call the 2nd-level handler */
2314 call _KiChainedDispatch2ndLvl@0
2315
2316 /* Exit the interrupt */
2317 INT_EPILOG 0
2318 .endfunc
2319
2320 .func KiInterruptDispatch@0
2321 _KiInterruptDispatch@0:
2322
2323 /* Increase interrupt count */
2324 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2325
2326 /* Save trap frame */
2327 mov ebp, esp
2328
2329 /* Save vector and IRQL */
2330 mov eax, [edi+KINTERRUPT_VECTOR]
2331 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2332
2333 /* Save old irql */
2334 push eax
2335 sub esp, 4
2336
2337 /* Begin interrupt */
2338 push esp
2339 push eax
2340 push ecx
2341 call _HalBeginSystemInterrupt@12
2342
2343 /* Check if it was handled */
2344 or al, al
2345 jz SpuriousInt
2346
2347 /* Acquire the lock */
2348 GetIntLock:
2349 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2350 ACQUIRE_SPINLOCK(esi, IntSpin)
2351
2352 /* Make sure that this interrupt isn't storming */
2353 VERIFY_INT kid
2354
2355 /* Save the tick count */
2356 mov ebx, _KeTickCount
2357
2358 /* Call the ISR */
2359 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2360 push eax
2361 push edi
2362 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2363
2364 /* Check if the ISR timed out */
2365 add ebx, _KiISRTimeout
2366 cmp _KeTickCount, ebx
2367 jnc IsrTimeout
2368
2369 ReleaseLock:
2370 /* Release the lock */
2371 RELEASE_SPINLOCK(esi)
2372
2373 /* Exit the interrupt */
2374 INT_EPILOG 0
2375
2376 SpuriousInt:
2377 /* Exit the interrupt */
2378 add esp, 8
2379 INT_EPILOG 1
2380
2381 #ifdef CONFIG_SMP
2382 IntSpin:
2383 SPIN_ON_LOCK esi, GetIntLock
2384 #endif
2385
2386 IsrTimeout:
2387 /* Print warning message */
2388 push [edi+KINTERRUPT_SERVICE_ROUTINE]
2389 push offset _IsrTimeoutMsg
2390 call _DbgPrint
2391 add esp,8
2392
2393 /* Break into debugger, then continue */
2394 int 3
2395 jmp ReleaseLock
2396
2397 /* Cleanup verification */
2398 VERIFY_INT_END kid, 0
2399 .endfunc