[BROWSEUI] SHExplorerParseCmdLine: Fix parsing of /root (#6752)
[reactos.git] / ntoskrnl / include / internal / i386 / asmmacro.S
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/include/internal/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 #define KI_PUSH_FAKE_ERROR_CODE HEX(0001)
70 #define KI_UNUSED HEX(0002)
71 #define KI_NONVOLATILES_ONLY HEX(0004)
72 #define KI_FAST_SYSTEM_CALL HEX(0008)
73 #define KI_SOFTWARE_TRAP HEX(0010)
74 #define KI_HARDWARE_INT HEX(0020)
75 #define KI_DONT_SAVE_SEGS HEX(0100)
76
77 MACRO(KiEnterTrap, Flags)
78 LOCAL not_v86_trap
79 LOCAL set_sane_segs
80
81 /* Check what kind of trap frame this trap requires */
82 if (Flags AND KI_FAST_SYSTEM_CALL)
83
84 /* SYSENTER requires us to build a complete ring transition trap frame */
85 FrameSize = KTRAP_FRAME_EIP
86
87 /* Fixup fs. cx is free to clobber */
88 mov cx, KGDT_R0_PCR
89 mov fs, cx
90
91 /* Get pointer to the TSS */
92 mov ecx, fs:[KPCR_TSS]
93
94 /* Get a stack pointer */
95 mov esp, [ecx + KTSS_ESP0]
96
97 /* Set up a fake hardware trap frame */
98 push KGDT_R3_DATA or RPL_MASK
99 push edx
100 pushfd
101 push KGDT_R3_CODE or RPL_MASK
102 push dword ptr ds:[KUSER_SHARED_SYSCALL_RET]
103
104 elseif (Flags AND KI_SOFTWARE_TRAP)
105
106 /* Software traps need a complete non-ring transition trap frame */
107 FrameSize = KTRAP_FRAME_ESP
108
109 /* Software traps need to get their EIP from the caller's frame */
110 pop eax
111
112 elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
113
114 /* If the trap doesn't have an error code, we'll make space for it */
115 FrameSize = KTRAP_FRAME_EIP
116
117 else
118
119 /* The trap already has an error code, so just make space for the rest */
120 FrameSize = KTRAP_FRAME_ERROR_CODE
121
122 endif
123
124 /* Make space for this frame */
125 sub esp, FrameSize
126
127 /* Save nonvolatile registers */
128 mov [esp + KTRAP_FRAME_EBP], ebp
129 mov [esp + KTRAP_FRAME_EBX], ebx
130 mov [esp + KTRAP_FRAME_ESI], esi
131 mov [esp + KTRAP_FRAME_EDI], edi
132
133 /* Save eax for system calls, for use by the C handler */
134 mov [esp + KTRAP_FRAME_EAX], eax
135
136 /* Does the caller want nonvolatiles only? */
137 if (NOT (Flags AND KI_NONVOLATILES_ONLY))
138 /* Otherwise, save the volatiles as well */
139 mov [esp + KTRAP_FRAME_ECX], ecx
140 mov [esp + KTRAP_FRAME_EDX], edx
141 endif
142
143 /* Save segment registers? */
144 if (Flags AND KI_DONT_SAVE_SEGS)
145
146 /* Initialize TrapFrame segment registers with sane values */
147 mov eax, KGDT_R3_DATA OR RPL_MASK
148 mov ecx, fs
149 mov [esp + KTRAP_FRAME_DS], eax
150 mov [esp + KTRAP_FRAME_ES], eax
151 mov [esp + KTRAP_FRAME_FS], ecx
152 mov dword ptr [esp + KTRAP_FRAME_GS], 0
153
154 else
155
156 /* Check for V86 mode */
157 test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK / HEX(10000))
158 jz not_v86_trap
159
160 /* Restore V8086 segments into Protected Mode segments */
161 mov eax, [esp + KTRAP_FRAME_V86_DS]
162 mov ecx, [esp + KTRAP_FRAME_V86_ES]
163 mov [esp + KTRAP_FRAME_DS], eax
164 mov [esp + KTRAP_FRAME_ES], ecx
165 mov eax, [esp + KTRAP_FRAME_V86_FS]
166 mov ecx, [esp + KTRAP_FRAME_V86_GS]
167 mov [esp + KTRAP_FRAME_FS], eax
168 mov [esp + KTRAP_FRAME_GS], ecx
169 jmp set_sane_segs
170
171 not_v86_trap:
172
173 /* Save segment selectors */
174 mov eax, ds
175 mov ecx, es
176 mov [esp + KTRAP_FRAME_DS], eax
177 mov [esp + KTRAP_FRAME_ES], ecx
178 mov eax, fs
179 mov ecx, gs
180 mov [esp + KTRAP_FRAME_FS], eax
181 mov [esp + KTRAP_FRAME_GS], ecx
182
183 endif
184
185 set_sane_segs:
186 /* Load correct data segments */
187 mov ax, KGDT_R3_DATA OR RPL_MASK
188 mov ds, ax
189 mov es, ax
190
191 /* Fast system calls have fs already fixed */
192 if (Flags AND KI_FAST_SYSTEM_CALL)
193
194 /* Enable interrupts and set a sane FS value */
195 or dword ptr [esp + KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
196 mov dword ptr [esp + KTRAP_FRAME_FS], KGDT_R3_TEB or RPL_MASK
197
198 /* Set sane active EFLAGS */
199 push 2
200 popfd
201
202 /* Point edx to the usermode parameters */
203 add edx, 8
204 else
205 /* Otherwise fix fs now */
206 mov ax, KGDT_R0_PCR
207 mov fs, ax
208 endif
209
210 /* Save ExceptionList, since the C handler might use SEH */
211 mov eax, fs:[KPCR_EXCEPTION_LIST]
212 mov [esp + KTRAP_FRAME_EXCEPTION_LIST], eax
213
214 #if DBG
215 /* Keep the frame chain intact */
216 mov eax, [esp + KTRAP_FRAME_EIP]
217 mov [esp + KTRAP_FRAME_DEBUGEIP], eax
218 mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
219 mov ebp, esp
220
221 /* Tell GDB what just happened */
222 CFI_DEF_CFA_REGISTER ebp
223 CFI_ADJUST_CFA_OFFSET FrameSize
224 CFI_REL_OFFSET ss, KTRAP_FRAME_SS
225 CFI_REL_OFFSET gs, KTRAP_FRAME_GS
226 CFI_REL_OFFSET fs, KTRAP_FRAME_FS
227 CFI_REL_OFFSET es, KTRAP_FRAME_ES
228 CFI_REL_OFFSET ds, KTRAP_FRAME_DS
229 CFI_REL_OFFSET cs, KTRAP_FRAME_CS
230
231 CFI_REL_OFFSET edi, KTRAP_FRAME_EDI
232 CFI_REL_OFFSET esi, KTRAP_FRAME_ESI
233 CFI_REL_OFFSET ebx, KTRAP_FRAME_EBX
234 CFI_REL_OFFSET ebp, KTRAP_FRAME_EBP
235 CFI_REL_OFFSET eip, KTRAP_FRAME_EIP
236 CFI_REL_OFFSET esp, KTRAP_FRAME_ESP
237
238 if (NOT (Flags AND KI_NONVOLATILES_ONLY))
239 CFI_REL_OFFSET eax, KTRAP_FRAME_EAX
240 CFI_REL_OFFSET ecx, KTRAP_FRAME_ECX
241 CFI_REL_OFFSET edx, KTRAP_FRAME_EDX
242 endif
243 #endif
244
245 /* Set parameter 1 (ECX) to point to the frame */
246 mov ecx, esp
247
248 /* Clear direction flag */
249 cld
250
251 ENDM
252
253 MACRO(KiCallHandler, Handler)
254 #if DBG
255 /* Use a call to get the return address for back traces */
256 call Handler
257 #else
258 /* Use the faster jmp */
259 jmp Handler
260 #endif
261 nop
262 ENDM
263
264 MACRO(TRAP_ENTRY, Trap, Flags)
265 EXTERN @&Trap&Handler@4 :PROC
266 PUBLIC _&Trap
267 .PROC _&Trap
268 /* Generate proper debugging symbols */
269 FPO 0, 0, 0, 0, 1, FRAME_TRAP
270
271 /* Common code to create the trap frame */
272 KiEnterTrap Flags
273
274 /* Call the C handler */
275 KiCallHandler @&Trap&Handler@4
276 .ENDP
277 ENDM
278
279 #define KI_NMI HEX(0001)
280
281 MACRO(TASK_ENTRY, Trap, Flags)
282 EXTERN _&Trap&Handler :PROC
283 PUBLIC _&Trap
284 .PROC _&Trap
285 /* Generate proper debugging symbols */
286 FPO 0, 0, 0, 0, 0, FRAME_TSS
287
288 /* Call the C handler */
289 call _&Trap&Handler
290
291 if (Flags AND KI_NMI)
292 /* Return from NMI: return with iret and handle NMI recursion */
293 iretd
294 jmp _&Trap
295 endif
296
297 .ENDP
298 ENDM
299
300 #define KI_RESTORE_EAX HEX(0001)
301 #define KI_RESTORE_ECX_EDX HEX(0002)
302 #define KI_RESTORE_FS HEX(0004)
303 #define KI_RESTORE_SEGMENTS HEX(0008)
304 #define KI_RESTORE_EFLAGS HEX(0010)
305 #define KI_EXIT_SYSCALL HEX(0020)
306 #define KI_EXIT_JMP HEX(0040)
307 #define KI_EXIT_RET HEX(0080)
308 #define KI_EXIT_IRET HEX(0100)
309 #define KI_EDITED_FRAME HEX(0200)
310 #define KI_EXIT_RET8 HEX(0400)
311 #define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
312
313 MACRO(KiTrapExitStub, Name, Flags)
314 LOCAL ret8_instruction
315 LOCAL not_nested_int
316
317 PUBLIC @&Name&@4
318 @&Name&@4:
319
320 if (Flags AND KI_EXIT_RET8) OR (Flags AND KI_EXIT_IRET)
321
322 /* This is the IRET frame */
323 OffsetEsp = KTRAP_FRAME_EIP
324
325 elseif (Flags AND KI_RESTORE_EFLAGS)
326
327 /* We will pop EFlags off the stack */
328 OffsetEsp = KTRAP_FRAME_EFLAGS
329
330 else
331
332 OffsetEsp = 0
333
334 endif
335
336 if (Flags AND KI_EDITED_FRAME)
337
338 /* Load the requested ESP */
339 mov esp, [ecx + KTRAP_FRAME_TEMPESP]
340
341 /* Put return address on the new stack */
342 push [ecx + KTRAP_FRAME_EIP]
343
344 /* Put EFLAGS on the new stack */
345 push [ecx + KTRAP_FRAME_EFLAGS]
346
347 else
348
349 /* Point esp to an appropriate member of the frame */
350 lea esp, [ecx + OffsetEsp]
351
352 endif
353
354 /* Restore non volatiles */
355 mov ebx, [ecx + KTRAP_FRAME_EBX]
356 mov esi, [ecx + KTRAP_FRAME_ESI]
357 mov edi, [ecx + KTRAP_FRAME_EDI]
358 mov ebp, [ecx + KTRAP_FRAME_EBP]
359
360 if (Flags AND KI_RESTORE_EAX)
361
362 /* Restore eax */
363 mov eax, [ecx + KTRAP_FRAME_EAX]
364
365 endif
366
367 if (Flags AND KI_RESTORE_ECX_EDX)
368
369 /* Restore volatiles */
370 mov edx, [ecx + KTRAP_FRAME_EDX]
371 mov ecx, [ecx + KTRAP_FRAME_ECX]
372
373 elseif (Flags AND KI_EXIT_JMP)
374
375 /* Load return address into edx */
376 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
377
378 elseif (Flags AND KI_EXIT_SYSCALL)
379
380 /* Set sysexit parameters */
381 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
382 mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
383
384 /* Keep interrupts disabled until the sti / sysexit */
385 and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100))
386
387 endif
388
389 if (Flags AND KI_RESTORE_SEGMENTS)
390
391 /* Restore segments for user mode */
392 mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
393 mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
394 mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
395
396 endif
397
398 if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
399
400 /* Restore user mode FS */
401 mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
402
403 endif
404
405 if (Flags AND KI_RESTORE_EFLAGS)
406
407 if (Flags AND KI_EXIT_RET8)
408
409 /* Check if we return from a nested interrupt, i.e. an interrupt
410 that occurred in the ret8 return path between restoring
411 EFLAGS and returning with the ret instruction. */
412 cmp dword ptr [esp], offset ret8_instruction
413 jne not_nested_int
414
415 /* This is a nested interrupt, so we have 2 IRET frames.
416 Skip the first, and go directly to the previous return address.
417 Do not pass Go. Do not collect $200 */
418 add esp, 12
419
420 not_nested_int:
421 /* We are at the IRET frame, so push EFLAGS first */
422 push dword ptr [esp + 8]
423
424 endif
425
426 /* Restore EFLAGS */
427 popfd
428
429 endif
430
431 if (Flags AND KI_EXIT_SYSCALL)
432
433 /* Enable interrupts and return to user mode.
434 Both must follow directly after another to be "atomic". */
435 sti
436 sysexit
437
438 elseif (Flags AND KI_EXIT_IRET)
439
440 /* Return with iret */
441 iretd
442
443 elseif (Flags AND KI_EXIT_JMP)
444
445 /* Return to kernel mode with a jmp */
446 jmp edx
447
448 elseif (Flags AND KI_EXIT_RET8)
449
450 /* Return to kernel mode with a ret 8 */
451 ret8_instruction:
452 ret 8
453
454 elseif (Flags AND KI_EXIT_RET)
455
456 /* Return to kernel mode with a ret */
457 ret
458
459 endif
460
461 ENDM
462