xref: /reactos/sdk/lib/rtl/amd64/except_asm.S (revision 9452b29c)
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 + CxP1Home]
299    mov rdx, rsp
300    call ZwRaiseException
301
302RaiseStatus:
303
304    mov rcx, rax
305    mov rdx, rsp
306    call RtlRaiseStatus
307
308.ENDP
309
310
311END
312
313
314