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