1d6ffecdc117d888323d3314fe94c06b6d213946
[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 #include <internal/i386/callconv.s>
14 .intel_syntax noprefix
15
16 #define Running 2
17 #define WrDispatchInt 0x1F
18
19 /* GLOBALS *******************************************************************/
20
21 .data
22 .globl _KiIdt
23 _KiIdt:
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) */
45 .rept 22
46 idt _KiTrap0F, INT_32_DPL0 /* INT 14-29: UNDEFINED INTERRUPTS */
47 .endr
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 */
55
56 /* System call entrypoints: */
57 .globl _KiFastCallEntry
58 .globl _KiSystemService
59
60 /* And special system-defined software traps: */
61 .globl _KiDispatchInterrupt@0
62
63 /* Interrupt template entrypoints */
64 .globl _KiInterruptTemplate
65 .globl _KiInterruptTemplateObject
66 .globl _KiInterruptTemplateDispatch
67
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
73 #endif
74
75 /* We implement the following trap exit points: */
76 .globl _Kei386EoiHelper@0 /* Exit from interrupt or H/W trap */
77
78 .globl _KiIdtDescriptor
79 _KiIdtDescriptor:
80 .short 0
81 .short 0x7FF
82 .long _KiIdt
83
84 .globl _KiUnexpectedEntrySize
85 _KiUnexpectedEntrySize:
86 .long _KiUnexpectedInterrupt1 - _KiUnexpectedInterrupt0
87
88 _UnexpectedMsg:
89 .asciz "\n\x7\x7!!! Unexpected Interrupt %02lx !!!\n"
90
91 _V86UnhandledMsg:
92 .asciz "\n\x7\x7!!! Unhandled V8086 (VDM) support at line: %lx!!!\n"
93
94 _UnhandledMsg:
95 .asciz "\n\x7\x7!!! Unhandled or Unexpected Code at line: %lx [%s]!!!\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 /* SOFTWARE INTERRUPT SERVICES ***********************************************/
104 .text
105
106 .func Kei386EoiHelper@0
107 _Kei386EoiHelper@0:
108
109 /* Disable interrupts */
110 cli
111
112 /* Check for, and deliver, User-Mode APCs if needed */
113 CHECK_FOR_APC_DELIVER 0
114
115 /* Exit and cleanup */
116 _Kei386EoiHelper2ndEntry:
117 TRAP_EPILOG NotFromSystemCall, DoNotRestorePreviousMode, DoRestoreSegments, DoRestoreVolatiles, DoNotRestoreEverything
118 .endfunc
119
120 V86_Exit:
121 /* Move to EDX position */
122 add esp, KTRAP_FRAME_EDX
123
124 /* Restore volatiles */
125 pop edx
126 pop ecx
127 pop eax
128
129 /* Move to non-volatiles */
130 lea esp, [ebp+KTRAP_FRAME_EDI]
131 pop edi
132 pop esi
133 pop ebx
134 pop ebp
135
136 /* Skip error code and return */
137 add esp, 4
138 iret
139
140 AbiosExit:
141 /* FIXME: TODO */
142 UNHANDLED_PATH
143
144 /* UNEXPECTED INTERRUPT HANDLERS **********************************************/
145
146 .globl _KiStartUnexpectedRange@0
147 _KiStartUnexpectedRange@0:
148
149 GENERATE_INT_HANDLERS
150
151 .globl _KiEndUnexpectedRange@0
152 _KiEndUnexpectedRange@0:
153 jmp _KiUnexpectedInterruptTail
154
155
156 /* DPC INTERRUPT HANDLER ******************************************************/
157
158 .func KiDispatchInterrupt@0
159 _KiDispatchInterrupt@0:
160
161 /* Preserve EBX */
162 push ebx
163
164 /* Get the PCR and disable interrupts */
165 mov ebx, PCR[KPCR_SELF]
166 cli
167
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]
172 jz CheckQuantum
173
174 /* Save stack pointer and exception list, then clear it */
175 push ebp
176 push dword ptr [ebx+KPCR_EXCEPTION_LIST]
177 mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
178
179 /* Save the stack and switch to the DPC Stack */
180 mov edx, esp
181 mov esp, [ebx+KPCR_PRCB_DPC_STACK]
182 push edx
183
184 /* Deliver DPCs */
185 mov ecx, [ebx+KPCR_PRCB]
186 call @KiRetireDpcList@4
187
188 /* Restore stack and exception list */
189 pop esp
190 pop dword ptr [ebx+KPCR_EXCEPTION_LIST]
191 pop ebp
192
193 CheckQuantum:
194
195 /* Re-enable interrupts */
196 sti
197
198 /* Check if we have quantum end */
199 cmp byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
200 jnz QuantumEnd
201
202 /* Check if we have a thread to swap to */
203 cmp byte ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
204 je Return
205
206 /* Make space on the stack to save registers */
207 sub esp, 3 * 4
208 mov [esp+8], esi
209 mov [esp+4], edi
210 mov [esp+0], ebp
211
212 /* Get the current thread */
213 mov edi, [ebx+KPCR_CURRENT_THREAD]
214
215 #ifdef CONFIG_SMP
216 /* Raise to synch level */
217 call _KeRaiseIrqlToSynchLevel@0
218
219 /* Set context swap busy */
220 mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
221
222 /* Acquire the PRCB Lock */
223 lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
224 jnb GetNext
225 lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
226 call @KefAcquireSpinLockAtDpcLevel@4
227 #endif
228
229 GetNext:
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
233
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
238
239 /* Put thread in ECX and get the PRCB in EDX */
240 mov ecx, edi
241 lea edx, [ebx+KPCR_PRCB_DATA]
242 call @KiQueueReadyThread@8
243
244 /* Set APC_LEVEL and do the swap */
245 mov cl, APC_LEVEL
246 call @KiSwapContextInternal@0
247
248 #ifdef CONFIG_SMP
249 /* Lower IRQL back to dispatch */
250 mov cl, DISPATCH_LEVEL
251 call @KfLowerIrql@4
252 #endif
253
254 /* Restore registers */
255 mov ebp, [esp+0]
256 mov edi, [esp+4]
257 mov esi, [esp+8]
258 add esp, 3*4
259
260 Return:
261 /* All done */
262 pop ebx
263 ret
264
265 QuantumEnd:
266 /* Disable quantum end and process it */
267 mov byte ptr [ebx+KPCR_PRCB_QUANTUM_END], 0
268 call _KiQuantumEnd@0
269 pop ebx
270 ret
271 .endfunc
272
273 /*
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.
280 *
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.
285 *
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.
292 *
293 */
294 .func KiInterruptTemplate
295 _KiInterruptTemplate:
296 TRAP_HANDLER_PROLOG 1, 0
297
298 _KiInterruptTemplate2ndDispatch:
299 /* Dummy code, will be replaced by the address of the KINTERRUPT */
300 mov edx, 0
301
302 _KiInterruptTemplateObject:
303 /* Jump to C code */
304 mov edi, offset @KiInterruptHandler@8
305 jmp edi
306
307 _KiInterruptTemplateDispatch:
308 /* Marks the end of the template so that the jump above can be edited */
309 .endfunc