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