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 legacy floating point registers */ 98 fxsave [rcx + CxFltSave] 99 stmxcsr [rcx + CxMxCsr] 100 101 /* Store rflags */ 102 mov [rcx + CxEFlags], eax 103 104 /* Cleanup stack and return */ 105 add rsp, 8 106 ret 107.ENDP 108 109/* 110 * VOID 111 * RtlpRestoreContextInternal( 112 * _In_ PCONTEXT ContextRecord@<rcx>); 113 */ 114PUBLIC RtlpRestoreContextInternal 115.PROC RtlpRestoreContextInternal 116 117 /* Allocate space */ 118 sub rsp, HEX(8) 119 .ALLOCSTACK 8 120 .ENDPROLOG 121 122 /* Restore legacy floating point registers (It is slow, so do it first) */ 123 ldmxcsr [rcx + CxMxCsr] 124 fxrstor [rcx + CxFltSave] 125 126 /* Load the target stack pointer into rdx */ 127 mov rdx, [rcx + CxRsp] 128 129 /* Load EFlags into rax (zero extended) */ 130 mov eax, [rcx + CxEFlags] 131 132 /* Load the return address into r8 */ 133 mov r8, [rcx + CxRip] 134 135 /* Load rdx restore value into r9 */ 136 mov r9, [rcx + CxRdx] 137 138 /* Restore xmm registers */ 139 movaps xmm0, [rcx + CxXmm0] 140 movaps xmm1, [rcx + CxXmm1] 141 movaps xmm2, [rcx + CxXmm2] 142 movaps xmm3, [rcx + CxXmm3] 143 movaps xmm4, [rcx + CxXmm4] 144 movaps xmm5, [rcx + CxXmm5] 145 movaps xmm6, [rcx + CxXmm6] 146 movaps xmm7, [rcx + CxXmm7] 147 movaps xmm8, [rcx + CxXmm8] 148 movaps xmm9, [rcx + CxXmm9] 149 movaps xmm10, [rcx + CxXmm10] 150 movaps xmm11, [rcx + CxXmm11] 151 movaps xmm12, [rcx + CxXmm12] 152 movaps xmm13, [rcx + CxXmm13] 153 movaps xmm14, [rcx + CxXmm14] 154 movaps xmm15, [rcx + CxXmm15] 155 156 /* Copy Return address (now in r8) to the target stack */ 157 mov [rdx - 2 * 8], r8 158 159 /* Copy Eflags (now in rax) to the target stack */ 160 mov [rdx - 3 * 8], rax 161 162 /* Copy the value for rdx (now in r9) to the target stack */ 163 mov [rdx - 4 * 8], r9 164 165 /* Restore the integer registers */ 166 mov rbx, [rcx + CxRbx] 167 mov rsi, [rcx + CxRsi] 168 mov rdi, [rcx + CxRdi] 169 mov rbp, [rcx + CxRbp] 170 mov r10, [rcx + CxR10] 171 mov r11, [rcx + CxR11] 172 mov r12, [rcx + CxR12] 173 mov r13, [rcx + CxR13] 174 mov r14, [rcx + CxR14] 175 mov r15, [rcx + CxR15] 176 177 /* Restore segment selectors */ 178 mov ds, [rcx + CxSegDs] // FIXME: WOW64 context? 179 mov es, [rcx + CxSegEs] 180 mov fs, [rcx + CxSegFs] 181 //mov gs, [rcx + CxSegGs] 182 //mov ss, [rcx + CxSegSs] 183 184 /* Restore the registers we used */ 185 mov r8, [rcx + CxR8] 186 mov r9, [rcx + CxR9] 187 188 /* Check if we go to a different cs */ 189 mov ax, cs 190 cmp [rcx + CxSegCs], ax 191 jne ReturnFar 192 193 /* Restore rax and rcx */ 194 mov rax, [rcx + CxRax] 195 mov rcx, [rcx + CxRcx] 196 197 /* Switch to the target stack */ 198 lea rsp, [rdx - 4 * 8] 199 200 /* Pop rdx from the stack */ 201 pop rdx 202 203 /* Pop Eflags from the stack */ 204 popfq 205 206 /* Return and fix up the stack */ 207 ret 8 208 209ReturnFar: 210 211 /* Put cs on the stack for the far return */ 212 mov ax, [rcx + CxSegCs] 213 mov [rdx - 1 * 8], ax 214 215 /* Load ss */ 216 mov ss, [rcx + CxSegSs] 217 218 /* Restore rax and rcx */ 219 mov rax, [rcx + CxRax] 220 mov rcx, [rcx + CxRcx] 221 222 /* Switch to the target stack */ 223 lea rsp, [rdx - 4 * 8] 224 225 /* Pop rdx from the stack */ 226 pop rdx 227 228 /* Pop Eflags from the stack */ 229 popfq 230 231 /* Return far */ 232 retf 233 234.ENDP 235 236EXTERN RtlpCheckForActiveDebugger:PROC 237EXTERN RtlDispatchException:PROC 238EXTERN ZwContinue:PROC 239EXTERN ZwRaiseException:PROC 240EXTERN RtlRaiseStatus:PROC 241 242/* 243 * VOID 244 * RtlRaiseException ( 245 * _In_ PEXCEPTION_RECORD ExceptionRecord); 246 */ 247PUBLIC RtlRaiseException 248.PROC RtlRaiseException 249 250 /* Allocate stack space for a CONTEXT record */ 251 sub rsp, CONTEXT_FRAME_LENGTH + 8 252 .allocstack CONTEXT_FRAME_LENGTH + 8 253 254 /* Save the ExceptionRecord pointer */ 255 mov [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home], rcx 256 257 .endprolog 258 259 /* Save the return address in EXCEPTION_RECORD.ExceptionAddress */ 260 mov rdx, [rsp + CONTEXT_FRAME_LENGTH + 8] 261 mov [rcx + ErExceptionAddress], rdx 262 263 /* Capture the current context */ 264 mov rcx, rsp 265 call RtlCaptureContext 266 267 /* Fix up CONTEXT.Rip for the caller (RtlCaptureContext doesn't change rdx!) */ 268 mov [rsp + CxRip], rdx 269 270 /* Fix up CONTEXT.Rsp for the caller (+8 for the return address) */ 271 lea rdx, [rsp + CONTEXT_FRAME_LENGTH + 8 + 8] 272 mov [rsp + CxRsp], rdx 273 274 /* Check if a user mode debugger is active */ 275 call RtlpCheckForActiveDebugger 276 test al, al 277 mov r8b, 1 278 jnz RaiseException 279 280 /* Dispatch the exception */ 281 mov rcx, [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home] 282 mov rdx, rsp 283 call RtlDispatchException 284 285 /* Check if it was handled */ 286 test al, al 287 mov r8b, 0 288 jz RaiseException 289 290 /* It was handled, continue with the updated context */ 291 mov rcx, rsp 292 mov dl, 0 293 call ZwContinue 294 jmp RaiseStatus 295 296RaiseException: 297 298 mov rcx, [rsp + CONTEXT_FRAME_LENGTH + 8 + P1Home] 299 mov rdx, rsp 300 call ZwRaiseException 301 302RaiseStatus: 303 304 mov rcx, rax 305 mov rdx, rsp 306 call RtlRaiseStatus 307 308 int HEX(2c) 309.ENDP 310 311 312END 313 314 315