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