- merge audio headers
[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/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 \Handler
64 .short \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_V86_ES
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 elseif (Flags AND KI_SOFTWARE_TRAP)
99
100 /* Software traps need a complete non-ring transition trap frame */
101 FrameSize = KTRAP_FRAME_ESP
102
103 /* Software traps need to get their EIP from the caller's frame */
104 pop eax
105
106 elseif (Flags AND KI_PUSH_FAKE_ERROR_CODE)
107
108 /* If the trap doesn't have an error code, we'll make space for it */
109 FrameSize = KTRAP_FRAME_EIP
110
111 else
112
113 /* The trap already has an error code, so just make space for the rest */
114 FrameSize = KTRAP_FRAME_ERROR_CODE
115
116 endif
117
118 /* Make space for this frame */
119 sub esp, FrameSize
120
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
126
127 /* Save eax for system calls, for use by the C handler */
128 mov [esp + KTRAP_FRAME_EAX], eax
129
130 /* Does the caller want nonvolatiles only? */
131 if ((Flags AND KI_NONVOLATILES_ONLY) == 0)
132 /* Otherwise, save the volatiles as well */
133 mov [esp + KTRAP_FRAME_ECX], ecx
134 mov [esp + KTRAP_FRAME_EDX], edx
135 endif
136
137 /* Save segment registers? */
138 if ((Flags AND KI_DONT_SAVE_SEGS) == 0)
139
140 /* Check for V86 mode */
141 test byte ptr [esp + KTRAP_FRAME_EFLAGS + 2], (EFLAGS_V86_MASK >> 16)
142 jz not_v86_trap
143
144 /* Restore V8086 segments into Protected Mode segments */
145 mov eax, [esp + KTRAP_FRAME_V86_DS]
146 mov ecx, [esp + KTRAP_FRAME_V86_ES]
147 mov [esp + KTRAP_FRAME_DS], eax
148 mov [esp + KTRAP_FRAME_ES], ecx
149 mov eax, [esp + KTRAP_FRAME_V86_FS]
150 mov ecx, [esp + KTRAP_FRAME_V86_GS]
151 mov [esp + KTRAP_FRAME_FS], eax
152 mov [esp + KTRAP_FRAME_GS], ecx
153 jmp set_sane_segs
154
155 not_v86_trap:
156
157 /* Save segment selectors */
158 mov eax, ds
159 mov ecx, es
160 mov [esp + KTRAP_FRAME_DS], eax
161 mov [esp + KTRAP_FRAME_ES], ecx
162 mov eax, fs
163 mov ecx, gs
164 mov [esp + KTRAP_FRAME_FS], eax
165 mov [esp + KTRAP_FRAME_GS], ecx
166
167 endif
168
169 set_sane_segs:
170 /* Load correct data segments */
171 mov ax, KGDT_R3_DATA OR RPL_MASK
172 mov ds, ax
173 mov es, ax
174
175 /* Fast system calls have fs already fixed */
176 if ((Flags AND KI_FAST_SYSTEM_CALL) == 0)
177 /* Otherwise fix fs now */
178 mov ax, KGDT_R0_PCR
179 mov fs, ax
180 endif
181
182 #if DBG
183 /* Keep the frame chain intact */
184 mov eax, [esp + KTRAP_FRAME_EIP]
185 mov [esp + KTRAP_FRAME_DEBUGEIP], eax
186 mov [esp + KTRAP_FRAME_DEBUGEBP], ebp
187 mov ebp, esp
188 #endif
189
190 /* Set parameter 1 (ECX) to point to the frame */
191 mov ecx, esp
192
193 /* Clear direction flag */
194 cld
195
196 ENDM
197
198 MACRO(KiCallHandler, Handler)
199 #if DBG
200 /* Use a call to get the return address for back traces */
201 call Handler
202 #else
203 /* Use the faster jmp */
204 jmp Handler
205 #endif
206 nop
207 ENDM
208
209 MACRO(TRAP_ENTRY, Trap, Flags)
210 EXTERN @&Trap&Handler@4 :PROC
211 PUBLIC _&Trap
212 _&Trap:
213 KiEnterTrap Flags
214 KiCallHandler @&Trap&Handler@4
215 ENDM
216
217 #define KI_RESTORE_EAX HEX(001)
218 #define KI_RESTORE_ECX_EDX HEX(002)
219 #define KI_RESTORE_FS HEX(004)
220 #define KI_RESTORE_SEGMENTS HEX(008)
221 #define KI_RESTORE_EFLAGS HEX(010)
222 #define KI_EXIT_SYSCALL HEX(020)
223 #define KI_EXIT_JMP HEX(040)
224 #define KI_EXIT_RET HEX(080)
225 #define KI_EXIT_IRET HEX(100)
226 #define KI_EDITED_FRAME HEX(200)
227 #define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX)
228
229 MACRO(KiTrapExitStub, Name, Flags)
230
231 PUBLIC @&Name&@4
232 @&Name&@4:
233
234 if (Flags AND KI_RESTORE_EFLAGS)
235
236 /* We will pop EFlags off the stack */
237 OffsetEsp = KTRAP_FRAME_EFLAGS
238
239 elseif (Flags AND KI_EXIT_IRET)
240
241 /* This is the IRET frame */
242 OffsetEsp = KTRAP_FRAME_EIP
243
244 else
245
246 OffsetEsp = 0
247
248 endif
249
250 if (Flags AND KI_EDITED_FRAME)
251
252 /* Load the requested ESP */
253 mov esp, [ecx + KTRAP_FRAME_TEMPESP]
254
255 /* Put return address on the new stack */
256 push [ecx + KTRAP_FRAME_EIP]
257
258 /* Put EFLAGS on the new stack */
259 push [ecx + KTRAP_FRAME_EFLAGS]
260
261 else
262
263 /* Point esp to an appropriate member of the frame */
264 lea esp, [ecx + OffsetEsp]
265
266 endif
267
268 /* Restore non volatiles */
269 mov ebx, [ecx + KTRAP_FRAME_EBX]
270 mov esi, [ecx + KTRAP_FRAME_ESI]
271 mov edi, [ecx + KTRAP_FRAME_EDI]
272 mov ebp, [ecx + KTRAP_FRAME_EBP]
273
274 if (Flags AND KI_RESTORE_EAX)
275
276 /* Restore eax */
277 mov eax, [ecx + KTRAP_FRAME_EAX]
278
279 endif
280
281 if (Flags AND KI_RESTORE_ECX_EDX)
282
283 /* Restore volatiles */
284 mov edx, [ecx + KTRAP_FRAME_EDX]
285 mov ecx, [ecx + KTRAP_FRAME_ECX]
286
287 elseif (Flags AND KI_EXIT_JMP)
288
289 /* Load return address into edx */
290 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
291
292 elseif (Flags AND KI_EXIT_SYSCALL)
293
294 /* Set sysexit parameters */
295 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP]
296 mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP]
297
298 /* Keep interrupts disabled until the sti / sysexit */
299 and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], ~(EFLAGS_INTERRUPT_MASK >> 8)
300
301 endif
302
303 if (Flags AND KI_RESTORE_SEGMENTS)
304
305 /* Restore segments for user mode */
306 mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS]
307 mov es, [esp - OffsetEsp + KTRAP_FRAME_ES]
308 mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS]
309
310 endif
311
312 if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS))
313
314 /* Restore user mode FS */
315 mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS]
316
317 endif
318
319 if (Flags AND KI_RESTORE_EFLAGS)
320
321 /* Restore EFLAGS */
322 popf
323
324 endif
325
326 if (Flags AND KI_EXIT_SYSCALL)
327
328 /* Enable interrupts and return to user mode.
329 Both must follow directly after another to be "atomic". */
330 sti
331 sysexit
332
333 elseif (Flags AND KI_EXIT_IRET)
334
335 /* Return with iret */
336 iret
337
338 elseif (Flags AND KI_EXIT_JMP)
339
340 /* Return to kernel mode with a jmp */
341 jmp edx
342
343 elseif (Flags AND KI_EXIT_RET)
344
345 /* Return to kernel mode with a ret */
346 ret
347
348 endif
349
350 ENDM
351