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 /* 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 238if (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 242endif 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 251ENDM 252 253MACRO(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 262ENDM 263 264MACRO(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 277ENDM 278 279#define KI_NMI HEX(0001) 280 281MACRO(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 298ENDM 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 313MACRO(KiTrapExitStub, Name, Flags) 314 LOCAL ret8_instruction 315 LOCAL not_nested_int 316 317PUBLIC @&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 420not_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 */ 451ret8_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 461ENDM 462 463