- Add EFLAGS_IOPL to asm.h and make use of it in assembly
[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 0
84 .short 0x7FF
85 .long _KiIdt
86
87 .globl _KiUnexpectedEntrySize
88 _KiUnexpectedEntrySize:
89 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
90
91 _UnexpectedMsg:
92 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
93
94 _UnhandledMsg:
95 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx!!!\n"
96
97 _IsrTimeoutMsg:
98 .asciz "\n*** ISR at %lx took over .5 second\n"
99
100 _IsrOverflowMsg:
101 .asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
102
103 _KiTrapPrefixTable:
104 .byte 0xF2 /* REP */
105 .byte 0xF3 /* REP INS/OUTS */
106 .byte 0x67 /* ADDR */
107 .byte 0xF0 /* LOCK */
108 .byte 0x66 /* OP */
109 .byte 0x2E /* SEG */
110 .byte 0x3E /* DS */
111 .byte 0x26 /* ES */
112 .byte 0x64 /* FS */
113 .byte 0x65 /* GS */
114 .byte 0x36 /* SS */
115
116 _KiTrapIoTable:
117 .byte 0xE4 /* IN */
118 .byte 0xE5 /* IN */
119 .byte 0xEC /* IN */
120 .byte 0xED /* IN */
121 .byte 0x6C /* INS */
122 .byte 0x6D /* INS */
123 .byte 0xE6 /* OUT */
124 .byte 0xE7 /* OUT */
125 .byte 0xEE /* OUT */
126 .byte 0xEF /* OUT */
127 .byte 0x6E /* OUTS */
128 .byte 0x6F /* OUTS */
129
130 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
131 .text
132
133 _KiGetTickCount:
134 _KiCallbackReturn:
135 _KiRaiseAssertion:
136 /* FIXME: TODO */
137 UNHANDLED_PATH
138
139 .func KiSystemService
140 TRAP_FIXUPS kss_a, kss_t, DoNotFixupV86, DoNotFixupAbios
141 _KiSystemService:
142
143 /* Enter the shared system call prolog */
144 SYSCALL_PROLOG kss_a, kss_t
145
146 /* Jump to the actual handler */
147 jmp SharedCode
148 .endfunc
149
150 .func KiFastCallEntry
151 TRAP_FIXUPS FastCallDrSave, FastCallDrReturn, DoNotFixupV86, DoNotFixupAbios
152 _KiFastCallEntry:
153
154 /* Enter the fast system call prolog */
155 FASTCALL_PROLOG FastCallDrSave, FastCallDrReturn
156
157 SharedCode:
158
159 /*
160 * Find out which table offset to use. Converts 0x1124 into 0x10.
161 * The offset is related to the Table Index as such: Offset = TableIndex x 10
162 */
163 mov edi, eax
164 shr edi, SERVICE_TABLE_SHIFT
165 and edi, SERVICE_TABLE_MASK
166 mov ecx, edi
167
168 /* Now add the thread's base system table to the offset */
169 add edi, [esi+KTHREAD_SERVICE_TABLE]
170
171 /* Get the true syscall ID and check it */
172 mov ebx, eax
173 and eax, SERVICE_NUMBER_MASK
174 cmp eax, [edi+SERVICE_DESCRIPTOR_LIMIT]
175
176 /* Invalid ID, try to load Win32K Table */
177 jnb KiBBTUnexpectedRange
178
179 /* Check if this was Win32K */
180 cmp ecx, SERVICE_TABLE_TEST
181 jnz NotWin32K
182
183 /* Get the TEB */
184 mov ecx, PCR[KPCR_TEB]
185
186 /* Check if we should flush the User Batch */
187 xor ebx, ebx
188 ReadBatch:
189 or ebx, [ecx+TEB_GDI_BATCH_COUNT]
190 jz NotWin32K
191
192 /* Flush it */
193 push edx
194 push eax
195 call [_KeGdiFlushUserBatch]
196 pop eax
197 pop edx
198
199 NotWin32K:
200 /* Increase total syscall count */
201 inc dword ptr PCR[KPCR_SYSTEM_CALLS]
202
203 #ifdef DBG
204 /* Increase per-syscall count */
205 mov ecx, [edi+SERVICE_DESCRIPTOR_COUNT]
206 jecxz NoCountTable
207 inc dword ptr [ecx+eax*4]
208 #endif
209
210 /* Users's current stack frame pointer is source */
211 NoCountTable:
212 mov esi, edx
213
214 /* Allocate room for argument list from kernel stack */
215 mov ebx, [edi+SERVICE_DESCRIPTOR_NUMBER]
216 xor ecx, ecx
217 mov cl, [eax+ebx]
218
219 /* Get pointer to function */
220 mov edi, [edi+SERVICE_DESCRIPTOR_BASE]
221 mov ebx, [edi+eax*4]
222
223 /* Allocate space on our stack */
224 sub esp, ecx
225
226 /* Set the size of the arguments and the destination */
227 shr ecx, 2
228 mov edi, esp
229
230 /* Make sure we're within the User Probe Address */
231 cmp esi, _MmUserProbeAddress
232 jnb AccessViolation
233
234 CopyParams:
235 /* Copy the parameters */
236 rep movsd
237
238 /* Do the System Call */
239 call ebx
240
241 AfterSysCall:
242 #ifdef DBG
243 /* Make sure the user-mode call didn't return at elevated IRQL */
244 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
245 jz SkipCheck
246 mov esi, eax /* We need to save the syscall's return val */
247 call _KeGetCurrentIrql@0
248 or al, al
249 jnz InvalidIrql
250 mov eax, esi /* Restore it */
251
252 /* Get our temporary current thread pointer for sanity check */
253 mov ecx, PCR[KPCR_CURRENT_THREAD]
254
255 /* Make sure that we are not attached and that APCs are not disabled */
256 mov dl, [ecx+KTHREAD_APC_STATE_INDEX]
257 or dl, dl
258 jnz InvalidIndex
259 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
260 or edx, edx
261 jnz InvalidIndex
262 #endif
263
264 SkipCheck:
265
266 /* Deallocate the kernel stack frame */
267 mov esp, ebp
268
269 KeReturnFromSystemCall:
270
271 /* Get the Current Thread */
272 mov ecx, PCR[KPCR_CURRENT_THREAD]
273
274 /* Restore the old trap frame pointer */
275 mov edx, [ebp+KTRAP_FRAME_EDX]
276 mov [ecx+KTHREAD_TRAP_FRAME], edx
277 .endfunc
278
279 .func KiServiceExit
280 _KiServiceExit:
281 /* Disable interrupts */
282 cli
283
284 /* Check for, and deliver, User-Mode APCs if needed */
285 CHECK_FOR_APC_DELIVER 1
286
287 /* Exit and cleanup */
288 TRAP_EPILOG FromSystemCall, DoRestorePreviousMode, DoNotRestoreSegments, DoNotRestoreVolatiles, DoRestoreEverything
289 .endfunc
290
291 KiBBTUnexpectedRange:
292
293 /* If this isn't a Win32K call, fail */
294 cmp ecx, SERVICE_TABLE_TEST
295 jne InvalidCall
296
297 /* Set up Win32K Table */
298 push edx
299 push ebx
300 call _PsConvertToGuiThread@0
301
302 /* Check return code */
303 or eax, eax
304
305 /* Restore registers */
306 pop eax
307 pop edx
308
309 /* Reset trap frame address */
310 mov ebp, esp
311 mov [esi+KTHREAD_TRAP_FRAME], ebp
312
313 /* Try the Call again, if we suceeded */
314 jz SharedCode
315
316 /*
317 * The Shadow Table should have a special byte table which tells us
318 * whether we should return FALSE, -1 or STATUS_INVALID_SYSTEM_SERVICE.
319 */
320
321 /* Get the table limit and base */
322 lea edx, _KeServiceDescriptorTableShadow + SERVICE_TABLE_TEST
323 mov ecx, [edx+SERVICE_DESCRIPTOR_LIMIT]
324 mov edx, [edx+SERVICE_DESCRIPTOR_BASE]
325
326 /* Get the table address and add our index into the array */
327 lea edx, [edx+ecx*4]
328 and eax, SERVICE_NUMBER_MASK
329 add edx, eax
330
331 /* Find out what we should return */
332 movsx eax, byte ptr [edx]
333 or eax, eax
334
335 /* Return either 0 or -1, we've set it in EAX */
336 jle KeReturnFromSystemCall
337
338 /* Set STATUS_INVALID_SYSTEM_SERVICE */
339 mov eax, STATUS_INVALID_SYSTEM_SERVICE
340 jmp KeReturnFromSystemCall
341
342 InvalidCall:
343
344 /* Invalid System Call */
345 mov eax, STATUS_INVALID_SYSTEM_SERVICE
346 jmp KeReturnFromSystemCall
347
348 AccessViolation:
349
350 /* Check if this came from kernel-mode */
351 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
352
353 /* It's fine, go ahead with it */
354 jz CopyParams
355
356 /* Caller sent invalid parameters, fail here */
357 mov eax, STATUS_ACCESS_VIOLATION
358 jmp AfterSysCall
359
360 BadStack:
361
362 /* Restore ESP0 stack */
363 mov ecx, PCR[KPCR_TSS]
364 mov esp, ss:[ecx+KTSS_ESP0]
365
366 /* Generate V86M Stack for Trap 6 */
367 push 0
368 push 0
369 push 0
370 push 0
371
372 /* Generate interrupt stack for Trap 6 */
373 push KGDT_R3_DATA + RPL_MASK
374 push 0
375 push 0x20202
376 push KGDT_R3_CODE + RPL_MASK
377 push 0
378 jmp _KiTrap6
379
380 #ifdef DBG
381 InvalidIrql:
382 /* Save current IRQL */
383 push PCR[KPCR_IRQL]
384
385 /* Set us at passive */
386 mov dword ptr PCR[KPCR_IRQL], 0
387 cli
388
389 /* Bugcheck */
390 push 0
391 push 0
392 push eax
393 push ebx
394 push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
395 call _KeBugCheckEx@20
396
397 InvalidIndex:
398
399 /* Get the index and APC state */
400 movzx eax, byte ptr [ecx+KTHREAD_APC_STATE_INDEX]
401 mov edx, [ecx+KTHREAD_COMBINED_APC_DISABLE]
402
403 /* Bugcheck */
404 push 0
405 push edx
406 push eax
407 push ebx
408 push APC_INDEX_MISMATCH
409 call _KeBugCheckEx@20
410 ret
411 #endif
412
413 .func KiServiceExit2
414 _KiServiceExit2:
415
416 /* Disable interrupts */
417 cli
418
419 /* Check for, and deliver, User-Mode APCs if needed */
420 CHECK_FOR_APC_DELIVER 0
421
422 /* Exit and cleanup */
423 TRAP_EPILOG NotFromSystemCall, DoRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
424 .endfunc
425
426 .func Kei386EoiHelper@0
427 _Kei386EoiHelper@0:
428
429 /* Disable interrupts */
430 cli
431
432 /* Check for, and deliver, User-Mode APCs if needed */
433 CHECK_FOR_APC_DELIVER 0
434
435 /* Exit and cleanup */
436 _Kei386EoiHelper2ndEntry:
437 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
438 .endfunc
439
440 V86_Exit:
441 /* Move to EDX position */
442 add esp, KTRAP_FRAME_EDX
443
444 /* Restore volatiles */
445 pop edx
446 pop ecx
447 pop eax
448
449 /* Move to non-volatiles */
450 lea esp, [ebp+KTRAP_FRAME_EDI]
451 pop edi
452 pop esi
453 pop ebx
454 pop ebp
455
456 /* Skip error code and return */
457 add esp, 4
458 iret
459
460 AbiosExit:
461 /* FIXME: TODO */
462 UNHANDLED_PATH
463
464 .func KiDebugService
465 TRAP_FIXUPS kids_a, kids_t, DoFixupV86, DoFixupAbios
466 _KiDebugService:
467
468 /* Push error code */
469 push 0
470
471 /* Enter trap */
472 TRAP_PROLOG kids_a, kids_t
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 DispatchOneParamZero
650 _DispatchOneParamZero:
651 /* Call the common dispatcher */
652 xor edx, edx
653 mov ecx, 1
654 call _CommonDispatchException
655 .endfunc
656
657 .func DispatchTwoParamZero
658 _DispatchTwoParamZero:
659 /* Call the common dispatcher */
660 xor edx, edx
661 mov ecx, 2
662 call _CommonDispatchException
663 .endfunc
664
665 .func DispatchTwoParam
666 _DispatchTwoParam:
667 /* Call the common dispatcher */
668 mov ecx, 2
669 call _CommonDispatchException
670 .endfunc
671
672 /* HARDWARE TRAP HANDLERS ****************************************************/
673
674 .func KiFixupFrame
675 _KiFixupFrame:
676
677 /* TODO: Routine to fixup a KTRAP_FRAME when faulting from a syscall. */
678 UNHANDLED_PATH
679 .endfunc
680
681 .func KiTrap0
682 TRAP_FIXUPS kit0_a, kit0_t, DoFixupV86, DoNotFixupAbios
683 _KiTrap0:
684 /* Push error code */
685 push 0
686
687 /* Enter trap */
688 TRAP_PROLOG kit0_a, kit0_t
689
690 /* Check for V86 */
691 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
692 jnz V86Int0
693
694 /* Check if the frame was from kernelmode */
695 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
696 jz SendException
697
698 /* Check the old mode */
699 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
700 jne VdmCheck
701
702 SendException:
703 /* Re-enable interrupts for user-mode and send the exception */
704 sti
705 mov eax, STATUS_INTEGER_DIVIDE_BY_ZERO
706 mov ebx, [ebp+KTRAP_FRAME_EIP]
707 jmp _DispatchNoParam
708
709 VdmCheck:
710 /* Check if this is a VDM process */
711 mov ebx, PCR[KPCR_CURRENT_THREAD]
712 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
713 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
714 jz SendException
715
716 /* We don't support this yet! */
717 V86Int0:
718 /* FIXME: TODO */
719 UNHANDLED_PATH
720 .endfunc
721
722 .func KiTrap1
723 TRAP_FIXUPS kit1_a, kit1_t, DoFixupV86, DoNotFixupAbios
724 _KiTrap1:
725 /* Push error code */
726 push 0
727
728 /* Enter trap */
729 TRAP_PROLOG kit1_a, kit1_t
730
731 /* Check for V86 */
732 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
733 jnz V86Int1
734
735 /* Check if the frame was from kernelmode */
736 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
737 jz PrepInt1
738
739 /* Check the old mode */
740 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
741 jne V86Int1
742
743 EnableInterrupts:
744 /* Enable interrupts for user-mode */
745 sti
746
747 PrepInt1:
748 /* Prepare the exception */
749 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAGS_TF
750 mov ebx, [ebp+KTRAP_FRAME_EIP]
751 mov eax, STATUS_SINGLE_STEP
752 jmp _DispatchNoParam
753
754 V86Int1:
755 /* Check if this is a VDM process */
756 mov ebx, PCR[KPCR_CURRENT_THREAD]
757 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
758 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
759 jz EnableInterrupts
760
761 /* We don't support VDM! */
762 UNHANDLED_PATH
763 .endfunc
764
765 .globl _KiTrap2
766 .func KiTrap2
767 _KiTrap2:
768
769 /* FIXME: This is an NMI, nothing like a normal exception */
770 mov eax, 2
771 jmp _KiSystemFatalException
772 .endfunc
773
774 .func KiTrap3
775 TRAP_FIXUPS kit3_a, kit3_t, DoFixupV86, DoNotFixupAbios
776 _KiTrap3:
777 /* Push error code */
778 push 0
779
780 /* Enter trap */
781 TRAP_PROLOG kit3_a, kit3_t
782
783 /* Set status code */
784 mov eax, 0 //STATUS_SUCCESS
785
786 /* Check for V86 */
787 PrepareInt3:
788 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
789 jnz V86Int3
790
791 /* Check if the frame was from kernelmode */
792 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
793 jz PrepInt3
794
795 /* Check the old mode */
796 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
797 jne V86Int3
798
799 EnableInterrupts3:
800 /* Enable interrupts for user-mode */
801 sti
802
803 PrepInt3:
804
805 /* Prepare the exception */
806 mov esi, ecx
807 mov edi, edx
808 mov edx, eax
809
810 /* Setup EIP, NTSTATUS and parameter count, then dispatch */
811 mov ebx, [ebp+KTRAP_FRAME_EIP]
812 dec ebx
813 mov ecx, 3
814 mov eax, STATUS_BREAKPOINT
815 call _CommonDispatchException
816
817 V86Int3:
818 /* Check if this is a VDM process */
819 mov ebx, PCR[KPCR_CURRENT_THREAD]
820 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
821 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
822 jz EnableInterrupts3
823
824 /* We don't support VDM! */
825 UNHANDLED_PATH
826 .endfunc
827
828 .func KiTrap4
829 TRAP_FIXUPS kit4_a, kit4_t, DoFixupV86, DoNotFixupAbios
830 _KiTrap4:
831 /* Push error code */
832 push 0
833
834 /* Enter trap */
835 TRAP_PROLOG kit4_a, kit4_t
836
837 /* Check for V86 */
838 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
839 jnz V86Int4
840
841 /* Check if the frame was from kernelmode */
842 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
843 jz SendException4
844
845 /* Check the old mode */
846 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
847 jne VdmCheck4
848
849 SendException4:
850 /* Re-enable interrupts for user-mode and send the exception */
851 sti
852 mov eax, STATUS_INTEGER_OVERFLOW
853 mov ebx, [ebp+KTRAP_FRAME_EIP]
854 dec ebx
855 jmp _DispatchNoParam
856
857 VdmCheck4:
858 /* Check if this is a VDM process */
859 mov ebx, PCR[KPCR_CURRENT_THREAD]
860 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
861 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
862 jz SendException4
863
864 /* We don't support this yet! */
865 V86Int4:
866 UNHANDLED_PATH
867 .endfunc
868
869 .func KiTrap5
870 TRAP_FIXUPS kit5_a, kit5_t, DoFixupV86, DoNotFixupAbios
871 _KiTrap5:
872 /* Push error code */
873 push 0
874
875 /* Enter trap */
876 TRAP_PROLOG kit5_a, kit5_t
877
878 /* Check for V86 */
879 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
880 jnz V86Int5
881
882 /* Check if the frame was from kernelmode */
883 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
884 jnz CheckMode
885
886 /* It did, and this should never happen */
887 mov eax, 5
888 jmp _KiSystemFatalException
889
890 /* Check the old mode */
891 CheckMode:
892 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
893 jne VdmCheck5
894
895 /* Re-enable interrupts for user-mode and send the exception */
896 SendException5:
897 sti
898 mov eax, STATUS_ARRAY_BOUNDS_EXCEEDED
899 mov ebx, [ebp+KTRAP_FRAME_EIP]
900 jmp _DispatchNoParam
901
902 VdmCheck5:
903 /* Check if this is a VDM process */
904 mov ebx, PCR[KPCR_CURRENT_THREAD]
905 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
906 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
907 jz SendException5
908
909 /* We don't support this yet! */
910 V86Int5:
911 UNHANDLED_PATH
912 .endfunc
913
914 .func KiTrap6
915 TRAP_FIXUPS kit6_a, kit6_t, DoFixupV86, DoNotFixupAbios
916 _KiTrap6:
917
918 /* It this a V86 GPF? */
919 test dword ptr [esp+8], EFLAGS_V86_MASK
920 jz NotV86UD
921
922 /* Enter V86 Trap */
923 V86_TRAP_PROLOG kit6_a, kit6_v
924
925 /* Not yet supported (Invalid OPCODE from V86) */
926 UNHANDLED_PATH
927
928 NotV86UD:
929 /* Push error code */
930 push 0
931
932 /* Enter trap */
933 TRAP_PROLOG kit6_a, kit6_t
934
935 /* Check if this happened in kernel mode */
936 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
937 jz KmodeOpcode
938
939 /* Check for VDM */
940 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
941 jz UmodeOpcode
942
943 /* Check if the process is vDM */
944 mov ebx, PCR[KPCR_CURRENT_THREAD]
945 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
946 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
947 jnz IsVdmOpcode
948
949 UmodeOpcode:
950 /* Get EIP and enable interrupts at this point */
951 mov esi, [ebp+KTRAP_FRAME_EIP]
952 sti
953
954 /* Set intruction prefix length */
955 mov ecx, 4
956
957 /* Setup a SEH frame */
958 push ebp
959 push OpcodeSEH
960 push PCR[KPCR_EXCEPTION_LIST]
961 mov PCR[KPCR_EXCEPTION_LIST], esp
962
963 OpcodeLoop:
964 /* Get the instruction and check if it's LOCK */
965 mov al, [esi]
966 cmp al, 0xF0
967 jz LockCrash
968
969 /* Keep moving */
970 add esi, 1
971 loop OpcodeLoop
972
973 /* Undo SEH frame */
974 pop PCR[KPCR_EXCEPTION_LIST]
975 add esp, 8
976
977 KmodeOpcode:
978
979 /* Re-enable interrupts */
980 sti
981
982 /* Setup illegal instruction exception and dispatch it */
983 mov ebx, [ebp+KTRAP_FRAME_EIP]
984 mov eax, STATUS_ILLEGAL_INSTRUCTION
985 jmp _DispatchNoParam
986
987 LockCrash:
988
989 /* Undo SEH Frame */
990 pop PCR[KPCR_EXCEPTION_LIST]
991 add esp, 8
992
993 /* Setup invalid lock exception and dispatch it */
994 mov ebx, [ebp+KTRAP_FRAME_EIP]
995 mov eax, STATUS_INVALID_LOCK_SEQUENCE
996 jmp _DispatchNoParam
997
998 IsVdmOpcode:
999
1000 /* Unhandled yet */
1001 UNHANDLED_PATH
1002
1003 /* Return to caller */
1004 jmp _Kei386EoiHelper@0
1005
1006 OpcodeSEH:
1007
1008 /* Get SEH frame */
1009 mov esp, [esp+8]
1010 pop PCR[KPCR_EXCEPTION_LIST]
1011 add esp, 4
1012 pop ebp
1013
1014 /* Check if this was user mode */
1015 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1016 jnz KmodeOpcode
1017
1018 /* Do a bugcheck */
1019 push ebp
1020 push 0
1021 push 0
1022 push 0
1023 push 0
1024 push KMODE_EXCEPTION_NOT_HANDLED
1025 call _KeBugCheckWithTf@24
1026 .endfunc
1027
1028 .func KiTrap7
1029 TRAP_FIXUPS kit7_a, kit7_t, DoFixupV86, DoNotFixupAbios
1030 _KiTrap7:
1031 /* Push error code */
1032 push 0
1033
1034 /* Enter trap */
1035 TRAP_PROLOG kit7_a, kit7_t
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 byte 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 [ecx]
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 _DispatchOneParamZero
1235
1236 InvalidStack:
1237
1238 /* Raise exception */
1239 mov eax, STATUS_FLOAT_STACK_CHECK
1240 jmp _DispatchTwoParamZero
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 _DispatchOneParamZero
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 _DispatchOneParamZero
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 _DispatchOneParamZero
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 _DispatchOneParamZero
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 _DispatchOneParamZero
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 TRAP_FIXUPS kit9_a, kit9_t, DoFixupV86, DoNotFixupAbios
1349 _KiTrap9:
1350 /* Push error code */
1351 push 0
1352
1353 /* Enter trap */
1354 TRAP_PROLOG kit9_a, kit9_t
1355
1356 /* Enable interrupts and bugcheck */
1357 sti
1358 mov eax, 9
1359 jmp _KiSystemFatalException
1360 .endfunc
1361
1362 .func KiTrap10
1363 TRAP_FIXUPS kita_a, kita_t, DoFixupV86, DoNotFixupAbios
1364 _KiTrap10:
1365 /* Enter trap */
1366 TRAP_PROLOG kita_a, kita_t
1367
1368 /* Check for V86 */
1369 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1370 jnz V86IntA
1371
1372 /* Check if the frame was from kernelmode */
1373 test word ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1374 jz Fatal
1375
1376 V86IntA:
1377 /* Check if OF was set during iretd */
1378 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAG_ZERO
1379 sti
1380 jz Fatal
1381
1382 /* It was, just mask it out */
1383 and dword ptr [ebp+KTRAP_FRAME_EFLAGS], ~EFLAG_ZERO
1384 jmp _Kei386EoiHelper@0
1385
1386 Fatal:
1387 /* TSS failure for some other reason: crash */
1388 mov eax, 10
1389 jmp _KiSystemFatalException
1390 .endfunc
1391
1392 .func KiTrap11
1393 TRAP_FIXUPS kitb_a, kitb_t, DoFixupV86, DoNotFixupAbios
1394 _KiTrap11:
1395 /* Enter trap */
1396 TRAP_PROLOG kitb_a, kitb_t
1397
1398 /* FIXME: ROS Doesn't handle segment faults yet */
1399 mov eax, 11
1400 jmp _KiSystemFatalException
1401 .endfunc
1402
1403 .func KiTrap12
1404 TRAP_FIXUPS kitc_a, kitc_t, DoFixupV86, DoNotFixupAbios
1405 _KiTrap12:
1406 /* Enter trap */
1407 TRAP_PROLOG kitc_a, kitc_t
1408
1409 /* FIXME: ROS Doesn't handle stack faults yet */
1410 mov eax, 12
1411 jmp _KiSystemFatalException
1412 .endfunc
1413
1414 .func KiTrapExceptHandler
1415 _KiTrapExceptHandler:
1416
1417 /* Setup SEH handler frame */
1418 mov esp, [esp+8]
1419 pop PCR[KPCR_EXCEPTION_LIST]
1420 add esp, 4
1421 pop ebp
1422
1423 /* Check if the fault came from user mode */
1424 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1425 jnz SetException
1426
1427 /* Kernel fault, bugcheck */
1428 push ebp
1429 push 0
1430 push 0
1431 push 0
1432 push 0
1433 push KMODE_EXCEPTION_NOT_HANDLED
1434 call _KeBugCheckWithTf@24
1435 .endfunc
1436
1437 .func KiTrap13
1438 TRAP_FIXUPS kitd_a, kitd_t, DoFixupV86, DoNotFixupAbios
1439 _KiTrap13:
1440
1441 /* It this a V86 GPF? */
1442 test dword ptr [esp+12], EFLAGS_V86_MASK
1443 jz NotV86
1444
1445 /* Enter V86 Trap */
1446 V86_TRAP_PROLOG kitd_a, kitd_v
1447
1448 /* Make sure that this is a V86 process */
1449 mov ecx, PCR[KPCR_CURRENT_THREAD]
1450 mov ecx, [ecx+KTHREAD_APCSTATE_PROCESS]
1451 cmp dword ptr [ecx+EPROCESS_VDM_OBJECTS], 0
1452 jnz RaiseIrql
1453
1454 /* Otherwise, something is very wrong, raise an exception */
1455 sti
1456 jmp SetException
1457
1458 RaiseIrql:
1459
1460 /* Go to APC level */
1461 mov ecx, APC_LEVEL
1462 call @KfRaiseIrql@4
1463
1464 /* Save old IRQL and enable interrupts */
1465 push eax
1466 sti
1467
1468 /* Handle the opcode */
1469 call _Ki386HandleOpcodeV86@0
1470
1471 /* Check if this was VDM */
1472 test al, 0xFF
1473 jnz NoReflect
1474
1475 /* FIXME: TODO */
1476 UNHANDLED_PATH
1477
1478 NoReflect:
1479
1480 /* Lower IRQL and disable interrupts */
1481 pop ecx
1482 call @KfLowerIrql@4
1483 cli
1484
1485 /* Check if this was a V86 trap */
1486 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1487 jz NotV86Trap
1488
1489 /* Exit the V86 Trap */
1490 V86_TRAP_EPILOG
1491
1492 NotV86Trap:
1493
1494 /* Either this wasn't V86, or it was, but an APC interrupted us */
1495 jmp _Kei386EoiHelper@0
1496
1497 NotV86:
1498 /* Enter trap */
1499 TRAP_PROLOG kitd_a, kitd_t
1500
1501 /* Check if this was from kernel-mode */
1502 test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1503 jnz UserModeGpf
1504
1505 /* Check if we have a VDM alert */
1506 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1507 jnz VdmAlertGpf
1508
1509 /* Check for GPF during GPF */
1510 mov eax, [ebp+KTRAP_FRAME_EIP]
1511 cmp eax, offset CheckPrivilegedInstruction
1512 jbe KmodeGpf
1513 cmp eax, offset CheckPrivilegedInstruction2
1514
1515 /* FIXME: TODO */
1516 UNHANDLED_PATH
1517
1518 /* Get the opcode and trap frame */
1519 KmodeGpf:
1520 mov eax, [ebp+KTRAP_FRAME_EIP]
1521 mov eax, [eax]
1522 mov edx, [ebp+KTRAP_FRAME_EBP]
1523
1524 /* We want to check if this was POP [DS/ES/FS/GS] */
1525 add edx, KTRAP_FRAME_DS
1526 cmp al, 0x1F
1527 jz SegPopGpf
1528 add edx, KTRAP_FRAME_ES - KTRAP_FRAME_DS
1529 cmp al, 7
1530 jz SegPopGpf
1531 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1532 cmp ax, 0xA10F
1533 jz SegPopGpf
1534 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1535 cmp ax, 0xA90F
1536 jz SegPopGpf
1537
1538 /* It isn't, was it IRETD? */
1539 cmp al, 0xCF
1540 jne NotIretGpf
1541
1542 /* Get error code */
1543 lea edx, [ebp+KTRAP_FRAME_ESP]
1544 mov ax, [ebp+KTRAP_FRAME_ERROR_CODE]
1545 and ax, ~RPL_MASK
1546
1547 /* Get CS */
1548 mov cx, word ptr [edx+4]
1549 and cx, ~RPL_MASK
1550 cmp cx, ax
1551 jnz NotCsGpf
1552
1553 /* This should be a Ki386CallBios return */
1554 mov eax, offset _Ki386BiosCallReturnAddress
1555 cmp eax, [edx]
1556 jne NotBiosGpf
1557 mov eax, [edx+4]
1558 cmp ax, KGDT_R0_CODE + RPL_MASK
1559 jne NotBiosGpf
1560
1561 /* Jump to return address */
1562 jmp _Ki386BiosCallReturnAddress
1563
1564 NotBiosGpf:
1565 /* Check if the thread was in kernel mode */
1566 mov ebx, PCR[KPCR_CURRENT_THREAD]
1567 test byte ptr [ebx+KTHREAD_PREVIOUS_MODE], 0xFF
1568 jz UserModeGpf
1569
1570 /* Set RPL_MASK for check below */
1571 or word ptr [edx+4], RPL_MASK
1572
1573 NotCsGpf:
1574 /* Check if the IRET goes to user-mode */
1575 test dword ptr [edx+4], RPL_MASK
1576 jz UserModeGpf
1577
1578 /* Setup trap frame to copy */
1579 mov ecx, (KTRAP_FRAME_LENGTH - 12) / 4
1580 lea edx, [ebp+KTRAP_FRAME_ERROR_CODE]
1581
1582 TrapCopy:
1583
1584 /* Copy each field */
1585 mov eax, [edx]
1586 mov [edx+12], eax
1587 sub edx, 4
1588 loop TrapCopy
1589
1590 /* Enable interrupts and adjust stack */
1591 sti
1592 add esp, 12
1593 add ebp, 12
1594
1595 /* Setup exception record */
1596 mov ebx, [ebp+KTRAP_FRAME_EIP]
1597 mov esi, [ebp+KTRAP_FRAME_ERROR_CODE]
1598 and esi, 0xFFFF
1599 mov eax, STATUS_ACCESS_VIOLATION
1600 jmp _DispatchTwoParamZero
1601
1602 MsrCheck:
1603
1604 /* FIXME: Handle RDMSR/WRMSR */
1605 UNHANDLED_PATH
1606
1607 NotIretGpf:
1608
1609 /* Check if this was an MSR opcode */
1610 cmp al, 0xF
1611 jz MsrCheck
1612
1613 /* Check if DS is Ring 3 */
1614 cmp word ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1615 jz CheckEs
1616
1617 /* Otherwise, fix it up */
1618 mov dword ptr [ebp+KTRAP_FRAME_DS], KGDT_R3_DATA + RPL_MASK
1619 jmp ExitGpfTrap
1620
1621 CheckEs:
1622
1623 /* Check if ES is Ring 3 */
1624 cmp word ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1625 jz UserModeGpf
1626
1627 /* Otherwise, fix it up */
1628 mov dword ptr [ebp+KTRAP_FRAME_ES], KGDT_R3_DATA + RPL_MASK
1629 jmp ExitGpfTrap
1630
1631 SegPopGpf:
1632
1633 /* Sanity check */
1634 lea eax, [ebp+KTRAP_FRAME_ESP]
1635 cmp edx, eax
1636 jz HandleSegPop
1637 int 3
1638
1639 /* Handle segment POP fault by setting it to 0 */
1640 HandleSegPop:
1641 xor eax, eax
1642 mov dword ptr [edx], eax
1643
1644 ExitGpfTrap:
1645
1646 /* Do a trap exit */
1647 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoNotRestoreSegments, DoRestoreVolatiles, DoRestoreEverything
1648
1649 UserModeGpf:
1650
1651 /* If the previous mode was kernel, raise a fatal exception */
1652 mov eax, 13
1653 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1654 jz _KiSystemFatalException
1655
1656 /* Get the process and check which CS this came from */
1657 mov ebx, PCR[KPCR_CURRENT_THREAD]
1658 mov ebx, [ebx+KTHREAD_APCSTATE_PROCESS]
1659 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1660 jz CheckVdmGpf
1661
1662 /* Check if this is a VDM */
1663 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1664 jnz DispatchV86Gpf
1665
1666 /* Enable interrupts and check if we have an error code */
1667 sti
1668 cmp word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
1669 jnz SetException
1670 jmp CheckPrivilegedInstruction
1671
1672 HandleSegPop2:
1673 /* Update EIP (will be updated below again) */
1674 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1675
1676 HandleEsPop:
1677 /* Clear the segment, update EIP and ESP */
1678 mov dword ptr [edx], 0
1679 add dword ptr [ebp+KTRAP_FRAME_EIP], 1
1680 add dword ptr [ebp+KTRAP_FRAME_ESP], 4
1681 jmp _Kei386EoiHelper@0
1682
1683 CheckVdmGpf:
1684 /* Check if this is a VDM */
1685 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
1686 jz CheckPrivilegedInstruction
1687
1688 /* Bring interrupts back */
1689 sti
1690
1691 /* Check what kind of instruction this is */
1692 mov eax, [ebp+KTRAP_FRAME_EIP]
1693 mov eax, [eax]
1694
1695 /* FIXME: Check for BOP4 */
1696
1697 /* Check if this is POP ES */
1698 mov edx, ebp
1699 add edx, KTRAP_FRAME_ES
1700 cmp al, 0x07
1701 jz HandleEsPop
1702
1703 /* Check if this is POP FS */
1704 add edx, KTRAP_FRAME_FS - KTRAP_FRAME_ES
1705 cmp ax, 0xA10F
1706 jz HandleSegPop2
1707
1708 /* Check if this is POP GS */
1709 add edx, KTRAP_FRAME_GS - KTRAP_FRAME_FS
1710 cmp ax, 0xA90F
1711 jz HandleSegPop2
1712
1713 CheckPrivilegedInstruction:
1714 /* Bring interrupts back */
1715 sti
1716
1717 /* Setup a SEH handler */
1718 push ebp
1719 push offset _KiTrapExceptHandler
1720 push PCR[KPCR_EXCEPTION_LIST]
1721 mov PCR[KPCR_EXCEPTION_LIST], esp
1722
1723 /* Get EIP */
1724 mov esi, [ebp+KTRAP_FRAME_EIP]
1725
1726 /* Setup loop count */
1727 mov ecx, 15
1728
1729 InstLoop:
1730 /* Save loop count */
1731 push ecx
1732
1733 /* Get the instruction */
1734 lods byte ptr [esi]
1735
1736 /* Now lookup in the prefix table */
1737 mov ecx, 11
1738 mov edi, offset _KiTrapPrefixTable
1739 repnz scasb
1740
1741 /* Restore loop count */
1742 pop ecx
1743
1744 /* If it's not a prefix byte, check other instructions */
1745 jnz NotPrefixByte
1746
1747 /* Keep looping */
1748 loop InstLoop
1749
1750 /* Fixup the stack */
1751 pop PCR[KPCR_EXCEPTION_LIST]
1752 add esp, 8
1753
1754 /* Illegal instruction */
1755 jmp KmodeOpcode
1756
1757 NotPrefixByte:
1758 /* Check if it's a HLT */
1759 cmp al, 0x0F4
1760 je IsPrivInstruction
1761
1762 /* Check if the instruction has two bytes */
1763 cmp al, 0xF
1764 jne CheckRing3Io
1765
1766 /* Check if this is a LLDT or LTR */
1767 lods byte ptr [esi]
1768 cmp al, 0
1769 jne NotLldt
1770
1771 /* Check if this is an LLDT */
1772 lods byte ptr [esi]
1773 and al, 0x38
1774 cmp al, 0x10
1775 je IsPrivInstruction
1776
1777 /* Check if this is an LTR */
1778 cmp al, 0x18
1779 je IsPrivInstruction
1780
1781 /* Otherwise, access violation */
1782 jmp NotIoViolation
1783
1784 NotLldt:
1785 /* Check if this is LGDT or LIDT or LMSW */
1786 cmp al, 0x01
1787 jne NotGdt
1788
1789 /* Check if this is an LGDT */
1790 lods byte ptr [esi]
1791 and al, 0x38
1792 cmp al, 0x10
1793 je IsPrivInstruction
1794
1795 /* Check if this is an LIDT */
1796 cmp al, 0x18
1797 je IsPrivInstruction
1798
1799 /* Check if this is an LMSW */
1800 cmp al, 0x30
1801 je IsPrivInstruction
1802
1803 /* Otherwise, access violation */
1804 jmp NotIoViolation
1805
1806 NotGdt:
1807 /* Check if it's INVD or WBINVD */
1808 cmp al, 0x8
1809 je IsPrivInstruction
1810 cmp al, 0x9
1811 je IsPrivInstruction
1812
1813 /* Check if it's sysexit */
1814 cmp al, 0x35
1815 je IsPrivInstruction
1816
1817 /* Check if it's a DR move */
1818 cmp al, 0x26
1819 je IsPrivInstruction
1820
1821 /* Check if it's a CLTS */
1822 cmp al, 0x6
1823 je IsPrivInstruction
1824
1825 /* Check if it's a CR move */
1826 cmp al, 0x20
1827 jb NotIoViolation
1828
1829 /* Check if it's a DR move */
1830 cmp al, 0x24
1831 jbe IsPrivInstruction
1832
1833 /* Everything else is an access violation */
1834 jmp NotIoViolation
1835
1836 CheckRing3Io:
1837 /* Get EFLAGS and IOPL */
1838 mov ebx, [ebp+KTRAP_FRAME_EFLAGS]
1839 and ebx, EFLAGS_IOPL
1840 shr ebx, 12
1841
1842 /* Check the CS's RPL mask */
1843 mov ecx, [ebp+KTRAP_FRAME_CS]
1844 and ecx, RPL_MASK
1845 cmp ebx, ecx
1846 jge NotIoViolation
1847
1848 CheckPrivilegedInstruction2:
1849 /* Check if this is a CLI or STI */
1850 cmp al, 0xFA
1851 je IsPrivInstruction
1852 cmp al, 0xFB
1853 je IsPrivInstruction
1854
1855 /* Setup I/O table lookup */
1856 mov ecx, 13
1857 mov edi, offset _KiTrapIoTable
1858
1859 /* Loopup in the table */
1860 repnz scasb
1861 jnz NotIoViolation
1862
1863 /* FIXME: Check IOPM!!! */
1864
1865 IsPrivInstruction:
1866 /* Cleanup the SEH frame */
1867 pop PCR[KPCR_EXCEPTION_LIST]
1868 add esp, 8
1869
1870 /* Setup the exception */
1871 mov ebx, [ebp+KTRAP_FRAME_EIP]
1872 mov eax, STATUS_PRIVILEGED_INSTRUCTION
1873 jmp _DispatchNoParam
1874
1875 NotIoViolation:
1876 /* Cleanup the SEH frame */
1877 pop PCR[KPCR_EXCEPTION_LIST]
1878 add esp, 8
1879
1880 SetException:
1881 /* Setup the exception */
1882 mov ebx, [ebp+KTRAP_FRAME_EIP]
1883 mov esi, -1
1884 mov eax, STATUS_ACCESS_VIOLATION
1885 jmp _DispatchTwoParamZero
1886
1887 DispatchV86Gpf:
1888 /* FIXME */
1889 UNHANDLED_PATH
1890 .endfunc
1891
1892 .func KiTrap14
1893 TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
1894 _KiTrap14:
1895
1896 /* Enter trap */
1897 TRAP_PROLOG kite_a, kite_t
1898
1899 /* Check if we have a VDM alert */
1900 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
1901 jnz VdmAlertGpf
1902
1903 /* Get the current thread */
1904 mov edi, PCR[KPCR_CURRENT_THREAD]
1905
1906 /* Get the stack address of the frame */
1907 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
1908 sub eax, [edi+KTHREAD_INITIAL_STACK]
1909 jz NoFixUp
1910
1911 /* This isn't the base frame, check if it's the second */
1912 cmp eax, -KTRAP_FRAME_EFLAGS
1913 jb NoFixUp
1914
1915 /* Check if we have a TEB */
1916 mov eax, PCR[KPCR_TEB]
1917 or eax, eax
1918 jle NoFixUp
1919
1920 /* Fixup the frame */
1921 call _KiFixupFrame
1922
1923 /* Save CR2 */
1924 NoFixUp:
1925 mov edi, cr2
1926
1927 /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
1928 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1929 je HandlePf
1930
1931 /* Enable interrupts and check if we got here with interrupts disabled */
1932 sti
1933 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
1934 jz IllegalState
1935
1936 HandlePf:
1937 /* Send trap frame and check if this is kernel-mode or usermode */
1938 push ebp
1939 mov eax, [ebp+KTRAP_FRAME_CS]
1940 and eax, MODE_MASK
1941 push eax
1942
1943 /* Send faulting address and check if this is read or write */
1944 push edi
1945 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
1946 and eax, 1
1947 push eax
1948
1949 /* Call the access fault handler */
1950 call _MmAccessFault@16
1951 test eax, eax
1952 jl AccessFail
1953
1954 /* Access fault handled, return to caller */
1955 jmp _Kei386EoiHelper@0
1956
1957 AccessFail:
1958 /* First check if this is a fault in the S-LIST functions */
1959 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
1960 cmp [ebp+KTRAP_FRAME_EIP], ecx
1961 jz SlistFault
1962
1963 /* Check if this is a fault in the syscall handler */
1964 mov ecx, offset CopyParams
1965 cmp [ebp+KTRAP_FRAME_EIP], ecx
1966 jz SysCallCopyFault
1967 mov ecx, offset ReadBatch
1968 cmp [ebp+KTRAP_FRAME_EIP], ecx
1969 jnz CheckVdmPf
1970
1971 /* FIXME: TODO */
1972 UNHANDLED_PATH
1973 jmp _Kei386EoiHelper@0
1974
1975 SysCallCopyFault:
1976 /* FIXME: TODO */
1977 UNHANDLED_PATH
1978 jmp _Kei386EoiHelper@0
1979
1980 /* Check if the fault occured in a V86 mode */
1981 CheckVdmPf:
1982 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
1983 shr ecx, 1
1984 and ecx, 1
1985 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
1986 jnz VdmPF
1987
1988 /* Check if the fault occured in a VDM */
1989 mov esi, PCR[KPCR_CURRENT_THREAD]
1990 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
1991 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
1992 jz CheckStatus
1993
1994 /* Check if we this was in kernel-mode */
1995 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
1996 jz CheckStatus
1997 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
1998 jz CheckStatus
1999
2000 VdmPF:
2001 /* FIXME: TODO */
2002 UNHANDLED_PATH
2003
2004 /* Save EIP and check what kind of status failure we got */
2005 CheckStatus:
2006 mov esi, [ebp+KTRAP_FRAME_EIP]
2007 cmp eax, STATUS_ACCESS_VIOLATION
2008 je AccessViol
2009 cmp eax, STATUS_GUARD_PAGE_VIOLATION
2010 je SpecialCode
2011 cmp eax, STATUS_STACK_OVERFLOW
2012 je SpecialCode
2013
2014 /* Setup an in-page exception to dispatch */
2015 mov edx, ecx
2016 mov ebx, esi
2017 mov esi, edi
2018 mov ecx, 3
2019 mov edi, eax
2020 mov eax, STATUS_IN_PAGE_ERROR
2021 call _CommonDispatchException
2022
2023 AccessViol:
2024 /* Use more proper status code */
2025 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
2026
2027 SpecialCode:
2028 /* Setup a normal page fault exception */
2029 mov ebx, esi
2030 mov edx, ecx
2031 mov esi, edi
2032 jmp _DispatchTwoParam
2033
2034 SlistFault:
2035 /* FIXME: TODO */
2036 UNHANDLED_PATH
2037
2038 IllegalState:
2039
2040 /* This is completely illegal, bugcheck the system */
2041 push ebp
2042 push esi
2043 push ecx
2044 push eax
2045 push edi
2046 push IRQL_NOT_LESS_OR_EQUAL
2047 call _KeBugCheckWithTf@24
2048
2049 VdmAlertGpf:
2050
2051 /* FIXME: NOT SUPPORTED */
2052 UNHANDLED_PATH
2053 .endfunc
2054
2055 .func KiTrap0F
2056 TRAP_FIXUPS kitf_a, kitf_t, DoFixupV86, DoNotFixupAbios
2057 _KiTrap0F:
2058 /* Push error code */
2059 push 0
2060
2061 /* Enter trap */
2062 TRAP_PROLOG kitf_a, kitf_t
2063 sti
2064
2065 /* Raise a fatal exception */
2066 mov eax, 15
2067 jmp _KiSystemFatalException
2068 .endfunc
2069
2070 .func KiTrap16
2071 TRAP_FIXUPS kit10_a, kit10_t, DoFixupV86, DoNotFixupAbios
2072 _KiTrap16:
2073 /* Push error code */
2074 push 0
2075
2076 /* Enter trap */
2077 TRAP_PROLOG kit10_a, kit10_t
2078
2079 /* Check if this is the NPX Thread */
2080 mov eax, PCR[KPCR_CURRENT_THREAD]
2081 cmp eax, PCR[KPCR_NPX_THREAD]
2082
2083 /* Get the initial stack and NPX frame */
2084 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2085 lea ecx, [ecx-NPX_FRAME_LENGTH]
2086
2087 /* If this is a valid fault, handle it */
2088 jz HandleNpxFault
2089
2090 /* Otherwise, re-enable interrupts and set delayed error */
2091 sti
2092 or dword ptr [ecx+FN_CR0_NPX_STATE], CR0_TS
2093 jmp _Kei386EoiHelper@0
2094 .endfunc
2095
2096 .func KiTrap17
2097 TRAP_FIXUPS kit11_a, kit11_t, DoFixupV86, DoNotFixupAbios
2098 _KiTrap17:
2099 /* Push error code */
2100 push 0
2101
2102 /* Enter trap */
2103 TRAP_PROLOG kit11_a, kit11_t
2104
2105 /* FIXME: ROS Doesn't handle alignment faults yet */
2106 mov eax, 17
2107 jmp _KiSystemFatalException
2108 .endfunc
2109
2110 .globl _KiTrap19
2111 .func KiTrap19
2112 TRAP_FIXUPS kit19_a, kit19_t, DoFixupV86, DoNotFixupAbios
2113 _KiTrap19:
2114 /* Push error code */
2115 push 0
2116
2117 /* Enter trap */
2118 TRAP_PROLOG kit19_a, kit19_t
2119
2120 /* Check if this is the NPX Thread */
2121 mov eax, PCR[KPCR_CURRENT_THREAD]
2122 cmp eax, PCR[KPCR_NPX_THREAD]
2123
2124 /* If this is a valid fault, handle it */
2125 jz HandleXmmiFault
2126
2127 /* Otherwise, bugcheck */
2128 mov eax, 19
2129 jmp _KiSystemFatalException
2130
2131 HandleXmmiFault:
2132 /* Get the initial stack and NPX frame */
2133 mov ecx, [eax+KTHREAD_INITIAL_STACK]
2134 lea ecx, [ecx-NPX_FRAME_LENGTH]
2135
2136 /* Check if the trap came from V86 mode */
2137 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
2138 jnz V86Xmmi
2139
2140 /* Check if it came from kernel mode */
2141 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
2142 jz KernelXmmi
2143
2144 /* Check if it came from a VDM */
2145 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
2146 jne VdmXmmi
2147
2148 HandleUserXmmi:
2149 /* Set new CR0 */
2150 mov ebx, cr0
2151 and ebx, ~(CR0_MP + CR0_EM + CR0_TS)
2152 mov cr0, ebx
2153
2154 /* Check if we have FX support */
2155 test byte ptr _KeI386FxsrPresent, 1
2156 jz XmmiFnSave2
2157
2158 /* Save the state */
2159 fxsave [ecx]
2160 jmp XmmiMakeCr0Dirty
2161 XmmiFnSave2:
2162 fnsave [ecx]
2163 wait
2164
2165 XmmiMakeCr0Dirty:
2166 /* Make CR0 state not loaded */
2167 or ebx, NPX_STATE_NOT_LOADED
2168 or ebx, [ecx+FN_CR0_NPX_STATE]
2169 mov cr0, ebx
2170
2171 /* Update NPX state */
2172 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
2173 mov dword ptr PCR[KPCR_NPX_THREAD], 0
2174
2175 /* Clear the TS bit and re-enable interrupts */
2176 and dword ptr [ecx+FN_CR0_NPX_STATE], ~CR0_TS
2177
2178 /* Re-enable interrupts for user-mode and send the exception */
2179 sti
2180 mov ebx, [ebp+KTRAP_FRAME_EIP]
2181
2182 /* Get MxCSR and get current mask (bits 7-12) */
2183 movzx eax, word ptr [ecx+FX_MXCSR]
2184 mov edx, eax
2185 shr edx, 7
2186 not edx
2187
2188 /* Set faulting opcode address to 0 */
2189 mov esi, 0
2190
2191 /* Apply legal exceptions mask */
2192 and eax, 0x3f
2193
2194 /* Apply the mask we got in MXCSR itself */
2195 and eax, edx
2196
2197 /* Check for invalid operation */
2198 test al, 1
2199 jz 1f
2200
2201 /* Raise exception */
2202 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2203 jmp _DispatchOneParamZero
2204
2205 1:
2206 /* Check for zero divide */
2207 test al, 2
2208 jz 1f
2209
2210 /* Raise exception */
2211 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2212 jmp _DispatchOneParamZero
2213
2214 1:
2215 /* Check for denormal */
2216 test al, 4
2217 jz 1f
2218
2219 /* Raise exception */
2220 mov eax, STATUS_FLOAT_MULTIPLE_TRAPS
2221 jmp _DispatchOneParamZero
2222
2223 1:
2224 /* Check for overflow*/
2225 test al, 8
2226 jz 1f
2227
2228 /* Raise exception */
2229 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2230 jmp _DispatchOneParamZero
2231
2232 1:
2233 /* Check for denormal */
2234 test al, 16
2235 jz 1f
2236
2237 /* Raise exception */
2238 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2239 jmp _DispatchOneParamZero
2240
2241 1:
2242 /* Check for Precision */
2243 test al, 32
2244 jz UnexpectedXmmi
2245
2246 /* Raise exception */
2247 mov eax, STATUS_FLOAT_MULTIPLE_FAULTS
2248 jmp _DispatchOneParamZero
2249
2250 UnexpectedXmmi:
2251 /* Strange result, bugcheck the OS */
2252 sti
2253 push ebp
2254 push 1
2255 push 0
2256 push eax
2257 push 13
2258 push TRAP_CAUSE_UNKNOWN
2259 call _KeBugCheckWithTf@24
2260
2261 VdmXmmi:
2262 /* Check if this is a VDM */
2263 mov eax, PCR[KPCR_CURRENT_THREAD]
2264 mov ebx, [eax+KTHREAD_APCSTATE_PROCESS]
2265 cmp dword ptr [ebx+EPROCESS_VDM_OBJECTS], 0
2266 jz HandleUserXmmi
2267
2268 V86Xmmi:
2269 /* V86 XMMI not handled */
2270 UNHANDLED_PATH
2271
2272 KernelXmmi:
2273 /* Another weird situation */
2274 push ebp
2275 push 2
2276 push 0
2277 push eax
2278 push 13
2279 push TRAP_CAUSE_UNKNOWN
2280 call _KeBugCheckWithTf@24
2281 .endfunc
2282
2283
2284 .func KiSystemFatalException
2285 _KiSystemFatalException:
2286
2287 /* Push the trap frame */
2288 push ebp
2289
2290 /* Push empty parameters */
2291 push 0
2292 push 0
2293 push 0
2294
2295 /* Push trap number and bugcheck code */
2296 push eax
2297 push UNEXPECTED_KERNEL_MODE_TRAP
2298 call _KeBugCheckWithTf@24
2299 ret
2300 .endfunc
2301
2302 .func KiCoprocessorError@0
2303 _KiCoprocessorError@0:
2304
2305 /* Get the NPX Thread's Initial stack */
2306 mov eax, PCR[KPCR_NPX_THREAD]
2307 mov eax, [eax+KTHREAD_INITIAL_STACK]
2308
2309 /* Make space for the FPU Save area */
2310 sub eax, SIZEOF_FX_SAVE_AREA
2311
2312 /* Set the CR0 State */
2313 mov dword ptr [eax+FN_CR0_NPX_STATE], 8
2314
2315 /* Update it */
2316 mov eax, cr0
2317 or eax, 8
2318 mov cr0, eax
2319
2320 /* Return to caller */
2321 ret
2322 .endfunc
2323
2324 .func Ki16BitStackException
2325 _Ki16BitStackException:
2326
2327 /* Save stack */
2328 push ss
2329 push esp
2330
2331 /* Go to kernel mode thread stack */
2332 mov eax, PCR[KPCR_CURRENT_THREAD]
2333 add esp, [eax+KTHREAD_INITIAL_STACK]
2334
2335 /* Switch to good stack segment */
2336 UNHANDLED_PATH
2337 .endfunc
2338
2339 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
2340
2341 .globl _KiStartUnexpectedRange@0
2342 _KiStartUnexpectedRange@0:
2343
2344 GENERATE_INT_HANDLERS
2345
2346 .globl _KiEndUnexpectedRange@0
2347 _KiEndUnexpectedRange@0:
2348 jmp _KiUnexpectedInterruptTail
2349
2350 .func KiUnexpectedInterruptTail
2351 TRAP_FIXUPS kui_a, kui_t, DoFixupV86, DoFixupAbios
2352 _KiUnexpectedInterruptTail:
2353
2354 /* Enter interrupt trap */
2355 INT_PROLOG kui_a, kui_t, DoNotPushFakeErrorCode
2356
2357 /* Increase interrupt count */
2358 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2359
2360 /* Put vector in EBX and make space for KIRQL */
2361 mov ebx, [esp]
2362 sub esp, 4
2363
2364 /* Begin interrupt */
2365 push esp
2366 push ebx
2367 push HIGH_LEVEL
2368 call _HalBeginSystemInterrupt@12
2369
2370 /* Check if it was spurious or not */
2371 or al, al
2372 jnz Handled
2373
2374 /* Spurious, ignore it */
2375 add esp, 8
2376 jmp _Kei386EoiHelper2ndEntry
2377
2378 Handled:
2379 /* Unexpected interrupt, print a message on debug builds */
2380 #if DBG
2381 push [esp+4]
2382 push offset _UnexpectedMsg
2383 call _DbgPrint
2384 add esp, 8
2385 #endif
2386
2387 /* Exit the interrupt */
2388 mov esi, $
2389 cli
2390 call _HalEndSystemInterrupt@8
2391 jmp _Kei386EoiHelper@0
2392 .endfunc
2393
2394 .globl _KiUnexpectedInterrupt
2395 _KiUnexpectedInterrupt:
2396
2397 /* Bugcheck with invalid interrupt code */
2398 push TRAP_CAUSE_UNKNOWN
2399 call _KeBugCheck@4
2400
2401 /* INTERRUPT HANDLERS ********************************************************/
2402
2403 .func KiDispatchInterrupt@0
2404 _KiDispatchInterrupt@0:
2405
2406 /* Get the PCR and disable interrupts */
2407 mov ebx, PCR[KPCR_SELF]
2408 cli
2409
2410 /* Check if we have to deliver DPCs, timers, or deferred threads */
2411 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
2412 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
2413 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
2414 jz CheckQuantum
2415
2416 /* Save stack pointer and exception list, then clear it */
2417 push ebp
2418 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
2419 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
2420
2421 /* Save the stack and switch to the DPC Stack */
2422 mov edx, esp
2423 mov esp, [ebx+KPCR_PRCB_DPC_STACK]
2424 push edx
2425
2426 /* Deliver DPCs */
2427 mov ecx, [ebx+KPCR_PRCB]
2428 call @KiRetireDpcList@4
2429
2430 /* Restore stack and exception list */
2431 pop esp
2432 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
2433 pop ebp
2434
2435 CheckQuantum:
2436
2437 /* Re-enable interrupts */
2438 sti
2439
2440 /* Check if we have quantum end */
2441 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2442 jnz QuantumEnd
2443
2444 /* Check if we have a thread to swap to */
2445 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2446 je Return
2447
2448 /* Make space on the stack to save registers */
2449 sub esp, 3 * 4
2450 mov [esp+8], esi
2451 mov [esp+4], edi
2452 mov [esp+0], ebp
2453
2454 /* Get the current thread */
2455 mov edi, [ebx+KPCR_CURRENT_THREAD]
2456
2457 #ifdef CONFIG_SMP
2458 #error SMP Interrupt not handled!
2459 #endif
2460
2461 /* Get the next thread and clear it */
2462 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
2463 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
2464
2465 /* Set us as the current running thread */
2466 mov [ebx+KPCR_CURRENT_THREAD], esi
2467 mov byte ptr [esi+KTHREAD_STATE_], Running
2468 mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
2469
2470 /* Put thread in ECX and get the PRCB in EDX */
2471 mov ecx, edi
2472 lea edx, [ebx+KPCR_PRCB_DATA]
2473 call @KiQueueReadyThread@8
2474
2475 /* Set APC_LEVEL and do the swap */
2476 mov cl, APC_LEVEL
2477 call @KiSwapContextInternal@0
2478
2479 /* Restore registers */
2480 mov ebp, [esp+0]
2481 mov edi, [esp+4]
2482 mov esi, [esp+8]
2483 add esp, 3*4
2484
2485 Return:
2486 /* All done */
2487 ret
2488
2489 QuantumEnd:
2490 /* Disable quantum end and process it */
2491 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
2492 call _KiQuantumEnd@0
2493 ret
2494 .endfunc
2495
2496 .func KiInterruptTemplate
2497 _KiInterruptTemplate:
2498
2499 /* Enter interrupt trap */
2500 INT_PROLOG kit_a, kit_t, DoPushFakeErrorCode
2501
2502 _KiInterruptTemplate2ndDispatch:
2503 /* Dummy code, will be replaced by the address of the KINTERRUPT */
2504 mov edi, 0
2505
2506 _KiInterruptTemplateObject:
2507 /* Dummy jump, will be replaced by the actual jump */
2508 jmp _KeSynchronizeExecution@12
2509
2510 _KiInterruptTemplateDispatch:
2511 /* Marks the end of the template so that the jump above can be edited */
2512
2513 TRAP_FIXUPS kit_a, kit_t, DoFixupV86, DoFixupAbios
2514 .endfunc
2515
2516 .func KiChainedDispatch2ndLvl@0
2517 _KiChainedDispatch2ndLvl@0:
2518
2519 /* Not yet supported */
2520 UNHANDLED_PATH
2521 .endfunc
2522
2523 .func KiChainedDispatch@0
2524 _KiChainedDispatch@0:
2525
2526 /* Increase interrupt count */
2527 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2528
2529 /* Save trap frame */
2530 mov ebp, esp
2531
2532 /* Save vector and IRQL */
2533 mov eax, [edi+KINTERRUPT_VECTOR]
2534 mov ecx, [edi+KINTERRUPT_IRQL]
2535
2536 /* Save old irql */
2537 push eax
2538 sub esp, 4
2539
2540 /* Begin interrupt */
2541 push esp
2542 push eax
2543 push ecx
2544 call _HalBeginSystemInterrupt@12
2545
2546 /* Check if it was handled */
2547 or al, al
2548 jz SpuriousInt
2549
2550 /* Call the 2nd-level handler */
2551 call _KiChainedDispatch2ndLvl@0
2552
2553 /* Exit the interrupt */
2554 INT_EPILOG 0
2555 .endfunc
2556
2557 .func KiInterruptDispatch@0
2558 _KiInterruptDispatch@0:
2559
2560 /* Increase interrupt count */
2561 inc dword ptr PCR[KPCR_PRCB_INTERRUPT_COUNT]
2562
2563 /* Save trap frame */
2564 mov ebp, esp
2565
2566 /* Save vector and IRQL */
2567 mov eax, [edi+KINTERRUPT_VECTOR]
2568 mov ecx, [edi+KINTERRUPT_SYNCHRONIZE_IRQL]
2569
2570 /* Save old irql */
2571 push eax
2572 sub esp, 4
2573
2574 /* Begin interrupt */
2575 push esp
2576 push eax
2577 push ecx
2578 call _HalBeginSystemInterrupt@12
2579
2580 /* Check if it was handled */
2581 or al, al
2582 jz SpuriousInt
2583
2584 /* Acquire the lock */
2585 GetIntLock:
2586 mov esi, [edi+KINTERRUPT_ACTUAL_LOCK]
2587 ACQUIRE_SPINLOCK(esi, IntSpin)
2588
2589 /* Make sure that this interrupt isn't storming */
2590 VERIFY_INT kid
2591
2592 /* Save the tick count */
2593 mov ebx, _KeTickCount
2594
2595 /* Call the ISR */
2596 mov eax, [edi+KINTERRUPT_SERVICE_CONTEXT]
2597 push eax
2598 push edi
2599 call [edi+KINTERRUPT_SERVICE_ROUTINE]
2600
2601 /* Check if the ISR timed out */
2602 add ebx, _KiISRTimeout
2603 cmp _KeTickCount, ebx
2604 jnc IsrTimeout
2605
2606 ReleaseLock:
2607 /* Release the lock */
2608 RELEASE_SPINLOCK(esi)
2609
2610 /* Exit the interrupt */
2611 INT_EPILOG 0
2612
2613 SpuriousInt:
2614 /* Exit the interrupt */
2615 add esp, 8
2616 INT_EPILOG 1
2617
2618 #ifdef CONFIG_SMP
2619 IntSpin:
2620 SPIN_ON_LOCK esi, GetIntLock
2621 #endif
2622
2623 IsrTimeout:
2624 /* Print warning message */
2625 push [edi+KINTERRUPT_SERVICE_ROUTINE]
2626 push offset _IsrTimeoutMsg
2627 call _DbgPrint
2628 add esp,8
2629
2630 /* Break into debugger, then continue */
2631 int 3
2632 jmp ReleaseLock
2633
2634 /* Cleanup verification */
2635 VERIFY_INT_END kid, 0
2636 .endfunc
2637
2638 .globl _KeSynchronizeExecution@12
2639 .func KeSynchronizeExecution@12
2640 _KeSynchronizeExecution@12:
2641
2642 /* Save EBX and put the interrupt object in it */
2643 push ebx
2644 mov ebx, [esp+8]
2645
2646 /* Go to DIRQL */
2647 mov cl, [ebx+KINTERRUPT_SYNCHRONIZE_IRQL]
2648 call @KfRaiseIrql@4
2649
2650 /* Call the routine */
2651 push eax
2652 push [esp+20]
2653 call [esp+20]
2654
2655 /* Lower IRQL */
2656 mov ebx, eax
2657 pop ecx
2658 call @KfLowerIrql@4
2659
2660 /* Return status */
2661 mov eax, ebx
2662 pop ebx
2663 ret 12
2664 .endfunc