]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/unix_signal.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / dev / ppc / unix_signal.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
27 */
28
29 #include <mach/mach_types.h>
30 #include <mach/exception_types.h>
31
32 #include <sys/param.h>
33 #include <sys/proc.h>
34 #include <sys/user.h>
35 #include <sys/ucontext.h>
36
37 #include <ppc/signal.h>
38 #include <sys/signalvar.h>
39 #include <sys/kdebug.h>
40 #include <sys/wait.h>
41 #include <kern/thread.h>
42 #include <kern/thread_act.h>
43 #include <mach/ppc/thread_status.h>
44 #define __ELF__ 0
45 #include <ppc/proc_reg.h>
46
47 #define C_REDZONE_LEN 224
48 #define C_STK_ALIGN 16
49 #define C_PARAMSAVE_LEN 64
50 #define C_LINKAGE_LEN 48
51 #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c))
52
53 /*
54 * Arrange for this process to run a signal handler
55 */
56
57 void
58 sendsig(p, catcher, sig, mask, code)
59 struct proc *p;
60 sig_t catcher;
61 int sig, mask;
62 u_long code;
63 {
64 struct mcontext mctx, *p_mctx;
65 struct ucontext uctx, *p_uctx;
66 siginfo_t sinfo, *p_sinfo;
67 struct sigacts *ps = p->p_sigacts;
68 int framesize;
69 int oonstack;
70 unsigned long sp;
71 unsigned long state_count;
72 thread_act_t th_act;
73 struct uthread *ut;
74 unsigned long paramp,linkp;
75 int infostyle = 1;
76 sig_t trampact;
77 int vec_used = 0;
78 int stack_size = 0;
79 int stack_flags = 0;
80
81 th_act = current_act();
82 ut = get_bsdthread_info(th_act);
83
84 state_count = PPC_EXCEPTION_STATE_COUNT;
85 if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count) != KERN_SUCCESS) {
86 goto bad;
87 }
88 state_count = PPC_THREAD_STATE_COUNT;
89 if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) {
90 goto bad;
91 }
92 state_count = PPC_FLOAT_STATE_COUNT;
93 if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) {
94 goto bad;
95 }
96
97 vec_save(th_act);
98 if (find_user_vec(th_act)) {
99 vec_used = 1;
100 state_count = PPC_VECTOR_STATE_COUNT;
101 if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) {
102 goto bad;
103 }
104
105 }
106
107 trampact = ps->ps_trampact[sig];
108 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
109 if (p->p_sigacts->ps_siginfo & sigmask(sig))
110 infostyle = 2;
111
112 /* figure out where our new stack lives */
113 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
114 (ps->ps_sigonstack & sigmask(sig))) {
115 sp = (unsigned long)(ps->ps_sigstk.ss_sp);
116 sp += ps->ps_sigstk.ss_size;
117 stack_size = ps->ps_sigstk.ss_size;
118 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
119 }
120 else
121 sp = mctx.ss.r1;
122
123 /* preserve RED ZONE area */
124 sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN);
125
126 /* context goes first on stack */
127 sp -= sizeof(*p_uctx);
128 p_uctx = (struct ucontext *) sp;
129
130 /* this is where siginfo goes on stack */
131 sp -= sizeof(*p_sinfo);
132 p_sinfo = (siginfo_t *) sp;
133
134 /* next are the saved registers */
135 sp -= sizeof(*p_mctx);
136 p_mctx = (struct mcontext *)sp;
137
138 /* C calling conventions, create param save and linkage
139 * areas
140 */
141
142 sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN);
143 paramp = sp;
144 sp -= C_LINKAGE_LEN;
145 linkp = sp;
146
147 uctx.uc_onstack = oonstack;
148 uctx.uc_sigmask = mask;
149 uctx.uc_stack.ss_sp = (char *)sp;
150 uctx.uc_stack.ss_size = stack_size;
151 if (oonstack)
152 uctx.uc_stack.ss_flags |= SS_ONSTACK;
153
154 uctx.uc_link = 0;
155 uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
156 if (vec_used)
157 uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int));
158 uctx.uc_mcontext = p_mctx;
159
160 /* setup siginfo */
161 bzero((caddr_t)&sinfo, sizeof(siginfo_t));
162 sinfo.si_signo = sig;
163 switch (sig) {
164 case SIGCHLD:
165 sinfo.si_pid = p->si_pid;
166 p->si_pid =0;
167 sinfo.si_status = p->si_status;
168 p->si_status = 0;
169 sinfo.si_uid = p->si_uid;
170 p->si_uid =0;
171 sinfo.si_code = p->si_code;
172 p->si_code = 0;
173 if (sinfo.si_code == CLD_EXITED) {
174 if (WIFEXITED(sinfo.si_status))
175 sinfo.si_code = CLD_EXITED;
176 else if (WIFSIGNALED(sinfo.si_status)) {
177 if (WCOREDUMP(sinfo.si_status))
178 sinfo.si_code = CLD_DUMPED;
179 else
180 sinfo.si_code = CLD_KILLED;
181 }
182 }
183 break;
184 case SIGILL:
185 sinfo.si_addr = (void *)mctx.ss.srr0;
186 if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT)))
187 sinfo.si_code = ILL_ILLOPC;
188 else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT)))
189 sinfo.si_code = ILL_PRVOPC;
190 else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT)))
191 sinfo.si_code = ILL_ILLTRP;
192 else
193 sinfo.si_code = ILL_NOOP;
194 break;
195 case SIGFPE:
196 #define FPSCR_VX 2
197 #define FPSCR_OX 3
198 #define FPSCR_UX 4
199 #define FPSCR_ZX 5
200 #define FPSCR_XX 6
201 sinfo.si_addr = (void *)mctx.ss.srr0;
202 if (mctx.fs.fpscr & (1 << (31 - FPSCR_VX)))
203 sinfo.si_code = FPE_FLTINV;
204 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_OX)))
205 sinfo.si_code = FPE_FLTOVF;
206 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_UX)))
207 sinfo.si_code = FPE_FLTUND;
208 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_ZX)))
209 sinfo.si_code = FPE_FLTDIV;
210 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_XX)))
211 sinfo.si_code = FPE_FLTRES;
212 else
213 sinfo.si_code = FPE_NOOP;
214 break;
215
216 case SIGBUS:
217 sinfo.si_addr = (void *)mctx.ss.srr0;
218 /* on ppc we generate only if EXC_PPC_UNALIGNED */
219 sinfo.si_code = BUS_ADRALN;
220 break;
221
222 case SIGSEGV:
223 sinfo.si_addr = (void *)mctx.ss.srr0;
224 /* First check in srr1 and then in dsisr */
225 if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT)))
226 sinfo.si_code = SEGV_ACCERR;
227 else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT)))
228 sinfo.si_code = SEGV_ACCERR;
229 else
230 sinfo.si_code = SEGV_MAPERR;
231 break;
232 default:
233 break;
234 }
235
236 /* copy info out to user space */
237 if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext)))
238 goto bad;
239 if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t)))
240 goto bad;
241 if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize))
242 goto bad;
243
244 /* Place our arguments in arg registers: rtm dependent */
245
246 mctx.ss.r3 = (unsigned long)catcher;
247 mctx.ss.r4 = (unsigned long)infostyle;
248 mctx.ss.r5 = (unsigned long)sig;
249 mctx.ss.r6 = (unsigned long)p_sinfo;
250 mctx.ss.r7 = (unsigned long)p_uctx;
251
252 mctx.ss.srr0 = (unsigned long)trampact;
253 mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
254 mctx.ss.r1 = sp;
255 state_count = PPC_THREAD_STATE_COUNT;
256 if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) {
257 goto bad;
258 }
259
260 return;
261
262 bad:
263 SIGACTION(p, SIGILL) = SIG_DFL;
264 sig = sigmask(SIGILL);
265 p->p_sigignore &= ~sig;
266 p->p_sigcatch &= ~sig;
267 ut->uu_sigmask &= ~sig;
268 /* sendsig is called with signal lock held */
269 psignal_lock(p, SIGILL, 0);
270 return;
271 }
272
273 /*
274 * System call to cleanup state after a signal
275 * has been taken. Reset signal mask and
276 * stack state from context left by sendsig (above).
277 * Return to previous pc and psl as specified by
278 * context left by sendsig. Check carefully to
279 * make sure that the user has not modified the
280 * psl to gain improper priviledges or to cause
281 * a machine fault.
282 */
283 struct sigreturn_args {
284 struct ucontext *uctx;
285 };
286
287 /* ARGSUSED */
288 int
289 sigreturn(p, uap, retval)
290 struct proc *p;
291 struct sigreturn_args *uap;
292 int *retval;
293 {
294 struct ucontext uctx, *p_uctx;
295 struct mcontext mctx, *p_mctx;
296 int error;
297 thread_act_t th_act;
298 struct ppc_float_state fs;
299 struct ppc_exception_state es;
300 struct sigacts *ps = p->p_sigacts;
301 sigset_t mask;
302 register sig_t action;
303 unsigned long state_count;
304 unsigned int nbits, rbits;
305 struct uthread * ut;
306 int vec_used = 0;
307
308 th_act = current_act();
309
310 ut = (struct uthread *)get_bsdthread_info(th_act);
311 if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
312 return(error);
313 }
314 if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) {
315 return(error);
316 }
317
318 if (uctx.uc_onstack & 01)
319 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
320 else
321 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
322 ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
323
324
325 if (ut->uu_siglist & ~ut->uu_sigmask)
326 signal_setast(current_act());
327
328 nbits = get_msr_nbits();
329 rbits = get_msr_rbits();
330 /* adjust the critical fields */
331 /* make sure naughty bits are off */
332 mctx.ss.srr1 &= ~(nbits);
333 /* make sure necessary bits are on */
334 mctx.ss.srr1 |= (rbits);
335
336 state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
337
338 if (uctx.uc_mcsize > state_count)
339 vec_used = 1;
340
341 state_count = PPC_THREAD_STATE_COUNT;
342 if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) {
343 return(EINVAL);
344 }
345
346 state_count = PPC_FLOAT_STATE_COUNT;
347 if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) {
348 return(EINVAL);
349 }
350
351 mask = sigmask(SIGFPE);
352 if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) {
353 action = ps->ps_sigact[SIGFPE];
354 if((action != SIG_DFL) && (action != SIG_IGN)) {
355 thread_enable_fpe(th_act, 1);
356 }
357 }
358
359 if (vec_used) {
360 state_count = PPC_VECTOR_STATE_COUNT;
361 if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) {
362 return(EINVAL);
363 }
364 }
365
366 return (EJUSTRETURN);
367 }
368
369 /*
370 * machine_exception() performs MD translation
371 * of a mach exception to a unix signal and code.
372 */
373
374 boolean_t
375 machine_exception(
376 int exception,
377 int code,
378 int subcode,
379 int *unix_signal,
380 int *unix_code
381 )
382 {
383 switch(exception) {
384
385 case EXC_BAD_INSTRUCTION:
386 *unix_signal = SIGILL;
387 *unix_code = code;
388 break;
389
390 case EXC_ARITHMETIC:
391 *unix_signal = SIGFPE;
392 *unix_code = code;
393 break;
394
395 case EXC_SOFTWARE:
396 if (code == EXC_PPC_TRAP) {
397 *unix_signal = SIGTRAP;
398 *unix_code = code;
399 break;
400 } else
401 return(FALSE);
402
403 default:
404 return(FALSE);
405 }
406
407 return(TRUE);
408 }
409