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