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)
11 #define INT_32_DPL0 HEX(08E00)
12 #define INT_32_DPL3 HEX(0EE00)
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:
20 // ACQUIRE_SPINLOCK(reg, .spin)
21 // <thread-safe code here>
22 // RELEASE_SPINLOCK(reg)
27 // <any necessary steps to be able to jump back safely>
28 // SPIN_ON_LOCK(reg, .BeginYourFunction)
33 #define ACQUIRE_SPINLOCK(x, y) \
34 lock bts dword ptr [x], 0; \
36 #define RELEASE_SPINLOCK(x) mov byte ptr [x], 0
37 #define SPIN_ON_LOCK(x, y) \
39 test dword ptr [x], 1; \
45 #define ACQUIRE_SPINLOCK(x, y)
46 #define RELEASE_SPINLOCK(x)
52 // This macro creates an IDT entry for the given handler
55 // Pointer to the IDT handler
58 // Descriptor Bits to associate
62 MACRO(idt, Handler, Bits)
69 KI_PUSH_FAKE_ERROR_CODE = HEX(0001)
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)
77 MACRO(KiEnterTrap, Flags)
82 /* Check what kind of trap frame this trap requires */
83 if (Flags AND KI_FAST_SYSTEM_CALL)
85 /* SYSENTER requires us to build a complete ring transition trap frame */
86 FrameSize = KTRAP_FRAME_V86_ES
88 /* Fixup fs. cx is free to clobber */
92 /* Get pointer to the TSS */
93 mov ecx, fs:[KPCR_TSS]
95 /* Get a stack pointer */
96 mov esp, [ecx + KTSS_ESP0]
98 elseif (Flags AND KI_SOFTWARE_TRAP)
100 /* Software traps need a complete non-ring transition trap frame */
101 FrameSize = KTRAP_FRAME_ESP
103 /* Software traps need to get their EIP from the caller's frame */
106 elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
108 /* If the trap doesn't have an error code, we'll make space for it */
109 FrameSize = KTRAP_FRAME_EIP
113 /* The trap already has an error code, so just make space for the rest */
114 FrameSize = KTRAP_FRAME_ERROR_CODE
118 /* Make space for this frame */
121 /* Save nonvolatile registers */
122 mov [esp + KTRAP_FRAME_EBP], ebp
123 mov [esp + KTRAP_FRAME_EBX], ebx
124 mov [esp + KTRAP_FRAME_ESI], esi
125 mov [esp + KTRAP_FRAME_EDI], edi
127 /* Save eax for system calls, for use by the C handler */
128 mov [esp + KTRAP_FRAME_EAX], eax
130 /* Does the caller want nonvolatiles only? */
131 if (NOT (Flags AND KI_NONVOLATILES_ONLY))
132 /* Otherwise, save the volatiles as well */
133 mov [esp + KTRAP_FRAME_ECX], ecx
134 mov [esp + KTRAP_FRAME_EDX], edx
137 /* Save segment registers? */
138 if (Flags AND KI_DONT_SAVE_SEGS)
140 /* Initialize TrapFrame segment registers with sane values */
141 mov eax, KGDT_R3_DATA OR 3
143 mov [esp + KTRAP_FRAME_DS], eax
144 mov [esp + KTRAP_FRAME_ES], eax
145 mov [esp + KTRAP_FRAME_FS], ecx
146 mov dword ptr [esp + KTRAP_FRAME_GS], 0
150 /* Check for V86 mode */
151 test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK / HEX(10000))
154 /* Restore V8086 segments into Protected Mode segments */
155 mov eax, [esp + KTRAP_FRAME_V86_DS]
156 mov ecx, [esp + KTRAP_FRAME_V86_ES]
157 mov [esp + KTRAP_FRAME_DS], eax
158 mov [esp + KTRAP_FRAME_ES], ecx
159 mov eax, [esp + KTRAP_FRAME_V86_FS]
160 mov ecx, [esp + KTRAP_FRAME_V86_GS]
161 mov [esp + KTRAP_FRAME_FS], eax
162 mov [esp + KTRAP_FRAME_GS], ecx
167 /* Save segment selectors */
170 mov [esp + KTRAP_FRAME_DS], eax
171 mov [esp + KTRAP_FRAME_ES], ecx
174 mov [esp + KTRAP_FRAME_FS], eax
175 mov [esp + KTRAP_FRAME_GS], ecx
180 /* Load correct data segments */
181 mov ax, KGDT_R3_DATA OR RPL_MASK
185 /* Fast system calls have fs already fixed */
186 if (NOT (Flags AND KI_FAST_SYSTEM_CALL))
187 /* Otherwise fix fs now */
193 /* Keep the frame chain intact */
194 mov eax, [esp + KTRAP_FRAME_EIP]
195 mov [esp + KTRAP_FRAME_DEBUGEIP], eax
196 mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
200 /* Set parameter 1 (ECX) to point to the frame */
203 /* Clear direction flag */
208 MACRO(KiCallHandler, Handler)
210 /* Use a call to get the return address for back traces */
213 /* Use the faster jmp */
219 MACRO(TRAP_ENTRY, Trap, Flags)
220 EXTERN @&Trap&Handler@4 :PROC
224 KiCallHandler @&Trap&Handler@4
227 #define KI_RESTORE_EAX HEX(001)
228 #define KI_RESTORE_ECX_EDX HEX(002)
229 #define KI_RESTORE_FS HEX(004)
230 #define KI_RESTORE_SEGMENTS HEX(008)
231 #define KI_RESTORE_EFLAGS HEX(010)
232 #define KI_EXIT_SYSCALL HEX(020)
233 #define KI_EXIT_JMP HEX(040)
234 #define KI_EXIT_RET HEX(080)
235 #define KI_EXIT_IRET HEX(100)
236 #define KI_EDITED_FRAME HEX(200)
237 #define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
239 MACRO(KiTrapExitStub, Name, Flags)
244 if (Flags AND KI_RESTORE_EFLAGS)
246 /* We will pop EFlags off the stack */
247 OffsetEsp = KTRAP_FRAME_EFLAGS
249 elseif (Flags AND KI_EXIT_IRET)
251 /* This is the IRET frame */
252 OffsetEsp = KTRAP_FRAME_EIP
260 if (Flags AND KI_EDITED_FRAME)
262 /* Load the requested ESP */
263 mov esp, [ecx + KTRAP_FRAME_TEMPESP]
265 /* Put return address on the new stack */
266 push [ecx + KTRAP_FRAME_EIP]
268 /* Put EFLAGS on the new stack */
269 push [ecx + KTRAP_FRAME_EFLAGS]
273 /* Point esp to an appropriate member of the frame */
274 lea esp, [ecx + OffsetEsp]
278 /* Restore non volatiles */
279 mov ebx, [ecx + KTRAP_FRAME_EBX]
280 mov esi, [ecx + KTRAP_FRAME_ESI]
281 mov edi, [ecx + KTRAP_FRAME_EDI]
282 mov ebp, [ecx + KTRAP_FRAME_EBP]
284 if (Flags AND KI_RESTORE_EAX)
287 mov eax, [ecx + KTRAP_FRAME_EAX]
291 if (Flags AND KI_RESTORE_ECX_EDX)
293 /* Restore volatiles */
294 mov edx, [ecx + KTRAP_FRAME_EDX]
295 mov ecx, [ecx + KTRAP_FRAME_ECX]
297 elseif (Flags AND KI_EXIT_JMP)
299 /* Load return address into edx */
300 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
302 elseif (Flags AND KI_EXIT_SYSCALL)
304 /* Set sysexit parameters */
305 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
306 mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
308 /* Keep interrupts disabled until the sti / sysexit */
309 and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100))
313 if (Flags AND KI_RESTORE_SEGMENTS)
315 /* Restore segments for user mode */
316 mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
317 mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
318 mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
322 if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
324 /* Restore user mode FS */
325 mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
329 if (Flags AND KI_RESTORE_EFLAGS)
336 if (Flags AND KI_EXIT_SYSCALL)
338 /* Enable interrupts and return to user mode.
339 Both must follow directly after another to be "atomic". */
343 elseif (Flags AND KI_EXIT_IRET)
345 /* Return with iret */
348 elseif (Flags AND KI_EXIT_JMP)
350 /* Return to kernel mode with a jmp */
353 elseif (Flags AND KI_EXIT_RET)
355 /* Return to kernel mode with a ret */