[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / include / internal / i386 / asmmacro.S
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/include/i386/asmmacro.S
5 * PURPOSE: Assembly Macros for Spinlocks and common Trap Code
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Timo Kreuzer (timo.kreuzer@reactos.org)
8 */
9
10 // Arguments for idt
11 #define INT_32_DPL0 HEX(08E00)
12 #define INT_32_DPL3 HEX(0EE00)
13
14 //
15 // These macros are inlined equivalents of KiAcquire/ReleaseSpinlock, that is,
16 // they will not be compiled into non-SMP builds. Usage is as follows:
17 //
18 // .BeginYourFunction
19 // mov reg, lockaddr
20 // ACQUIRE_SPINLOCK(reg, .spin)
21 // <thread-safe code here>
22 // RELEASE_SPINLOCK(reg)
23 // <misc code here>
24 // retn
25 // #IFDEF CONFIG_SMP
26 // .spin
27 // <any necessary steps to be able to jump back safely>
28 // SPIN_ON_LOCK(reg, .BeginYourFunction)
29 // #ENDIF
30 //
31 #ifdef CONFIG_SMP
32 #define LOCK lock
33 #define ACQUIRE_SPINLOCK(x, y) \
34 lock bts dword ptr [x], 0; \
35 jb y
36 #define RELEASE_SPINLOCK(x) mov byte ptr [x], 0
37 #define SPIN_ON_LOCK(x, y) \
38 1: \
39 test dword ptr [x], 1; \
40 jz y; \
41 pause; \
42 jmp 1b
43 #else
44 #define LOCK
45 #define ACQUIRE_SPINLOCK(x, y)
46 #define RELEASE_SPINLOCK(x)
47 #endif
48
49 //
50 // @name IDT
51 //
52 // This macro creates an IDT entry for the given handler
53 //
54 // @param Handler
55 // Pointer to the IDT handler
56 //
57 // @param Bits
58 // Descriptor Bits to associate
59 //
60 // @remark None.
61 //
62 MACRO(idt, Handler, Bits)
63 .long VAL(Handler)
64 .short VAL(Bits)
65 .short KGDT_R0_CODE
66 ENDM
67
68
69 KI_PUSH_FAKE_ERROR_CODE = HEX(0001)
70 KI_UNUSED = HEX(0002)
71 KI_NONVOLATILES_ONLY = HEX(0004)
72 KI_FAST_SYSTEM_CALL = HEX(0008)
73 KI_SOFTWARE_TRAP = HEX(0010)
74 KI_HARDWARE_INT = HEX(0020)
75 KI_DONT_SAVE_SEGS = HEX(0100)
76
77 MACRO(KiEnterTrap, Flags)
78 LOCAL kernel_trap
79 LOCAL not_v86_trap
80 LOCAL set_sane_segs
81
82 /* Check what kind of trap frame this trap requires */
83 if (Flags AND KI_FAST_SYSTEM_CALL)
84
85 /* SYSENTER requires us to build a complete ring transition trap frame */
86 FrameSize = KTRAP_FRAME_EIP
87
88 /* Fixup fs. cx is free to clobber */
89 mov cx, KGDT_R0_PCR
90 mov fs, cx
91
92 /* Get pointer to the TSS */
93 mov ecx, fs:[KPCR_TSS]
94
95 /* Get a stack pointer */
96 mov esp, [ecx + KTSS_ESP0]
97
98 /* Set up a fake hardware trap frame */
99 push KGDT_R3_DATA or RPL_MASK
100 push edx
101 pushfd
102 push KGDT_R3_CODE or RPL_MASK
103 push dword ptr ds:[KUSER_SHARED_SYSCALL_RET]
104
105 elseif (Flags AND KI_SOFTWARE_TRAP)
106
107 /* Software traps need a complete non-ring transition trap frame */
108 FrameSize = KTRAP_FRAME_ESP
109
110 /* Software traps need to get their EIP from the caller's frame */
111 pop eax
112
113 elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
114
115 /* If the trap doesn't have an error code, we'll make space for it */
116 FrameSize = KTRAP_FRAME_EIP
117
118 else
119
120 /* The trap already has an error code, so just make space for the rest */
121 FrameSize = KTRAP_FRAME_ERROR_CODE
122
123 endif
124
125 /* Make space for this frame */
126 sub esp, FrameSize
127
128 /* Save nonvolatile registers */
129 mov [esp + KTRAP_FRAME_EBP], ebp
130 mov [esp + KTRAP_FRAME_EBX], ebx
131 mov [esp + KTRAP_FRAME_ESI], esi
132 mov [esp + KTRAP_FRAME_EDI], edi
133
134 /* Save eax for system calls, for use by the C handler */
135 mov [esp + KTRAP_FRAME_EAX], eax
136
137 /* Does the caller want nonvolatiles only? */
138 if (NOT (Flags AND KI_NONVOLATILES_ONLY))
139 /* Otherwise, save the volatiles as well */
140 mov [esp + KTRAP_FRAME_ECX], ecx
141 mov [esp + KTRAP_FRAME_EDX], edx
142 endif
143
144 /* Save segment registers? */
145 if (Flags AND KI_DONT_SAVE_SEGS)
146
147 /* Initialize TrapFrame segment registers with sane values */
148 mov eax, KGDT_R3_DATA OR 3
149 mov ecx, fs
150 mov [esp + KTRAP_FRAME_DS], eax
151 mov [esp + KTRAP_FRAME_ES], eax
152 mov [esp + KTRAP_FRAME_FS], ecx
153 mov dword ptr [esp + KTRAP_FRAME_GS], 0
154
155 else
156
157 /* Check for V86 mode */
158 test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK / HEX(10000))
159 jz not_v86_trap
160
161 /* Restore V8086 segments into Protected Mode segments */
162 mov eax, [esp + KTRAP_FRAME_V86_DS]
163 mov ecx, [esp + KTRAP_FRAME_V86_ES]
164 mov [esp + KTRAP_FRAME_DS], eax
165 mov [esp + KTRAP_FRAME_ES], ecx
166 mov eax, [esp + KTRAP_FRAME_V86_FS]
167 mov ecx, [esp + KTRAP_FRAME_V86_GS]
168 mov [esp + KTRAP_FRAME_FS], eax
169 mov [esp + KTRAP_FRAME_GS], ecx
170 jmp set_sane_segs
171
172 not_v86_trap:
173
174 /* Save segment selectors */
175 mov eax, ds
176 mov ecx, es
177 mov [esp + KTRAP_FRAME_DS], eax
178 mov [esp + KTRAP_FRAME_ES], ecx
179 mov eax, fs
180 mov ecx, gs
181 mov [esp + KTRAP_FRAME_FS], eax
182 mov [esp + KTRAP_FRAME_GS], ecx
183
184 endif
185
186 set_sane_segs:
187 /* Load correct data segments */
188 mov ax, KGDT_R3_DATA OR RPL_MASK
189 mov ds, ax
190 mov es, ax
191
192 /* Fast system calls have fs already fixed */
193 if (Flags AND KI_FAST_SYSTEM_CALL)
194
195 /* Enable interrupts and set a sane FS value */
196 or dword ptr [esp + KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
197 mov dword ptr [esp + KTRAP_FRAME_FS], KGDT_R3_TEB or RPL_MASK
198
199 /* Set sane active EFLAGS */
200 push 2
201 popfd
202
203 /* Point edx to the usermode parameters */
204 add edx, 8
205 else
206 /* Otherwise fix fs now */
207 mov ax, KGDT_R0_PCR
208 mov fs, ax
209 endif
210
211 #if DBG
212 /* Keep the frame chain intact */
213 mov eax, [esp + KTRAP_FRAME_EIP]
214 mov [esp + KTRAP_FRAME_DEBUGEIP], eax
215 mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
216 mov ebp, esp
217 #endif
218
219 /* Set parameter 1 (ECX) to point to the frame */
220 mov ecx, esp
221
222 /* Clear direction flag */
223 cld
224
225 ENDM
226
227 MACRO(KiCallHandler, Handler)
228 #if DBG
229 /* Use a call to get the return address for back traces */
230 call Handler
231 #else
232 /* Use the faster jmp */
233 jmp Handler
234 #endif
235 nop
236 ENDM
237
238 MACRO(TRAP_ENTRY, Trap, Flags)
239 EXTERN @&Trap&Handler@4 :PROC
240 PUBLIC _&Trap
241 .PROC _&Trap
242 /* Generate proper debugging symbols */
243 FPO 0, 0, 0, 0, 1, FRAME_TRAP
244
245 /* Common code to create the trap frame */
246 KiEnterTrap Flags
247
248 /* Call the C handler */
249 KiCallHandler @&Trap&Handler@4
250 .ENDP
251 ENDM
252
253 #define KI_RESTORE_EAX HEX(001)
254 #define KI_RESTORE_ECX_EDX HEX(002)
255 #define KI_RESTORE_FS HEX(004)
256 #define KI_RESTORE_SEGMENTS HEX(008)
257 #define KI_RESTORE_EFLAGS HEX(010)
258 #define KI_EXIT_SYSCALL HEX(020)
259 #define KI_EXIT_JMP HEX(040)
260 #define KI_EXIT_RET HEX(080)
261 #define KI_EXIT_IRET HEX(100)
262 #define KI_EDITED_FRAME HEX(200)
263 #define KI_EXIT_RET8 HEX(400)
264 #define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
265
266 MACRO(KiTrapExitStub, Name, Flags)
267
268 PUBLIC @&Name&@4
269 @&Name&@4:
270
271 if (Flags AND KI_EXIT_RET8) OR (Flags AND KI_EXIT_IRET)
272
273 /* This is the IRET frame */
274 OffsetEsp = KTRAP_FRAME_EIP
275
276 elseif (Flags AND KI_RESTORE_EFLAGS)
277
278 /* We will pop EFlags off the stack */
279 OffsetEsp = KTRAP_FRAME_EFLAGS
280
281 else
282
283 OffsetEsp = 0
284
285 endif
286
287 if (Flags AND KI_EDITED_FRAME)
288
289 /* Load the requested ESP */
290 mov esp, [ecx + KTRAP_FRAME_TEMPESP]
291
292 /* Put return address on the new stack */
293 push [ecx + KTRAP_FRAME_EIP]
294
295 /* Put EFLAGS on the new stack */
296 push [ecx + KTRAP_FRAME_EFLAGS]
297
298 else
299
300 /* Point esp to an appropriate member of the frame */
301 lea esp, [ecx + OffsetEsp]
302
303 endif
304
305 /* Restore non volatiles */
306 mov ebx, [ecx + KTRAP_FRAME_EBX]
307 mov esi, [ecx + KTRAP_FRAME_ESI]
308 mov edi, [ecx + KTRAP_FRAME_EDI]
309 mov ebp, [ecx + KTRAP_FRAME_EBP]
310
311 if (Flags AND KI_RESTORE_EAX)
312
313 /* Restore eax */
314 mov eax, [ecx + KTRAP_FRAME_EAX]
315
316 endif
317
318 if (Flags AND KI_RESTORE_ECX_EDX)
319
320 /* Restore volatiles */
321 mov edx, [ecx + KTRAP_FRAME_EDX]
322 mov ecx, [ecx + KTRAP_FRAME_ECX]
323
324 elseif (Flags AND KI_EXIT_JMP)
325
326 /* Load return address into edx */
327 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
328
329 elseif (Flags AND KI_EXIT_SYSCALL)
330
331 /* Set sysexit parameters */
332 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
333 mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
334
335 /* Keep interrupts disabled until the sti / sysexit */
336 and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100))
337
338 endif
339
340 if (Flags AND KI_RESTORE_SEGMENTS)
341
342 /* Restore segments for user mode */
343 mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
344 mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
345 mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
346
347 endif
348
349 if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
350
351 /* Restore user mode FS */
352 mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
353
354 endif
355
356 if (Flags AND KI_RESTORE_EFLAGS)
357
358 if (Flags AND KI_EXIT_RET8)
359
360 /* We are at the IRET frame, so push EFLAGS first */
361 push dword ptr [esp + 8]
362
363 endif
364
365 /* Restore EFLAGS */
366 popfd
367
368 endif
369
370 if (Flags AND KI_EXIT_SYSCALL)
371
372 /* Enable interrupts and return to user mode.
373 Both must follow directly after another to be "atomic". */
374 sti
375 sysexit
376
377 elseif (Flags AND KI_EXIT_IRET)
378
379 /* Return with iret */
380 iretd
381
382 elseif (Flags AND KI_EXIT_JMP)
383
384 /* Return to kernel mode with a jmp */
385 jmp edx
386
387 elseif (Flags AND KI_EXIT_RET8)
388
389 /* Return to kernel mode with a ret 8 */
390 ret 8
391
392 elseif (Flags AND KI_EXIT_RET)
393
394 /* Return to kernel mode with a ret */
395 ret
396
397 endif
398
399 ENDM
400