xref: /reactos/sdk/lib/rtl/amd64/except_asm.S (revision d6eebaa4)
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