]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/ppc/unix_signal.c
xnu-517.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>
9bccf70c 44#include <ppc/proc_reg.h>
1c79356b
A
45
46#define C_REDZONE_LEN 224
47#define C_STK_ALIGN 16
48#define C_PARAMSAVE_LEN 64
49#define C_LINKAGE_LEN 48
50#define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c))
51
55e303ae
A
52/*
53 * The stack layout possibilities (info style); This needs to mach with signal trampoline code
54 *
55 * Traditional: 1
56 * Traditional64: 20
57 * Traditional64with vec: 25
58 * 32bit context 30
59 * 32bit context with vector 35
60 * 64bit context 40
61 * 64bit context with vector 45
62 * Dual context 50
63 * Dual context with vector 55
64 *
65 */
66
67#define UC_TRAD 1
68#define UC_TRAD_VEC 6
69#define UC_TRAD64 20
70#define UC_TRAD64_VEC 25
71#define UC_FLAVOR 30
72#define UC_FLAVOR_VEC 35
73#define UC_FLAVOR64 40
74#define UC_FLAVOR64_VEC 45
75#define UC_DUAL 50
76#define UC_DUAL_VEC 55
77
78 /* The following are valid mcontext sizes */
79#define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
80
81#define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
82
83#define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
84
85#define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
86
87
1c79356b
A
88/*
89 * Arrange for this process to run a signal handler
90 */
91
1c79356b
A
92void
93sendsig(p, catcher, sig, mask, code)
94 struct proc *p;
95 sig_t catcher;
96 int sig, mask;
97 u_long code;
98{
55e303ae 99 kern_return_t kretn;
9bccf70c 100 struct mcontext mctx, *p_mctx;
55e303ae 101 struct mcontext64 mctx64, *p_mctx64;
9bccf70c
A
102 struct ucontext uctx, *p_uctx;
103 siginfo_t sinfo, *p_sinfo;
1c79356b
A
104 struct sigacts *ps = p->p_sigacts;
105 int framesize;
106 int oonstack;
107 unsigned long sp;
1c79356b 108 unsigned long state_count;
1c79356b 109 thread_act_t th_act;
9bccf70c 110 struct uthread *ut;
1c79356b 111 unsigned long paramp,linkp;
55e303ae
A
112 int infostyle = UC_TRAD;
113 int dualcontext =0;
9bccf70c
A
114 sig_t trampact;
115 int vec_used = 0;
116 int stack_size = 0;
117 int stack_flags = 0;
55e303ae
A
118 void * tstate;
119 int flavor;
120 int ctx32 = 1;
121 int is_64signalregset(void);
1c79356b 122
1c79356b 123 th_act = current_act();
9bccf70c 124 ut = get_bsdthread_info(th_act);
1c79356b 125
55e303ae
A
126
127 if (p->p_sigacts->ps_siginfo & sigmask(sig)) {
128 infostyle = UC_FLAVOR;
129 }
130 if(is_64signalregset() && (infostyle == UC_FLAVOR)) {
131 dualcontext = 1;
132 infostyle = UC_DUAL;
133 }
134 if (p->p_sigacts->ps_64regset & sigmask(sig)) {
135 dualcontext = 0;
136 ctx32 = 0;
137 infostyle = UC_FLAVOR64;
138 }
139 if (is_64signalregset() && (infostyle == UC_TRAD)) {
140 ctx32=0;
141 infostyle = UC_TRAD64;
142 }
143
144 /* I need this for SIGINFO anyway */
145 flavor = PPC_THREAD_STATE;
146 tstate = (void *)&mctx.ss;
1c79356b 147 state_count = PPC_THREAD_STATE_COUNT;
55e303ae 148 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
de355530 149 goto bad;
1c79356b 150
55e303ae
A
151 if ((ctx32 == 0) || dualcontext) {
152 flavor = PPC_THREAD_STATE64;
153 tstate = (void *)&mctx64.ss;
154 state_count = PPC_THREAD_STATE64_COUNT;
155 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
156 goto bad;
de355530 157 }
9bccf70c 158
55e303ae
A
159 if ((ctx32 == 1) || dualcontext) {
160 flavor = PPC_EXCEPTION_STATE;
161 tstate = (void *)&mctx.es;
162 state_count = PPC_EXCEPTION_STATE_COUNT;
163 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
164 goto bad;
165 }
166
167 if ((ctx32 == 0) || dualcontext) {
168 flavor = PPC_EXCEPTION_STATE64;
169 tstate = (void *)&mctx64.es;
170 state_count = PPC_EXCEPTION_STATE64_COUNT;
171
172 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
173 goto bad;
174
175 }
176
177
178 if ((ctx32 == 1) || dualcontext) {
179 flavor = PPC_FLOAT_STATE;
180 tstate = (void *)&mctx.fs;
181 state_count = PPC_FLOAT_STATE_COUNT;
182 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
183 goto bad;
184 }
185
186 if ((ctx32 == 0) || dualcontext) {
187 flavor = PPC_FLOAT_STATE;
188 tstate = (void *)&mctx64.fs;
189 state_count = PPC_FLOAT_STATE_COUNT;
190 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
191 goto bad;
192
193 }
194
195
196 if (find_user_vec_curr()) {
197 vec_used = 1;
198
199 if ((ctx32 == 1) || dualcontext) {
200 flavor = PPC_VECTOR_STATE;
201 tstate = (void *)&mctx.vs;
202 state_count = PPC_VECTOR_STATE_COUNT;
203 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
204 goto bad;
205 infostyle += 5;
206 }
207
208 if ((ctx32 == 0) || dualcontext) {
209 flavor = PPC_VECTOR_STATE;
210 tstate = (void *)&mctx64.vs;
211 state_count = PPC_VECTOR_STATE_COUNT;
212 if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS)
213 goto bad;
214 infostyle += 5;
215 }
216 }
217
9bccf70c 218 trampact = ps->ps_trampact[sig];
1c79356b
A
219 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
220
221 /* figure out where our new stack lives */
222 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
223 (ps->ps_sigonstack & sigmask(sig))) {
224 sp = (unsigned long)(ps->ps_sigstk.ss_sp);
225 sp += ps->ps_sigstk.ss_size;
9bccf70c 226 stack_size = ps->ps_sigstk.ss_size;
1c79356b
A
227 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
228 }
55e303ae
A
229 else {
230 if (ctx32 == 0)
231 sp = (unsigned int)mctx64.ss.r1;
232 else
233 sp = mctx.ss.r1;
234 }
1c79356b 235
55e303ae
A
236
237 /* put siginfo on top */
238
9bccf70c 239 /* preserve RED ZONE area */
1c79356b
A
240 sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN);
241
55e303ae
A
242 /* next are the saved registers */
243 if ((ctx32 == 0) || dualcontext) {
244 sp -= sizeof(*p_mctx64);
245 p_mctx64 = (struct mcontext64 *)sp;
246 }
247 if ((ctx32 == 1) || dualcontext) {
248 sp -= sizeof(*p_mctx);
249 p_mctx = (struct mcontext *)sp;
250 }
251
252 /* context goes first on stack */
9bccf70c
A
253 sp -= sizeof(*p_uctx);
254 p_uctx = (struct ucontext *) sp;
255
256 /* this is where siginfo goes on stack */
257 sp -= sizeof(*p_sinfo);
258 p_sinfo = (siginfo_t *) sp;
1c79356b 259
9bccf70c 260 /* C calling conventions, create param save and linkage
55e303ae
A
261 * areas
262 */
1c79356b
A
263
264 sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN);
265 paramp = sp;
266 sp -= C_LINKAGE_LEN;
267 linkp = sp;
268
9bccf70c
A
269 uctx.uc_onstack = oonstack;
270 uctx.uc_sigmask = mask;
271 uctx.uc_stack.ss_sp = (char *)sp;
272 uctx.uc_stack.ss_size = stack_size;
273 if (oonstack)
274 uctx.uc_stack.ss_flags |= SS_ONSTACK;
275
276 uctx.uc_link = 0;
55e303ae
A
277 if (ctx32 == 0)
278 uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE64_COUNT + PPC_THREAD_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
279 else
280 uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int));
281
9bccf70c
A
282 if (vec_used)
283 uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int));
55e303ae
A
284
285 if (ctx32 == 0)
286 uctx.uc_mcontext = (void *)p_mctx64;
287 else
288 uctx.uc_mcontext = (void *)p_mctx;
9bccf70c
A
289
290 /* setup siginfo */
291 bzero((caddr_t)&sinfo, sizeof(siginfo_t));
292 sinfo.si_signo = sig;
55e303ae
A
293 sinfo.si_addr = (void *)mctx.ss.srr0;
294 sinfo.pad[0] = (unsigned int)mctx.ss.r1;
295
9bccf70c
A
296 switch (sig) {
297 case SIGCHLD:
298 sinfo.si_pid = p->si_pid;
299 p->si_pid =0;
300 sinfo.si_status = p->si_status;
301 p->si_status = 0;
302 sinfo.si_uid = p->si_uid;
303 p->si_uid =0;
304 sinfo.si_code = p->si_code;
305 p->si_code = 0;
306 if (sinfo.si_code == CLD_EXITED) {
307 if (WIFEXITED(sinfo.si_status))
308 sinfo.si_code = CLD_EXITED;
309 else if (WIFSIGNALED(sinfo.si_status)) {
310 if (WCOREDUMP(sinfo.si_status))
311 sinfo.si_code = CLD_DUMPED;
312 else
313 sinfo.si_code = CLD_KILLED;
314 }
315 }
316 break;
317 case SIGILL:
318 sinfo.si_addr = (void *)mctx.ss.srr0;
319 if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT)))
320 sinfo.si_code = ILL_ILLOPC;
321 else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT)))
322 sinfo.si_code = ILL_PRVOPC;
323 else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT)))
324 sinfo.si_code = ILL_ILLTRP;
325 else
326 sinfo.si_code = ILL_NOOP;
327 break;
328 case SIGFPE:
329#define FPSCR_VX 2
330#define FPSCR_OX 3
331#define FPSCR_UX 4
332#define FPSCR_ZX 5
333#define FPSCR_XX 6
334 sinfo.si_addr = (void *)mctx.ss.srr0;
335 if (mctx.fs.fpscr & (1 << (31 - FPSCR_VX)))
336 sinfo.si_code = FPE_FLTINV;
337 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_OX)))
338 sinfo.si_code = FPE_FLTOVF;
339 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_UX)))
340 sinfo.si_code = FPE_FLTUND;
341 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_ZX)))
342 sinfo.si_code = FPE_FLTDIV;
343 else if (mctx.fs.fpscr & (1 << (31 - FPSCR_XX)))
344 sinfo.si_code = FPE_FLTRES;
345 else
346 sinfo.si_code = FPE_NOOP;
347 break;
348
349 case SIGBUS:
350 sinfo.si_addr = (void *)mctx.ss.srr0;
351 /* on ppc we generate only if EXC_PPC_UNALIGNED */
352 sinfo.si_code = BUS_ADRALN;
353 break;
354
355 case SIGSEGV:
356 sinfo.si_addr = (void *)mctx.ss.srr0;
357 /* First check in srr1 and then in dsisr */
358 if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT)))
359 sinfo.si_code = SEGV_ACCERR;
360 else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT)))
361 sinfo.si_code = SEGV_ACCERR;
362 else
363 sinfo.si_code = SEGV_MAPERR;
364 break;
365 default:
366 break;
367 }
1c79356b 368
55e303ae 369
1c79356b 370 /* copy info out to user space */
9bccf70c 371 if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext)))
1c79356b 372 goto bad;
9bccf70c 373 if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t)))
1c79356b 374 goto bad;
55e303ae
A
375 if ((ctx32 == 0) || dualcontext) {
376 tstate = &mctx64;
377 if (copyout((caddr_t)tstate, (caddr_t)p_mctx64, uctx.uc_mcsize))
378 goto bad;
379 }
380 if ((ctx32 == 1) || dualcontext) {
381 tstate = &mctx;
382 if (copyout((caddr_t)tstate, (caddr_t)p_mctx, uctx.uc_mcsize))
1c79356b 383 goto bad;
55e303ae
A
384 }
385
1c79356b
A
386
387 /* Place our arguments in arg registers: rtm dependent */
388
9bccf70c
A
389 mctx.ss.r3 = (unsigned long)catcher;
390 mctx.ss.r4 = (unsigned long)infostyle;
391 mctx.ss.r5 = (unsigned long)sig;
392 mctx.ss.r6 = (unsigned long)p_sinfo;
393 mctx.ss.r7 = (unsigned long)p_uctx;
1c79356b 394
9bccf70c
A
395 mctx.ss.srr0 = (unsigned long)trampact;
396 mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
397 mctx.ss.r1 = sp;
1c79356b 398 state_count = PPC_THREAD_STATE_COUNT;
55e303ae
A
399 if ((kretn = thread_setstatus(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)) != KERN_SUCCESS) {
400 panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn);
1c79356b 401 }
1c79356b
A
402 return;
403
404bad:
405 SIGACTION(p, SIGILL) = SIG_DFL;
406 sig = sigmask(SIGILL);
407 p->p_sigignore &= ~sig;
408 p->p_sigcatch &= ~sig;
9bccf70c 409 ut->uu_sigmask &= ~sig;
1c79356b 410 /* sendsig is called with signal lock held */
9bccf70c 411 psignal_lock(p, SIGILL, 0);
1c79356b
A
412 return;
413}
414
415/*
416 * System call to cleanup state after a signal
417 * has been taken. Reset signal mask and
418 * stack state from context left by sendsig (above).
419 * Return to previous pc and psl as specified by
420 * context left by sendsig. Check carefully to
421 * make sure that the user has not modified the
422 * psl to gain improper priviledges or to cause
423 * a machine fault.
424 */
55e303ae
A
425
426#define FOR64_TRANSITION 1
427
428
429#ifdef FOR64_TRANSITION
430
431struct osigreturn_args {
432 struct ucontext *uctx;
433};
434
435/* ARGSUSED */
436int
437osigreturn(p, uap, retval)
438 struct proc *p;
439 struct osigreturn_args *uap;
440 int *retval;
441{
442 struct ucontext uctx;
443 struct ucontext *p_uctx;
444 struct mcontext64 mctx64;
445 struct mcontext64 *p_64mctx;
446 struct mcontext *p_mctx;
447 int error;
448 thread_act_t th_act;
449 struct sigacts *ps = p->p_sigacts;
450 sigset_t mask;
451 register sig_t action;
452 unsigned long state_count;
453 unsigned int state_flavor;
454 struct uthread * ut;
455 int vec_used = 0;
456 void *tsptr, *fptr, *vptr, *mactx;
457 void ppc_checkthreadstate(void *, int);
458
459 th_act = current_act();
460 /* lets use the larger one */
461 mactx = (void *)&mctx64;
462
463 ut = (struct uthread *)get_bsdthread_info(th_act);
464 if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
465 return(error);
466 }
467 if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) {
468 return(error);
469 }
470
471 if (uctx.uc_onstack & 01)
472 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
473 else
474 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
475
476 ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
477 if (ut->uu_siglist & ~ut->uu_sigmask)
478 signal_setast(current_act());
479
480 vec_used = 0;
481 switch (uctx.uc_mcsize) {
482 case UC_FLAVOR64_VEC_SIZE :
483 vec_used = 1;
484 case UC_FLAVOR64_SIZE : {
485 p_64mctx = (struct mcontext64 *)mactx;
486 tsptr = (void *)&p_64mctx->ss;
487 fptr = (void *)&p_64mctx->fs;
488 vptr = (void *)&p_64mctx->vs;
489 state_flavor = PPC_THREAD_STATE64;
490 state_count = PPC_THREAD_STATE64_COUNT;
491 }
492 break;
493 case UC_FLAVOR_VEC_SIZE :
494 vec_used = 1;
495 case UC_FLAVOR_SIZE:
496 default: {
497 p_mctx = (struct mcontext *)mactx;
498 tsptr = (void *)&p_mctx->ss;
499 fptr = (void *)&p_mctx->fs;
500 vptr = (void *)&p_mctx->vs;
501 state_flavor = PPC_THREAD_STATE;
502 state_count = PPC_THREAD_STATE_COUNT;
503 }
504 break;
505 } /* switch () */
506
507 /* validate the thread state, set/reset appropriate mode bits in srr1 */
508 (void)ppc_checkthreadstate(tsptr, state_flavor);
509
510 if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) {
511 return(EINVAL);
512 }
513
514 state_count = PPC_FLOAT_STATE_COUNT;
515 if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) {
516 return(EINVAL);
517 }
518
519 mask = sigmask(SIGFPE);
520 if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) {
521 action = ps->ps_sigact[SIGFPE];
522 if((action != SIG_DFL) && (action != SIG_IGN)) {
523 thread_enable_fpe(th_act, 1);
524 }
525 }
526
527 if (vec_used) {
528 state_count = PPC_VECTOR_STATE_COUNT;
529 if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) {
530 return(EINVAL);
531 }
532 }
533 return (EJUSTRETURN);
534}
535
536#endif /* FOR64_TRANSITION */
537
1c79356b 538struct sigreturn_args {
9bccf70c 539 struct ucontext *uctx;
55e303ae 540 int infostyle;
1c79356b
A
541};
542
543/* ARGSUSED */
544int
545sigreturn(p, uap, retval)
546 struct proc *p;
547 struct sigreturn_args *uap;
548 int *retval;
549{
55e303ae
A
550 struct ucontext uctx;
551 struct ucontext *p_uctx;
552 char mactx[sizeof(struct mcontext64)];
553 struct mcontext *p_mctx;
554 struct mcontext64 *p_64mctx;
1c79356b 555 int error;
1c79356b 556 thread_act_t th_act;
9bccf70c
A
557 struct sigacts *ps = p->p_sigacts;
558 sigset_t mask;
559 register sig_t action;
1c79356b 560 unsigned long state_count;
55e303ae 561 unsigned int state_flavor;
9bccf70c
A
562 struct uthread * ut;
563 int vec_used = 0;
55e303ae
A
564 void *tsptr, *fptr, *vptr;
565 int infostyle = uap->infostyle;
566 void ppc_checkthreadstate(void *, int);
1c79356b 567
1c79356b
A
568 th_act = current_act();
569
9bccf70c
A
570 ut = (struct uthread *)get_bsdthread_info(th_act);
571 if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) {
1c79356b
A
572 return(error);
573 }
55e303ae
A
574
575
576 if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) {
9bccf70c
A
577 return(error);
578 }
579
580 if (uctx.uc_onstack & 01)
581 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
582 else
583 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
de355530 584
55e303ae 585 ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask;
9bccf70c
A
586 if (ut->uu_siglist & ~ut->uu_sigmask)
587 signal_setast(current_act());
588
55e303ae
A
589 vec_used = 0;
590 switch (infostyle) {
591 case UC_FLAVOR64_VEC:
592 case UC_TRAD64_VEC:
593 vec_used = 1;
594 case UC_TRAD64:
595 case UC_FLAVOR64: {
596 p_64mctx = (struct mcontext64 *)mactx;
597 tsptr = (void *)&p_64mctx->ss;
598 fptr = (void *)&p_64mctx->fs;
599 vptr = (void *)&p_64mctx->vs;
600 state_flavor = PPC_THREAD_STATE64;
601 state_count = PPC_THREAD_STATE64_COUNT;
602 }
603 break;
604 case UC_FLAVOR_VEC :
605 case UC_TRAD_VEC :
606 vec_used = 1;
607 case UC_FLAVOR :
608 case UC_TRAD :
609 default: {
610 p_mctx = (struct mcontext *)mactx;
611 tsptr = (void *)&p_mctx->ss;
612 fptr = (void *)&p_mctx->fs;
613 vptr = (void *)&p_mctx->vs;
614 state_flavor = PPC_THREAD_STATE;
615 state_count = PPC_THREAD_STATE_COUNT;
616 }
617 break;
618 } /* switch () */
1c79356b 619
55e303ae
A
620 /* validate the thread state, set/reset appropriate mode bits in srr1 */
621 (void)ppc_checkthreadstate(tsptr, state_flavor);
1c79356b 622
55e303ae 623 if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) {
1c79356b
A
624 return(EINVAL);
625 }
626
627 state_count = PPC_FLOAT_STATE_COUNT;
55e303ae 628 if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) {
1c79356b
A
629 return(EINVAL);
630 }
9bccf70c
A
631
632 mask = sigmask(SIGFPE);
633 if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) {
634 action = ps->ps_sigact[SIGFPE];
635 if((action != SIG_DFL) && (action != SIG_IGN)) {
636 thread_enable_fpe(th_act, 1);
637 }
638 }
639
640 if (vec_used) {
641 state_count = PPC_VECTOR_STATE_COUNT;
55e303ae 642 if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) {
9bccf70c
A
643 return(EINVAL);
644 }
645 }
1c79356b
A
646 return (EJUSTRETURN);
647}
648
649/*
650 * machine_exception() performs MD translation
651 * of a mach exception to a unix signal and code.
652 */
653
654boolean_t
655machine_exception(
656 int exception,
657 int code,
658 int subcode,
659 int *unix_signal,
660 int *unix_code
661)
662{
663 switch(exception) {
664
665 case EXC_BAD_INSTRUCTION:
666 *unix_signal = SIGILL;
667 *unix_code = code;
668 break;
669
670 case EXC_ARITHMETIC:
671 *unix_signal = SIGFPE;
672 *unix_code = code;
673 break;
674
675 case EXC_SOFTWARE:
676 if (code == EXC_PPC_TRAP) {
677 *unix_signal = SIGTRAP;
678 *unix_code = code;
679 break;
680 } else
681 return(FALSE);
682
683 default:
684 return(FALSE);
685 }
686
687 return(TRUE);
688}
689