1/* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Runtime Library (RTL) 4 * FILE: lib/rtl/amd64/except_asm.S 5 * PURPOSE: Exception support for AMD64 6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org) 7 */ 8 9/* INCLUDES ******************************************************************/ 10 11#include <asm.inc> 12#include <ksamd64.inc> 13 14/* FUNCTIONS *****************************************************************/ 15 16.code64 17 18/* 19 * VOID 20 * RtlCaptureContext( 21 * _Out_ PCONTEXT ContextRecord@<rcx>); 22 */ 23PUBLIC RtlCaptureContext 24.PROC RtlCaptureContext 25 26 /* Push rflags */ 27 pushfq 28 .ALLOCSTACK 8 29 .ENDPROLOG 30 31 /* Save rax first, we use it later to copy some data */ 32 mov [rcx + CxRax], rax 33 34 /* Set ContextFlags */ 35 mov dword ptr [rcx + CxContextFlags], (CONTEXT_FULL or CONTEXT_SEGMENTS) 36 37 /* Store the basic register context */ 38 mov [rcx + CxRcx], rcx 39 mov [rcx + CxRdx], rdx 40 mov [rcx + CxRbx], rbx 41 mov [rcx + CxRsi], rsi 42 43 /* Load return address in rax */ 44 mov rax, [rsp + 8] 45 46 mov [rcx + CxRdi], rdi 47 mov [rcx + CxRbp], rbp 48 mov [rcx + CxR8], r8 49 mov [rcx + CxR9], r9 50 mov [rcx + CxR10], r10 51 52 /* Store the return address */ 53 mov [rcx + CxRip], rax 54 55 mov [rcx + CxR11], r11 56 mov [rcx + CxR12], r12 57 mov [rcx + CxR13], r13 58 mov [rcx + CxR14], r14 59 mov [rcx + CxR15], r15 60 61 /* Load former stack pointer in rax */ 62 lea rax, [rsp + 16] 63 64 /* Store segment selectors */ 65 mov [rcx + CxSegCs], cs 66 mov [rcx + CxSegDs], ds 67 mov [rcx + CxSegEs], es 68 mov [rcx + CxSegFs], fs 69 mov [rcx + CxSegGs], gs 70 mov [rcx + CxSegSs], ss 71 72 /* Store stack pointer */ 73 mov [rcx + CxRsp], rax 74 75 /* Store xmm registers */ 76 movaps [rcx + CxXmm0], xmm0 77 movaps [rcx + CxXmm1], xmm1 78 movaps [rcx + CxXmm2], xmm2 79 movaps [rcx + CxXmm3], xmm3 80 movaps [rcx + CxXmm4], xmm4 81 movaps [rcx + CxXmm5], xmm5 82 movaps [rcx + CxXmm6], xmm6 83 movaps [rcx + CxXmm7], xmm7 84 85 /* Load rflags into eax */ 86 mov eax, [rsp] 87 88 movaps [rcx + CxXmm8], xmm8 89 movaps [rcx + CxXmm9], xmm9 90 movaps [rcx + CxXmm10], xmm10 91 movaps [rcx + CxXmm11], xmm11 92 movaps [rcx + CxXmm12], xmm12 93 movaps [rcx + CxXmm13], xmm13 94 movaps [rcx + CxXmm14], xmm14 95 movaps [rcx + CxXmm15], xmm15 96 97 /* Store eflags */ 98 mov [rcx + CxEFlags], eax 99 100 /* Store mxcsr */ 101 stmxcsr [rcx + CxMxCsr] 102 103 /* Check if we are in user mode */ 104 test byte ptr [rcx + CxSegCs], 3 105 jz RtlCaptureContextExit 106 107 /* Store legacy floating point registers */ 108 fxsave [rcx + CxFltSave] 109 110RtlCaptureContextExit: 111 112 /* Cleanup stack and return */ 113 add rsp, 8 114 ret 115.ENDP 116 117/* 118 * VOID 119 * RtlpRestoreContextInternal( 120 * _In_ PCONTEXT ContextRecord@<rcx>); 121 */ 122PUBLIC RtlpRestoreContextInternal 123.PROC RtlpRestoreContextInternal 124 125 /* Allocate space */ 126 sub rsp, HEX(8) 127 .ALLOCSTACK 8 128 .ENDPROLOG 129 130 /* Load the target stack pointer into rdx */ 131 mov rdx, [rcx + CxRsp] 132 133 /* Load EFlags into rax (zero extended) */ 134 mov eax, [rcx + CxEFlags] 135 136 /* Load the return address into r8 */ 137 mov r8, [rcx + CxRip] 138 139 /* Load rdx restore value into r9 */ 140 mov r9, [rcx + CxRdx] 141 142 /* Restore xmm registers */ 143 movaps xmm0, [rcx + CxXmm0] 144 movaps xmm1, [rcx + CxXmm1] 145 movaps xmm2, [rcx + CxXmm2] 146 movaps xmm3, [rcx + CxXmm3] 147 movaps xmm4, [rcx + CxXmm4] 148 movaps xmm5, [rcx + CxXmm5] 149 movaps xmm6, [rcx + CxXmm6] 150 movaps xmm7, [rcx + CxXmm7] 151 movaps xmm8, [rcx + CxXmm8] 152 movaps xmm9, [rcx + CxXmm9] 153 movaps xmm10, [rcx + CxXmm10] 154 movaps xmm11, [rcx + CxXmm11] 155 movaps xmm12, [rcx + CxXmm12] 156 movaps xmm13, [rcx + CxXmm13] 157 movaps xmm14, [rcx + CxXmm14] 158 movaps xmm15, [rcx + CxXmm15] 159 160 /* Copy Return address (now in r8) to the target stack */ 161 mov [rdx - 2 * 8], r8 162 163 /* Copy Eflags (now in rax) to the target stack */ 164 mov [rdx - 3 * 8], rax 165 166 /* Copy the value for rdx (now in r9) to the target stack */ 167 mov [rdx - 4 * 8], r9 168 169 /* Restore the integer registers */ 170 mov rbx, [rcx + CxRbx] 171 mov rsi, [rcx + CxRsi] 172 mov rdi, [rcx + CxRdi] 173 mov rbp, [rcx + CxRbp] 174 mov r10, [rcx + CxR10] 175 mov r11, [rcx + CxR11] 176 mov r12, [rcx + CxR12] 177 mov r13, [rcx + CxR13] 178 mov r14, [rcx + CxR14] 179 mov r15, [rcx + CxR15] 180 181 /* Restore segment selectors */ 182 mov ds, [rcx + CxSegDs] // FIXME: WOW64 context? 183 mov es, [rcx + CxSegEs] 184 mov fs, [rcx + CxSegFs] 185 //mov gs, [rcx + CxSegGs] 186 //mov ss, [rcx + CxSegSs] 187 188 /* Restore the registers we used */ 189 mov r8, [rcx + CxR8] 190 mov r9, [rcx + CxR9] 191 192 /* Restore MXCSR */ 193 ldmxcsr [rcx + CxMxCsr] 194 195 /* Check if we go to user mode */ 196 test byte ptr [rcx + CxSegCs], 3 197 jz Exit 198 199 /* Restore legacy floating point registers */ 200 fxrstor [rcx + CxFltSave] 201 202Exit: 203 204 /* Check if we go to a different cs */ 205 mov ax, cs 206 cmp [rcx + CxSegCs], ax 207 jne ReturnFar 208 209 /* Restore rax and rcx */ 210 mov rax, [rcx + CxRax] 211 mov rcx, [rcx + CxRcx] 212 213 /* Switch to the target stack */ 214 lea rsp, [rdx - 4 * 8] 215 216 /* Pop rdx from the stack */ 217 pop rdx 218 219 /* Pop Eflags from the stack */ 220 popfq 221 222 /* Return and fix up the stack */ 223 ret 8 224 225ReturnFar: 226 227 // We should never need this path 228 int HEX(2c) 229 230 /* Put cs on the stack for the far return */ 231 mov ax, [rcx + CxSegCs] 232 mov [rdx - 1 * 8], ax 233 234 /* Load ss */ 235 mov ss, [rcx + CxSegSs] 236 237 /* Restore rax and rcx */ 238 mov rax, [rcx + CxRax] 239 mov rcx, [rcx + CxRcx] 240 241 /* Switch to the target stack */ 242 lea rsp, [rdx - 4 * 8] 243 244 /* Pop rdx from the stack */ 245 pop rdx 246 247 /* Pop Eflags from the stack */ 248 popfq 249 250 /* Return far */ 251 retf 252 253.ENDP 254 255EXTERN RtlpCheckForActiveDebugger:PROC 256EXTERN RtlDispatchException:PROC 257EXTERN ZwContinue:PROC 258EXTERN ZwRaiseException:PROC 259EXTERN RtlRaiseStatus:PROC 260 261/* 262 * VOID 263 * RtlRaiseException ( 264 * _In_ PEXCEPTION_RECORD ExceptionRecord); 265 */ 266PUBLIC RtlRaiseException 267.PROC RtlRaiseException 268 269 /* Allocate stack space for a CONTEXT record */ 270 sub rsp, CONTEXT_FRAME_LENGTH + 8 271 .allocstack CONTEXT_FRAME_LENGTH + 8 272 273 /* Save the ExceptionRecord pointer */ 274 mov [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home], rcx 275 276 .endprolog 277 278 /* Save the return address in EXCEPTION_RECORD.ExceptionAddress */ 279 mov rdx, [rsp + CONTEXT_FRAME_LENGTH + 8] 280 mov [rcx + ErExceptionAddress], rdx 281 282 /* Capture the current context */ 283 mov rcx, rsp 284 call RtlCaptureContext 285 286 /* Fix up CONTEXT.Rip for the caller (RtlCaptureContext doesn't change rdx!) */ 287 mov [rsp + CxRip], rdx 288 289 /* Fix up CONTEXT.Rsp for the caller (+8 for the return address) */ 290 lea rdx, [rsp + CONTEXT_FRAME_LENGTH + 8 + 8] 291 mov [rsp + CxRsp], rdx 292 293 /* Check if a user mode debugger is active */ 294 call RtlpCheckForActiveDebugger 295 test al, al 296 mov r8b, 1 297 jnz RaiseException 298 299 /* Dispatch the exception */ 300 mov rcx, [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home] 301 mov rdx, rsp 302 call RtlDispatchException 303 304 /* Check if it was handled */ 305 test al, al 306 mov r8b, 0 307 jz RaiseException 308 309 /* It was handled, continue with the updated context */ 310 mov rcx, rsp 311 mov dl, 0 312 call ZwContinue 313 jmp RaiseStatus 314 315RaiseException: 316 317 mov rcx, [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home] 318 mov rdx, rsp 319 call ZwRaiseException 320 321RaiseStatus: 322 323 mov rcx, rax 324 mov rdx, rsp 325 call RtlRaiseStatus 326 327 int HEX(2c) 328.ENDP 329 330 331END 332 333 334