]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * Copyright (c) 1992 NeXT, Inc. | |
27 | * | |
28 | * HISTORY | |
29 | * 13 May 1992 ? at NeXT | |
30 | * Created. | |
31 | */ | |
32 | ||
33 | #include <mach/mach_types.h> | |
34 | #include <mach/exception.h> | |
35 | ||
36 | #include <kern/thread.h> | |
37 | #include <kern/thread_act.h> | |
38 | ||
39 | #include <sys/param.h> | |
40 | #include <sys/proc.h> | |
41 | #include <sys/user.h> | |
42 | ||
43 | #include <i386/psl.h> | |
44 | ||
45 | #include <mach/i386/thread_status.h> | |
46 | #include <dev/i386/sel_inline.h> | |
47 | ||
48 | ||
49 | /* | |
50 | * FIXME.. should be included from mach_kernel/i386/seg.h | |
51 | */ | |
52 | ||
53 | #define USER_CS 0x17 | |
54 | #define USER_DS 0x1f | |
55 | ||
56 | #define UDATA_SEL USER_DS | |
57 | #define UCODE_SEL USER_CS | |
58 | ||
59 | #define valid_user_code_selector(x) (TRUE) | |
60 | #define valid_user_data_selector(x) (TRUE) | |
61 | #define valid_user_stack_selector(x) (TRUE) | |
62 | ||
63 | ||
64 | #define NULL_SEG 0 | |
65 | ||
66 | /* | |
67 | * Send an interrupt to process. | |
68 | * | |
69 | * Stack is set up to allow sigcode stored | |
70 | * in u. to call routine, followed by chmk | |
71 | * to sigreturn routine below. After sigreturn | |
72 | * resets the signal mask, the stack, the frame | |
73 | * pointer, and the argument pointer, it returns | |
74 | * to the user specified pc, psl. | |
75 | */ | |
76 | ||
77 | void | |
78 | sendsig(p, catcher, sig, mask, code) | |
79 | struct proc *p; | |
80 | sig_t catcher; | |
81 | int sig, mask; | |
82 | u_long code; | |
83 | { | |
9bccf70c A |
84 | struct sigframe { |
85 | int retaddr; | |
86 | sig_t catcher; | |
87 | int sigstyle; | |
88 | int sig; | |
89 | int code; | |
90 | struct sigcontext * scp; | |
91 | } frame, *fp; | |
92 | struct sigcontext context, *scp; | |
1c79356b | 93 | struct sigacts *ps = p->p_sigacts; |
9bccf70c A |
94 | int oonstack; |
95 | thread_t thread = current_thread(); | |
96 | thread_act_t th_act = current_act(); | |
97 | struct uthread * ut; | |
98 | struct i386_saved_state * saved_state = get_user_regs(th_act); | |
99 | sig_t trampact; | |
1c79356b | 100 | |
9bccf70c | 101 | ut = get_bsdthread_info(th_act); |
1c79356b | 102 | oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; |
9bccf70c | 103 | if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && |
1c79356b | 104 | (ps->ps_sigonstack & sigmask(sig))) { |
9bccf70c | 105 | scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1; |
1c79356b | 106 | ps->ps_sigstk.ss_flags |= SA_ONSTACK; |
9bccf70c A |
107 | } else |
108 | scp = ((struct sigcontext *)saved_state->uesp) - 1; | |
109 | fp = ((struct sigframe *)scp) - 1; | |
1c79356b | 110 | |
9bccf70c A |
111 | /* |
112 | * Build the argument list for the signal handler. | |
113 | */ | |
1c79356b | 114 | |
9bccf70c A |
115 | trampact = ps->ps_trampact[sig]; |
116 | /* Handler should call sigreturn to get out of it */ | |
117 | frame.retaddr = 0xffffffff; | |
118 | frame.catcher = catcher; | |
de355530 | 119 | frame.sigstyle = 1; |
9bccf70c | 120 | frame.sig = sig; |
1c79356b | 121 | |
9bccf70c A |
122 | if (sig == SIGILL || sig == SIGFPE) { |
123 | frame.code = code; | |
124 | } else | |
125 | frame.code = 0; | |
126 | frame.scp = scp; | |
127 | if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame))) | |
128 | goto bad; | |
1c79356b A |
129 | |
130 | #if PC_SUPPORT | |
9bccf70c | 131 | { |
1c79356b A |
132 | PCcontext_t context = threadPCContext(thread); |
133 | ||
134 | if (context && context->running) { | |
9bccf70c A |
135 | oonstack |= 02; |
136 | context->running = FALSE; | |
137 | } | |
1c79356b | 138 | } |
1c79356b | 139 | #endif |
9bccf70c A |
140 | /* |
141 | * Build the signal context to be used by sigreturn. | |
142 | */ | |
143 | context.sc_onstack = oonstack; | |
144 | context.sc_mask = mask; | |
145 | context.sc_eax = saved_state->eax; | |
146 | context.sc_ebx = saved_state->ebx; | |
147 | context.sc_ecx = saved_state->ecx; | |
148 | context.sc_edx = saved_state->edx; | |
149 | context.sc_edi = saved_state->edi; | |
150 | context.sc_esi = saved_state->esi; | |
151 | context.sc_ebp = saved_state->ebp; | |
152 | context.sc_esp = saved_state->uesp; | |
153 | context.sc_ss = saved_state->ss; | |
154 | context.sc_eflags = saved_state->efl; | |
155 | context.sc_eip = saved_state->eip; | |
156 | context.sc_cs = saved_state->cs; | |
157 | if (saved_state->efl & EFL_VM) { | |
158 | context.sc_ds = saved_state->v86_segs.v86_ds; | |
159 | context.sc_es = saved_state->v86_segs.v86_es; | |
160 | context.sc_fs = saved_state->v86_segs.v86_fs; | |
161 | context.sc_gs = saved_state->v86_segs.v86_gs; | |
162 | ||
163 | saved_state->efl &= ~EFL_VM; | |
164 | } else { | |
165 | context.sc_ds = saved_state->ds; | |
166 | context.sc_es = saved_state->es; | |
167 | context.sc_fs = saved_state->fs; | |
168 | context.sc_gs = saved_state->gs; | |
169 | } | |
170 | if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context))) | |
171 | goto bad; | |
172 | ||
173 | saved_state->eip = (unsigned int)trampact; | |
174 | saved_state->cs = UCODE_SEL; | |
175 | ||
176 | saved_state->uesp = (unsigned int)fp; | |
177 | saved_state->ss = UDATA_SEL; | |
178 | ||
179 | saved_state->ds = UDATA_SEL; | |
180 | saved_state->es = UDATA_SEL; | |
181 | saved_state->fs = NULL_SEG; | |
182 | saved_state->gs = NULL_SEG; | |
183 | return; | |
1c79356b A |
184 | |
185 | bad: | |
186 | SIGACTION(p, SIGILL) = SIG_DFL; | |
187 | sig = sigmask(SIGILL); | |
188 | p->p_sigignore &= ~sig; | |
189 | p->p_sigcatch &= ~sig; | |
9bccf70c | 190 | ut->uu_sigmask &= ~sig; |
1c79356b | 191 | /* sendsig is called with signal lock held */ |
9bccf70c | 192 | psignal_lock(p, SIGILL, 0); |
1c79356b A |
193 | return; |
194 | } | |
195 | ||
196 | /* | |
197 | * System call to cleanup state after a signal | |
198 | * has been taken. Reset signal mask and | |
199 | * stack state from context left by sendsig (above). | |
200 | * Return to previous pc and psl as specified by | |
201 | * context left by sendsig. Check carefully to | |
202 | * make sure that the user has not modified the | |
203 | * psl to gain improper priviledges or to cause | |
204 | * a machine fault. | |
205 | */ | |
206 | struct sigreturn_args { | |
207 | struct sigcontext *sigcntxp; | |
208 | }; | |
209 | /* ARGSUSED */ | |
210 | int | |
211 | sigreturn(p, uap, retval) | |
212 | struct proc *p; | |
213 | struct sigreturn_args *uap; | |
214 | int *retval; | |
215 | { | |
216 | struct sigcontext context; | |
217 | thread_t thread = current_thread(); | |
218 | thread_act_t th_act = current_act(); | |
219 | int error; | |
220 | struct i386_saved_state* saved_state = get_user_regs(th_act); | |
9bccf70c A |
221 | struct uthread * ut; |
222 | ||
223 | ||
1c79356b A |
224 | |
225 | if (saved_state == NULL) | |
226 | return EINVAL; | |
227 | ||
228 | if (error = copyin((caddr_t)uap->sigcntxp, (caddr_t)&context, | |
229 | sizeof (context))) | |
230 | return(error); | |
9bccf70c | 231 | ut = (struct uthread *)get_bsdthread_info(th_act); |
1c79356b A |
232 | |
233 | if (context.sc_onstack & 01) | |
234 | p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; | |
235 | else | |
236 | p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; | |
9bccf70c A |
237 | ut->uu_sigmask = context.sc_mask &~ sigcantmask; |
238 | if(ut->uu_siglist & ~ut->uu_sigmask) | |
239 | signal_setast(current_act()); | |
1c79356b A |
240 | saved_state->eax = context.sc_eax; |
241 | saved_state->ebx = context.sc_ebx; | |
242 | saved_state->ecx = context.sc_ecx; | |
243 | saved_state->edx = context.sc_edx; | |
244 | saved_state->edi = context.sc_edi; | |
245 | saved_state->esi = context.sc_esi; | |
246 | saved_state->ebp = context.sc_ebp; | |
247 | saved_state->uesp = context.sc_esp; | |
248 | saved_state->ss = context.sc_ss; | |
249 | saved_state->efl = context.sc_eflags; | |
250 | saved_state->efl &= ~EFL_USERCLR; | |
251 | saved_state->efl |= EFL_USERSET; | |
252 | saved_state->eip = context.sc_eip; | |
253 | saved_state->cs = context.sc_cs; | |
254 | ||
255 | if (context.sc_eflags & EFL_VM) { | |
256 | saved_state->ds = NULL_SEG; | |
257 | saved_state->es = NULL_SEG; | |
258 | saved_state->fs = NULL_SEG; | |
259 | saved_state->gs = NULL_SEG; | |
260 | saved_state->v86_segs.v86_ds = context.sc_ds; | |
261 | saved_state->v86_segs.v86_es = context.sc_es; | |
262 | saved_state->v86_segs.v86_fs = context.sc_fs; | |
263 | saved_state->v86_segs.v86_gs = context.sc_gs; | |
264 | ||
265 | saved_state->efl |= EFL_VM; | |
266 | } | |
267 | else { | |
268 | saved_state->ds = context.sc_ds; | |
269 | saved_state->es = context.sc_es; | |
270 | saved_state->fs = context.sc_fs; | |
271 | saved_state->gs = context.sc_gs; | |
272 | } | |
273 | ||
274 | #if PC_SUPPORT | |
275 | if (context.sc_onstack & 02) { | |
276 | PCcontext_t context = threadPCContext(thread); | |
277 | ||
278 | if (context) | |
279 | context->running = TRUE; | |
280 | } | |
281 | #endif | |
282 | ||
283 | return (EJUSTRETURN); | |
284 | } | |
285 | ||
286 | /* | |
287 | * machine_exception() performs MD translation | |
288 | * of a mach exception to a unix signal and code. | |
289 | */ | |
290 | ||
291 | boolean_t | |
292 | machine_exception( | |
293 | int exception, | |
294 | int code, | |
295 | int subcode, | |
296 | int *unix_signal, | |
297 | int *unix_code | |
298 | ) | |
299 | { | |
300 | ||
301 | switch(exception) { | |
302 | ||
303 | case EXC_BAD_INSTRUCTION: | |
304 | *unix_signal = SIGILL; | |
305 | *unix_code = code; | |
306 | break; | |
307 | ||
308 | case EXC_ARITHMETIC: | |
309 | *unix_signal = SIGFPE; | |
310 | *unix_code = code; | |
311 | break; | |
312 | ||
313 | default: | |
314 | return(FALSE); | |
315 | } | |
316 | ||
317 | return(TRUE); | |
318 | } |