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.
9 /* INCLUDES ******************************************************************/
12 #include <internal/i386/asmmacro.S>
13 #include <internal/i386/callconv.s>
14 .intel_syntax noprefix
17 #define WrDispatchInt 0x1F
19 /* GLOBALS *******************************************************************/
24 /* This is the Software Interrupt Table that we handle in this file: */
25 idt _KiTrap00, INT_32_DPL0 /* INT 00: Divide Error (#DE) */
26 idt _KiTrap01, INT_32_DPL0 /* INT 01: Debug Exception (#DB) */
27 idt _KiTrap02, INT_32_DPL0 /* INT 02: NMI Interrupt */
28 idt _KiTrap03, INT_32_DPL3 /* INT 03: Breakpoint Exception (#BP) */
29 idt _KiTrap04, INT_32_DPL3 /* INT 04: Overflow Exception (#OF) */
30 idt _KiTrap05, INT_32_DPL0 /* INT 05: BOUND Range Exceeded (#BR) */
31 idt _KiTrap06, INT_32_DPL0 /* INT 06: Invalid Opcode Code (#UD) */
32 idt _KiTrap07, INT_32_DPL0 /* INT 07: Device Not Available (#NM) */
33 idt _KiTrap08, INT_32_DPL0 /* INT 08: Double Fault Exception (#DF) */
34 idt _KiTrap09, INT_32_DPL0 /* INT 09: RESERVED */
35 idt _KiTrap0A, INT_32_DPL0 /* INT 0A: Invalid TSS Exception (#TS) */
36 idt _KiTrap0B, INT_32_DPL0 /* INT 0B: Segment Not Present (#NP) */
37 idt _KiTrap0C, INT_32_DPL0 /* INT 0C: Stack Fault Exception (#SS) */
38 idt _KiTrap0D, INT_32_DPL0 /* INT 0D: General Protection (#GP) */
39 idt _KiTrap0E, INT_32_DPL0 /* INT 0E: Page-Fault Exception (#PF) */
40 idt _KiTrap0F, INT_32_DPL0 /* INT 0F: RESERVED */
41 idt _KiTrap10, INT_32_DPL0 /* INT 10: x87 FPU Error (#MF) */
42 idt _KiTrap11, INT_32_DPL0 /* INT 11: Align Check Exception (#AC) */
43 idt _KiTrap0F, INT_32_DPL0 /* INT 12: Machine Check Exception (#MC)*/
44 idt _KiTrap0F, INT_32_DPL0 /* INT 13: SIMD FPU Exception (#XF) */
46 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
48 idt _KiGetTickCount, INT_32_DPL3 /* INT 2A: Get Tick Count Handler */
49 idt _KiCallbackReturn, INT_32_DPL3 /* INT 2B: User-Mode Callback Return */
50 idt _KiRaiseAssertion, INT_32_DPL3 /* INT 2C: Debug Assertion Handler */
51 idt _KiDebugService, INT_32_DPL3 /* INT 2D: Debug Service Handler */
52 idt _KiSystemService, INT_32_DPL3 /* INT 2E: System Call Service Handler */
53 idt _KiTrap0F, INT_32_DPL0 /* INT 2F: RESERVED */
54 GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
56 /* System call entrypoints: */
57 .globl _KiFastCallEntry
58 .globl _KiSystemService
60 /* And special system-defined software traps: */
61 .globl _KiDispatchInterrupt@0
63 /* Interrupt template entrypoints */
64 .globl _KiInterruptTemplate
65 .globl _KiInterruptTemplateObject
66 .globl _KiInterruptTemplateDispatch
68 #ifndef HAL_INTERRUPT_SUPPORT_IN_C
69 /* Chained and Normal generic interrupt handlers for 1st and 2nd level entry*/
70 .globl _KiChainedDispatch2ndLvl@0
71 .globl _KiInterruptDispatch@0
72 .globl _KiChainedDispatch@0
75 /* We implement the following trap exit points: */
76 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
78 .globl _KiIdtDescriptor
84 .globl _KiUnexpectedEntrySize
85 _KiUnexpectedEntrySize:
86 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
89 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
92 .asciz "\n\x7\x7!!! Unhandled V8086 (VDM) support at line: %lx!!!\n"
95 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx [%s]!!!\n"
98 .asciz "\n*** ISR at %lx took over .5 second\n"
101 .asciz "\n*** ISR at %lx appears to have an interrupt storm\n"
103 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
106 .func Kei386EoiHelper@0
109 /* Disable interrupts */
112 /* Check for, and deliver, User-Mode APCs if needed */
113 CHECK_FOR_APC_DELIVER 0
115 /* Exit and cleanup */
116 _Kei386EoiHelper2ndEntry:
117 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
121 /* Move to EDX position */
122 add esp, KTRAP_FRAME_EDX
124 /* Restore volatiles */
129 /* Move to non-volatiles */
130 lea esp, [ebp+KTRAP_FRAME_EDI]
136 /* Skip error code and return */
144 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
146 .globl _KiStartUnexpectedRange@0
147 _KiStartUnexpectedRange@0:
149 GENERATE_INT_HANDLERS
151 .globl _KiEndUnexpectedRange@0
152 _KiEndUnexpectedRange@0:
153 jmp _KiUnexpectedInterruptTail
156 /* DPC INTERRUPT HANDLER ******************************************************/
158 .func KiDispatchInterrupt@0
159 _KiDispatchInterrupt@0:
164 /* Get the PCR and disable interrupts */
165 mov ebx, PCR[KPCR_SELF]
168 /* Check if we have to deliver DPCs, timers, or deferred threads */
169 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
170 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
171 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
174 /* Save stack pointer and exception list, then clear it */
176 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
177 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
179 /* Save the stack and switch to the DPC Stack */
181 mov esp, [ebx+KPCR_PRCB_DPC_STACK]
185 mov ecx, [ebx+KPCR_PRCB]
186 call @KiRetireDpcList@4
188 /* Restore stack and exception list */
190 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
195 /* Re-enable interrupts */
198 /* Check if we have quantum end */
199 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
202 /* Check if we have a thread to swap to */
203 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
206 /* Make space on the stack to save registers */
212 /* Get the current thread */
213 mov edi, [ebx+KPCR_CURRENT_THREAD]
216 /* Raise to synch level */
217 call _KeRaiseIrqlToSynchLevel@0
219 /* Set context swap busy */
220 mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
222 /* Acquire the PRCB Lock */
223 lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
225 lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
226 call @KefAcquireSpinLockAtDpcLevel@4
230 /* Get the next thread and clear it */
231 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
232 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
234 /* Set us as the current running thread */
235 mov [ebx+KPCR_CURRENT_THREAD], esi
236 mov byte ptr [esi+KTHREAD_STATE_], Running
237 mov byte ptr [edi+KTHREAD_WAIT_REASON], WrDispatchInt
239 /* Put thread in ECX and get the PRCB in EDX */
241 lea edx, [ebx+KPCR_PRCB_DATA]
242 call @KiQueueReadyThread@8
244 /* Set APC_LEVEL and do the swap */
246 call @KiSwapContextInternal@0
249 /* Lower IRQL back to dispatch */
250 mov cl, DISPATCH_LEVEL
254 /* Restore registers */
266 /* Disable quantum end and process it */
267 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
274 * We setup the stack for a trap frame in the KINTERRUPT DispatchCode itself and
275 * then move the stack address in ECX, since the handlers are FASTCALL. We also
276 * need to know the address of the KINTERRUPT. To do this, we maintain the old
277 * dynamic patching technique (EDX instead of EDI, however) and let the C API
278 * up in KeInitializeInterrupt replace the 0 with the address. Since this is in
279 * EDX, it becomes the second parameter for our FASTCALL function.
281 * Finally, we jump directly to the C interrupt handler, which will choose the
282 * appropriate dispatcher (chained, single, flat, floating) that was setup. The
283 * dispatchers themselves are also C FASTCALL functions. This double-indirection
284 * maintains the NT model should anything depend on it.
286 * Note that since we always jump to the C handler which then jumps to the C
287 * dispatcher, the first JMP in the template object is NOT patched anymore since
288 * it's static. Also, keep in mind this code is dynamically copied into nonpaged
289 * pool! It runs off the KINTERRUPT directly, so you can't just JMP to the code
290 * since JMPs are relative, and the location of the JMP below is dynamic. So we
291 * use EDI to store the absolute offset, and jump to that instead.
294 .func KiInterruptTemplate
295 _KiInterruptTemplate:
296 TRAP_HANDLER_PROLOG 1, 0
298 _KiInterruptTemplate2ndDispatch:
299 /* Dummy code, will be replaced by the address of the KINTERRUPT */
302 _KiInterruptTemplateObject:
304 mov edi, offset @KiInterruptHandler@8
307 _KiInterruptTemplateDispatch:
308 /* Marks the end of the template so that the jump above can be edited */