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) \ 381: \ 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// 62MACRO(idt, Handler, Bits) 63 .long VAL(Handler) 64 .short VAL(Bits) 65 .short KGDT_R0_CODE 66ENDM 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 77MACRO(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 185set_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#if DBG 211 /* Keep the frame chain intact */ 212 mov eax, [esp + KTRAP_FRAME_EIP] 213 mov [esp + KTRAP_FRAME_DEBUGEIP], eax 214 mov [esp + KTRAP_FRAME_DEBUGEBP], ebp 215 mov ebp, esp 216#endif 217 218 /* Set parameter 1 (ECX) to point to the frame */ 219 mov ecx, esp 220 221 /* Clear direction flag */ 222 cld 223 224ENDM 225 226MACRO(KiCallHandler, Handler) 227#if DBG 228 /* Use a call to get the return address for back traces */ 229 call Handler 230#else 231 /* Use the faster jmp */ 232 jmp Handler 233#endif 234 nop 235ENDM 236 237MACRO(TRAP_ENTRY, Trap, Flags) 238 EXTERN @&Trap&Handler@4 :PROC 239 PUBLIC _&Trap 240 .PROC _&Trap 241 /* Generate proper debugging symbols */ 242 FPO 0, 0, 0, 0, 1, FRAME_TRAP 243 244 /* Common code to create the trap frame */ 245 KiEnterTrap Flags 246 247 /* Call the C handler */ 248 KiCallHandler @&Trap&Handler@4 249 .ENDP 250ENDM 251 252#define KI_NMI HEX(0001) 253 254MACRO(TASK_ENTRY, Trap, Flags) 255 EXTERN _&Trap&Handler :PROC 256 PUBLIC _&Trap 257 .PROC _&Trap 258 /* Generate proper debugging symbols */ 259 FPO 0, 0, 0, 0, 0, FRAME_TSS 260 261 /* Call the C handler */ 262 call _&Trap&Handler 263 264 if (Flags AND KI_NMI) 265 /* Return from NMI: return with iret and handle NMI recursion */ 266 iretd 267 jmp _&Trap 268 endif 269 270 .ENDP 271ENDM 272 273#define KI_RESTORE_EAX HEX(0001) 274#define KI_RESTORE_ECX_EDX HEX(0002) 275#define KI_RESTORE_FS HEX(0004) 276#define KI_RESTORE_SEGMENTS HEX(0008) 277#define KI_RESTORE_EFLAGS HEX(0010) 278#define KI_EXIT_SYSCALL HEX(0020) 279#define KI_EXIT_JMP HEX(0040) 280#define KI_EXIT_RET HEX(0080) 281#define KI_EXIT_IRET HEX(0100) 282#define KI_EDITED_FRAME HEX(0200) 283#define KI_EXIT_RET8 HEX(0400) 284#define KI_RESTORE_VOLATILES (KI_RESTORE_EAX OR KI_RESTORE_ECX_EDX) 285 286MACRO(KiTrapExitStub, Name, Flags) 287 LOCAL ret8_instruction 288 LOCAL not_nested_int 289 290PUBLIC @&Name&@4 291@&Name&@4: 292 293 if (Flags AND KI_EXIT_RET8) OR (Flags AND KI_EXIT_IRET) 294 295 /* This is the IRET frame */ 296 OffsetEsp = KTRAP_FRAME_EIP 297 298 elseif (Flags AND KI_RESTORE_EFLAGS) 299 300 /* We will pop EFlags off the stack */ 301 OffsetEsp = KTRAP_FRAME_EFLAGS 302 303 else 304 305 OffsetEsp = 0 306 307 endif 308 309 if (Flags AND KI_EDITED_FRAME) 310 311 /* Load the requested ESP */ 312 mov esp, [ecx + KTRAP_FRAME_TEMPESP] 313 314 /* Put return address on the new stack */ 315 push [ecx + KTRAP_FRAME_EIP] 316 317 /* Put EFLAGS on the new stack */ 318 push [ecx + KTRAP_FRAME_EFLAGS] 319 320 else 321 322 /* Point esp to an appropriate member of the frame */ 323 lea esp, [ecx + OffsetEsp] 324 325 endif 326 327 /* Restore non volatiles */ 328 mov ebx, [ecx + KTRAP_FRAME_EBX] 329 mov esi, [ecx + KTRAP_FRAME_ESI] 330 mov edi, [ecx + KTRAP_FRAME_EDI] 331 mov ebp, [ecx + KTRAP_FRAME_EBP] 332 333 if (Flags AND KI_RESTORE_EAX) 334 335 /* Restore eax */ 336 mov eax, [ecx + KTRAP_FRAME_EAX] 337 338 endif 339 340 if (Flags AND KI_RESTORE_ECX_EDX) 341 342 /* Restore volatiles */ 343 mov edx, [ecx + KTRAP_FRAME_EDX] 344 mov ecx, [ecx + KTRAP_FRAME_ECX] 345 346 elseif (Flags AND KI_EXIT_JMP) 347 348 /* Load return address into edx */ 349 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] 350 351 elseif (Flags AND KI_EXIT_SYSCALL) 352 353 /* Set sysexit parameters */ 354 mov edx, [esp - OffsetEsp + KTRAP_FRAME_EIP] 355 mov ecx, [esp - OffsetEsp + KTRAP_FRAME_ESP] 356 357 /* Keep interrupts disabled until the sti / sysexit */ 358 and byte ptr [esp - OffsetEsp + KTRAP_FRAME_EFLAGS + 1], NOT (EFLAGS_INTERRUPT_MASK / HEX(100)) 359 360 endif 361 362 if (Flags AND KI_RESTORE_SEGMENTS) 363 364 /* Restore segments for user mode */ 365 mov ds, [esp - OffsetEsp + KTRAP_FRAME_DS] 366 mov es, [esp - OffsetEsp + KTRAP_FRAME_ES] 367 mov gs, [esp - OffsetEsp + KTRAP_FRAME_GS] 368 369 endif 370 371 if ((Flags AND KI_RESTORE_FS) OR (Flags AND KI_RESTORE_SEGMENTS)) 372 373 /* Restore user mode FS */ 374 mov fs, [esp - OffsetEsp + KTRAP_FRAME_FS] 375 376 endif 377 378 if (Flags AND KI_RESTORE_EFLAGS) 379 380 if (Flags AND KI_EXIT_RET8) 381 382 /* Check if we return from a nested interrupt, i.e. an interrupt 383 that occurred in the ret8 return path between restoring 384 EFLAGS and returning with the ret instruction. */ 385 cmp dword ptr [esp], offset ret8_instruction 386 jne not_nested_int 387 388 /* This is a nested interrupt, so we have 2 IRET frames. 389 Skip the first, and go directly to the previous return address. 390 Do not pass Go. Do not collect $200 */ 391 add esp, 12 392 393not_nested_int: 394 /* We are at the IRET frame, so push EFLAGS first */ 395 push dword ptr [esp + 8] 396 397 endif 398 399 /* Restore EFLAGS */ 400 popfd 401 402 endif 403 404 if (Flags AND KI_EXIT_SYSCALL) 405 406 /* Enable interrupts and return to user mode. 407 Both must follow directly after another to be "atomic". */ 408 sti 409 sysexit 410 411 elseif (Flags AND KI_EXIT_IRET) 412 413 /* Return with iret */ 414 iretd 415 416 elseif (Flags AND KI_EXIT_JMP) 417 418 /* Return to kernel mode with a jmp */ 419 jmp edx 420 421 elseif (Flags AND KI_EXIT_RET8) 422 423 /* Return to kernel mode with a ret 8 */ 424ret8_instruction: 425 ret 8 426 427 elseif (Flags AND KI_EXIT_RET) 428 429 /* Return to kernel mode with a ret */ 430 ret 431 432 endif 433 434ENDM 435 436