]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/ppc/unix_signal.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / dev / ppc / unix_signal.c
CommitLineData
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) 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>
9bccf70c 35#include <sys/ucontext.h>
1c79356b
A
36
37#include <ppc/signal.h>
38#include <sys/signalvar.h>
9bccf70c
A
39#include <sys/kdebug.h>
40#include <sys/wait.h>
1c79356b
A
41#include <kern/thread.h>
42#include <kern/thread_act.h>
43#include <mach/ppc/thread_status.h>
de355530 44#define __ELF__ 0
9bccf70c 45#include <ppc/proc_reg.h>
1c79356b
A
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
1c79356b
A
57void
58sendsig(p, catcher, sig, mask, code)
59 struct proc *p;
60 sig_t catcher;
61 int sig, mask;
62 u_long code;
63{
9bccf70c
A
64 struct mcontext mctx, *p_mctx;
65 struct ucontext uctx, *p_uctx;
66 siginfo_t sinfo, *p_sinfo;
1c79356b
A
67 struct sigacts *ps = p->p_sigacts;
68 int framesize;
69 int oonstack;
70 unsigned long sp;
1c79356b 71 unsigned long state_count;
1c79356b 72 thread_act_t th_act;
9bccf70c 73 struct uthread *ut;
1c79356b 74 unsigned long paramp,linkp;
de355530 75 int infostyle = 1;
9bccf70c
A
76 sig_t trampact;
77 int vec_used = 0;
78 int stack_size = 0;
79 int stack_flags = 0;
1c79356b 80
1c79356b 81 th_act = current_act();
9bccf70c 82 ut = get_bsdthread_info(th_act);
1c79356b 83
de355530
A
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 }
1c79356b 88 state_count = PPC_THREAD_STATE_COUNT;
de355530 89 if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) {
1c79356b 90 goto bad;
de355530
A
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 }
1c79356b 96
9bccf70c
A
97 vec_save(th_act);
98 if (find_user_vec(th_act)) {
99 vec_used = 1;
de355530
A
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 }
9bccf70c
A
106
107 trampact = ps->ps_trampact[sig];
1c79356b 108 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
de355530
A
109 if (p->p_sigacts->ps_siginfo & sigmask(sig))
110 infostyle = 2;
1c79356b
A
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;
9bccf70c 117 stack_size = ps->ps_sigstk.ss_size;
1c79356b
A
118 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
119 }
de355530
A
120 else
121 sp = mctx.ss.r1;
1c79356b 122
9bccf70c 123 /* preserve RED ZONE area */
1c79356b
A
124 sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN);
125
de355530 126 /* context goes first on stack */
9bccf70c
A
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;
1c79356b 133
de355530
A
134 /* next are the saved registers */
135 sp -= sizeof(*p_mctx);
136 p_mctx = (struct mcontext *)sp;
137
9bccf70c 138 /* C calling conventions, create param save and linkage
de355530
A
139 * areas
140 */
1c79356b
A
141
142 sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN);
143 paramp = sp;
144 sp -= C_LINKAGE_LEN;
145 linkp = sp;
146
9bccf70c
A
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;
de355530 155 uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
9bccf70c
A
156 if (vec_used)
157 uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int));
de355530 158 uctx.uc_mcontext = p_mctx;
9bccf70c
A
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 }
1c79356b
A
235
236 /* copy info out to user space */
9bccf70c 237 if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext)))
1c79356b 238 goto bad;
9bccf70c 239 if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t)))
1c79356b 240 goto bad;
de355530 241 if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize))
1c79356b
A
242 goto bad;
243
244 /* Place our arguments in arg registers: rtm dependent */
245
9bccf70c
A
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;
1c79356b 251
9bccf70c
A
252 mctx.ss.srr0 = (unsigned long)trampact;
253 mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
254 mctx.ss.r1 = sp;
1c79356b 255 state_count = PPC_THREAD_STATE_COUNT;
de355530 256 if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) {
1c79356b
A
257 goto bad;
258 }
de355530 259
1c79356b
A
260 return;
261
262bad:
263 SIGACTION(p, SIGILL) = SIG_DFL;
264 sig = sigmask(SIGILL);
265 p->p_sigignore &= ~sig;
266 p->p_sigcatch &= ~sig;
9bccf70c 267 ut->uu_sigmask &= ~sig;
1c79356b 268 /* sendsig is called with signal lock held */
9bccf70c 269 psignal_lock(p, SIGILL, 0);
1c79356b
A
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 */
283struct sigreturn_args {
9bccf70c 284 struct ucontext *uctx;
1c79356b
A
285};
286
287/* ARGSUSED */
288int
289sigreturn(p, uap, retval)
290 struct proc *p;
291 struct sigreturn_args *uap;
292 int *retval;
293{
de355530
A
294 struct ucontext uctx, *p_uctx;
295 struct mcontext mctx, *p_mctx;
1c79356b 296 int error;
1c79356b 297 thread_act_t th_act;
de355530
A
298 struct ppc_float_state fs;
299 struct ppc_exception_state es;
9bccf70c
A
300 struct sigacts *ps = p->p_sigacts;
301 sigset_t mask;
302 register sig_t action;
1c79356b 303 unsigned long state_count;
de355530 304 unsigned int nbits, rbits;
9bccf70c
A
305 struct uthread * ut;
306 int vec_used = 0;
1c79356b 307
1c79356b
A
308 th_act = current_act();
309
9bccf70c
A
310 ut = (struct uthread *)get_bsdthread_info(th_act);
311 if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
1c79356b
A
312 return(error);
313 }
de355530 314 if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) {
9bccf70c
A
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;
d7e50217 322 ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
de355530
A
323
324
9bccf70c
A
325 if (ut->uu_siglist & ~ut->uu_sigmask)
326 signal_setast(current_act());
327
de355530
A
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);
1c79356b 335
de355530 336 state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
1c79356b 337
de355530
A
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) {
1c79356b
A
343 return(EINVAL);
344 }
345
346 state_count = PPC_FLOAT_STATE_COUNT;
de355530 347 if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) {
1c79356b
A
348 return(EINVAL);
349 }
9bccf70c
A
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;
de355530 361 if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) {
9bccf70c
A
362 return(EINVAL);
363 }
364 }
de355530 365
1c79356b
A
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
374boolean_t
375machine_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