Fix RtlpGetStackLimits to get the right limits if called in kernel-mode (separated...
[reactos.git] / reactos / lib / rtl / i386 / except.s
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NT Library
4 * FILE: lib/rtl/i386/except.S
5 * PURPOSE: User-mode exception support for IA-32
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Casper S. Hornstrup (chorns@users.sourceforge.net)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ndk/asm.h>
13 #include <ndk/i386/segment.h>
14 .intel_syntax noprefix
15
16 #define EXCEPTION_UNWINDING 2
17 #define EXCEPTION_EXIT_UNWIND 4
18 #define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND)
19
20 #define ExceptionContinueExecution 0
21 #define ExceptionContinueSearch 1
22 #define ExceptionNestedException 2
23 #define ExceptionCollidedUnwind 3
24
25 /* FUNCTIONS ****************************************************************/
26
27 .globl _RtlpGetExceptionList@0
28 _RtlpGetExceptionList@0:
29
30 /* Return the exception list */
31 mov eax, [fs:TEB_EXCEPTION_LIST]
32 ret
33
34 .globl _RtlpSetExceptionList@4
35 _RtlpSetExceptionList@4:
36
37 /* Get the new list */
38 mov ecx, [esp+4]
39 mov ecx, [ecx]
40
41 /* Write it */
42 mov [fs:TEB_EXCEPTION_LIST], ecx
43
44 /* Return */
45 ret 4
46
47 .globl _RtlpGetExceptionAddress@0
48 _RtlpGetExceptionAddress@0:
49
50 /* Return the address from the stack */
51 mov eax, [ebp+4]
52
53 /* Return */
54 ret
55
56 .globl _RtlCaptureContext@4
57 _RtlCaptureContext@4:
58
59 /* Preserve EBX and put the context in it */
60 push ebx
61 mov ebx, [esp+8]
62
63 /* Save the basic register context */
64 mov [ebx+CONTEXT_EAX], eax
65 mov [ebx+CONTEXT_ECX], ecx
66 mov [ebx+CONTEXT_EDX], edx
67 mov eax, [esp] /* We pushed EBX, remember? ;) */
68 mov [ebx+CONTEXT_EBX], eax
69 mov [ebx+CONTEXT_ESI], esi
70 mov [ebx+CONTEXT_EDI], edi
71
72 /* Capture the other regs */
73 jmp CaptureRest
74
75 .globl _RtlpCaptureContext@4
76 _RtlpCaptureContext@4:
77
78 /* Preserve EBX and put the context in it */
79 push ebx
80 mov ebx, [esp+8]
81
82 /* Clear the basic register context */
83 mov dword ptr [ebx+CONTEXT_EAX], 0
84 mov dword ptr [ebx+CONTEXT_ECX], 0
85 mov dword ptr [ebx+CONTEXT_EDX], 0
86 mov dword ptr [ebx+CONTEXT_EBX], 0
87 mov dword ptr [ebx+CONTEXT_ESI], 0
88 mov dword ptr [ebx+CONTEXT_EDI], 0
89
90 CaptureRest:
91 /* Capture the segment registers */
92 mov [ebx+CONTEXT_SEGCS], cs
93 mov [ebx+CONTEXT_SEGDS], ds
94 mov [ebx+CONTEXT_SEGES], es
95 mov [ebx+CONTEXT_SEGFS], fs
96 mov [ebx+CONTEXT_SEGGS], gs
97 mov [ebx+CONTEXT_SEGSS], ss
98
99 /* Capture flags */
100 pushfd
101 pop [ebx+CONTEXT_EFLAGS]
102
103 /* The return address should be in [ebp+4] */
104 mov eax, [ebp+4]
105 mov [ebx+CONTEXT_EIP], eax
106
107 /* Get EBP */
108 mov eax, [esp]
109 mov [ebx+CONTEXT_EBP], eax
110
111 /* And get ESP */
112 mov eax, [ebp+8]
113 mov [ebx+CONTEXT_ESP], eax
114
115 /* Return to the caller */
116 pop ebx
117 ret 4
118
119 .globl _RtlpExecuteHandlerForException@20
120 _RtlpExecuteHandlerForException@20:
121
122 /* Copy the routine in EDX */
123 mov edx, offset _RtlpExceptionProtector
124
125 /* Jump to common routine */
126 jmp _RtlpExecuteHandler@20
127
128 .globl _RtlpExecuteHandlerForUnwind@20
129 _RtlpExecuteHandlerForUnwind@20:
130
131 /* Copy the routine in EDX */
132 mov edx, offset _RtlpExceptionProtector
133
134 /* Run the common routine */
135 _RtlpExecuteHandler@20:
136
137 /* Save non-volatile */
138 push ebx
139 push esi
140 push edi
141
142 /* Clear registers */
143 xor eax, eax
144 xor ebx, ebx
145 xor esi, esi
146 xor edi, edi
147
148 /* Call the 2nd-stage executer */
149 push [esp+0x20]
150 push [esp+0x20]
151 push [esp+0x20]
152 push [esp+0x20]
153 push [esp+0x20]
154 call _RtlpExecuteHandler2@20
155
156 /* Restore non-volatile */
157 pop edi
158 pop esi
159 pop ebx
160 ret 0x14
161
162 .globl _RtlpExecuteHandler2@20
163 _RtlpExecuteHandler2@20:
164
165 /* Set up stack frame */
166 push ebp
167 mov ebp, esp
168
169 /* Save the Frame */
170 push [ebp+0xC]
171
172 /* Push handler address */
173 push edx
174
175 /* Push the exception list */
176 push [fs:TEB_EXCEPTION_LIST]
177
178 /* Link us to it */
179 mov [fs:TEB_EXCEPTION_LIST], esp
180
181 /* Call the handler */
182 push [ebp+0x14]
183 push [ebp+0x10]
184 push [ebp+0xC]
185 push [ebp+8]
186 mov ecx, [ebp+0x18]
187 call ecx
188
189 /* Unlink us */
190 mov esp, [fs:TEB_EXCEPTION_LIST]
191
192 /* Restore it */
193 pop [fs:TEB_EXCEPTION_LIST]
194
195 /* Undo stack frame and return */
196 mov esp, ebp
197 pop ebp
198 ret 0x14
199
200 _RtlpExceptionProtector:
201
202 /* Assume we'll continue */
203 mov eax, ExceptionContinueSearch
204
205 /* Put the exception record in ECX and check the Flags */
206 mov ecx, [esp+4]
207 test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWIND
208 jnz return
209
210 /* Save the frame in ECX and Context in EDX */
211 mov ecx, [esp+8]
212 mov edx, [esp+16]
213
214 /* Get the nested frame */
215 mov eax, [ecx+8]
216
217 /* Set it as the dispatcher context */
218 mov [edx], eax
219
220 /* Return nested exception */
221 mov eax, ExceptionNestedException
222
223 return:
224 ret 16
225
226 _RtlpUnwindProtector:
227 /* Assume we'll continue */
228 mov eax, ExceptionContinueSearch
229
230 /* Put the exception record in ECX and check the Flags */
231 mov ecx, [esp+4]
232 test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWIND
233 jnz .return
234
235 /* Save the frame in ECX and Context in EDX */
236 mov ecx, [esp+8]
237 mov edx, [esp+16]
238
239 /* Get the nested frame */
240 mov eax, [ecx+8]
241
242 /* Set it as the dispatcher context */
243 mov [edx], eax
244
245 /* Return collided unwind */
246 mov eax, ExceptionCollidedUnwind
247
248 .return:
249 ret 16
250