1/* 2 * PROJECT: ReactOS SDK 3 * LICENSE: MIT (https://spdx.org/licenses/MIT) 4 * PURPOSE: ASM macros for x64 trap handling 5 * COPYRIGHT: Copyright 2011-2024 Timo Kreuzer (timo.kreuzer@reactos.org) 6 */ 7 8MACRO(ASSERT_TRAP_FRAME_INTS_ENABLED, Register) 9#if DBG 10 LOCAL IntsAreEnabled 11 test dword ptr [Register + KTRAP_FRAME_EFlags], HEX(200) 12 jnz IntsAreEnabled 13 int HEX(2C) 14IntsAreEnabled: 15#endif 16ENDM 17 18MACRO(ASSERT_TRAP_FRAME_IRQL_VALID, Register) 19#if DBG 20 LOCAL IrqlIsValid 21 mov rax, cr8 22 cmp byte ptr [Register + KTRAP_FRAME_PreviousIrql], al 23 je IrqlIsValid 24 int HEX(2C) 25IrqlIsValid: 26#endif 27ENDM 28 29MACRO(ASSERT_IRQL_PASSIVE) 30#if DBG 31 LOCAL IrqlIsPassive 32 mov rax, cr8 33 test rax, rax 34 jz IrqlIsPassive 35 int HEX(2C) 36IrqlIsPassive: 37#endif 38ENDM 39 40// Checks for user APCs and delivers them if necessary. 41// Clobbers all volatile registers except rax. 42MACRO(HANDLE_USER_APCS, ThreadReg, TrapFrame) 43 LOCAL NoUserApcPending 44 45 /* Check for pending user APC */ 46 cmp byte ptr [ThreadReg + ThApcState + AsUserApcPending], 0 47 jz NoUserApcPending 48 lea rcx, [TrapFrame] 49 call KiInitiateUserApc 50NoUserApcPending: 51ENDM 52 53APIC_EOI = HEX(0FFFFFFFFFFFE00B0) 54 55TF_SEGMENTS = HEX(08) 56TF_DEBUG = HEX(10) 57TF_IRQL = HEX(20) 58TF_SAVE_ALL = (TF_SEGMENTS) 59TF_HAS_ERROR_CODE = HEX(40) 60TF_SEND_EOI = HEX(80) 61//TF_SYSTEMSERVICE = (TRAPFLAG_VOLATILES or TRAPFLAG_DEBUG) 62TF_CHECKUSERAPC = HEX(100) 63 64/* 65 * Stack Layout: 66 * |-------------------| 67 * | KTRAP_FRAME | 68 * |-------------------| <- rbp 69 * | EXCEPTION_RECORD | 70 * |-------------------| 71 * | KEXCEPTION_FRAME | 72 * |-------------------| <- rsp 73 * 74 */ 75 76/* 77 * EnterTrap - Allocate KTRAP_FRAME_LENGTH and save registers to it 78 */ 79MACRO(EnterTrap, Flags) 80 LOCAL kernel_mode_entry 81 82 /* Save the trap flags for this trap */ 83 CurrentTrapFlags = VAL(Flags) 84 85 /* Size of hardware trap frame */ 86 if (Flags AND TF_HAS_ERROR_CODE) 87 .pushframe code 88 SIZE_INITIAL_FRAME = 6 * 8 89 else 90 .pushframe 91 SIZE_INITIAL_FRAME = 5 * 8 92 endif 93 94 /* Make room for a KTRAP_FRAME */ 95 sub rsp, (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME) 96 .allocstack (KTRAP_FRAME_LENGTH - SIZE_INITIAL_FRAME) 97 98 /* Save rbp */ 99 mov [rsp + KTRAP_FRAME_Rbp], rbp 100 .savereg rbp, KTRAP_FRAME_Rbp 101 102 /* Point rbp to the KTRAP_FRAME */ 103 lea rbp, [rsp] 104 .setframe rbp, 0 105 106 .endprolog 107 108 /* Save volatile registers */ 109 mov [rbp + KTRAP_FRAME_Rax], rax 110 mov [rbp + KTRAP_FRAME_Rcx], rcx 111 mov [rbp + KTRAP_FRAME_Rdx], rdx 112 mov [rbp + KTRAP_FRAME_R8], r8 113 mov [rbp + KTRAP_FRAME_R9], r9 114 mov [rbp + KTRAP_FRAME_R10], r10 115 mov [rbp + KTRAP_FRAME_R11], r11 116 117 /* Save volatile xmm registers */ 118 movaps [rbp + KTRAP_FRAME_Xmm0], xmm0 119 movaps [rbp + KTRAP_FRAME_Xmm1], xmm1 120 movaps [rbp + KTRAP_FRAME_Xmm2], xmm2 121 movaps [rbp + KTRAP_FRAME_Xmm3], xmm3 122 movaps [rbp + KTRAP_FRAME_Xmm4], xmm4 123 movaps [rbp + KTRAP_FRAME_Xmm5], xmm5 124 125 if (Flags AND TF_SEGMENTS) 126 /* Save segment selectors */ 127 mov [rbp + KTRAP_FRAME_SegDs], ds 128 mov [rbp + KTRAP_FRAME_SegEs], es 129 mov [rbp + KTRAP_FRAME_SegFs], fs 130 mov [rbp + KTRAP_FRAME_SegGs], gs 131 endif 132 133 /* Save MCXSR */ 134 stmxcsr [rbp + KTRAP_FRAME_MxCsr] 135 136#if DBG 137 mov ecx, MSR_GS_BASE 138 rdmsr 139 mov [rbp + KTRAP_FRAME_GsBase], eax 140 mov [rbp + KTRAP_FRAME_GsBase + 4], edx 141#endif 142 143 /* Save previous mode and check if it was user mode */ 144 mov ax, [rbp + KTRAP_FRAME_SegCs] 145 and al, 1 146 mov [rbp + KTRAP_FRAME_PreviousMode], al 147 jz kernel_mode_entry 148 149 /* Set sane segments */ 150 mov ax, (KGDT64_R3_DATA or RPL_MASK) 151 mov ds, ax 152 mov es, ax 153 swapgs 154 155 /* Load kernel MXCSR */ 156 ldmxcsr gs:[PcMxCsr] 157 158 ASSERT_IRQL_PASSIVE 159 160kernel_mode_entry: 161 162// if (Flags AND TF_IRQL) 163 /* Save previous irql */ 164 mov rax, cr8 165 mov [rbp + KTRAP_FRAME_PreviousIrql], al 166// endif 167 168 if (Flags AND TF_DEBUG) 169 /* Save debug registers */ 170 mov rax, dr0 171 mov [rbp + KTRAP_FRAME_Dr0], rax 172 mov rax, dr1 173 mov [rbp + KTRAP_FRAME_Dr1], rax 174 mov rax, dr2 175 mov [rbp + KTRAP_FRAME_Dr2], rax 176 mov rax, dr3 177 mov [rbp + KTRAP_FRAME_Dr3], rax 178 mov rax, dr6 179 mov [rbp + KTRAP_FRAME_Dr6], rax 180 mov rax, dr7 181 mov [rbp + KTRAP_FRAME_Dr7], rax 182 endif 183 184 /* Make sure the direction flag is cleared */ 185 cld 186ENDM 187 188/* 189 * ExitTrap - Restore registers and free stack space 190 */ 191MACRO(ExitTrap, Flags) 192 LOCAL kernel_mode_return 193 194 ASSERT_TRAP_FRAME_IRQL_VALID rbp 195 196 if (Flags AND TF_SEGMENTS) 197 /* Restore segment selectors */ 198 mov ds, [rbp + KTRAP_FRAME_SegDs] 199 mov es, [rbp + KTRAP_FRAME_SegEs] 200 mov fs, [rbp + KTRAP_FRAME_SegFs] 201 endif 202 203 if (Flags AND TF_IRQL) 204 /* Restore previous irql */ 205 movzx rax, byte ptr [rbp + KTRAP_FRAME_PreviousIrql] 206 mov cr8, rax 207 endif 208 209 /* Check if we came from user mode */ 210 test byte ptr [rbp + KTRAP_FRAME_SegCs], 1 211 jz kernel_mode_return 212 213 if (Flags AND TF_CHECKUSERAPC) 214 mov r10, gs:[PcCurrentThread] 215 HANDLE_USER_APCS r10, rbp 216 endif 217 218 ASSERT_TRAP_FRAME_INTS_ENABLED rbp 219 ASSERT_IRQL_PASSIVE 220 221 cli 222 223 /* Swap gs to user mode */ 224 swapgs 225 226kernel_mode_return: 227 228 /* Restore volatile registers */ 229 mov rax, [rbp + KTRAP_FRAME_Rax] 230 mov rcx, [rbp + KTRAP_FRAME_Rcx] 231 mov rdx, [rbp + KTRAP_FRAME_Rdx] 232 mov r8, [rbp + KTRAP_FRAME_R8] 233 mov r9, [rbp + KTRAP_FRAME_R9] 234 mov r10, [rbp + KTRAP_FRAME_R10] 235 mov r11, [rbp + KTRAP_FRAME_R11] 236 237 /* Restore xmm registers */ 238 movaps xmm0, [rbp + KTRAP_FRAME_Xmm0] 239 movaps xmm1, [rbp + KTRAP_FRAME_Xmm1] 240 movaps xmm2, [rbp + KTRAP_FRAME_Xmm2] 241 movaps xmm3, [rbp + KTRAP_FRAME_Xmm3] 242 movaps xmm4, [rbp + KTRAP_FRAME_Xmm4] 243 movaps xmm5, [rbp + KTRAP_FRAME_Xmm5] 244 245 /* Restore MCXSR */ 246 ldmxcsr [rbp + KTRAP_FRAME_MxCsr] 247 248 /* Restore rbp */ 249 mov rbp, [rbp + KTRAP_FRAME_Rbp] 250 251 /* Adjust stack pointer */ 252 add rsp, KTRAP_FRAME_Rip 253 254 if (Flags AND TF_SEND_EOI) 255 /* Write 0 to the local APIC EOI register */ 256 mov dword ptr [APIC_EOI], 0 257 endif 258 259 /* Return from the trap */ 260 iretq 261ENDM 262 263 264MACRO(TRAP_ENTRY, Trap, Flags) 265 EXTERN Trap&Handler :PROC 266 PUBLIC &Trap 267 FUNC &Trap 268 /* Common code to create the trap frame */ 269 EnterTrap Flags 270 271 /* Call the C handler */ 272 mov rcx, rbp 273 call Trap&Handler 274 275 /* Leave */ 276 ExitTrap Flags 277 ENDFUNC 278ENDM 279 280