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