2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
26 #include <mach/mach_types.h>
27 #include <mach/exception_types.h>
29 #include <sys/param.h>
32 #include <sys/ucontext.h>
34 #include <ppc/signal.h>
35 #include <sys/signalvar.h>
36 #include <sys/kdebug.h>
38 #include <kern/thread.h>
39 #include <kern/thread_act.h>
40 #include <mach/ppc/thread_status.h>
41 #include <ppc/proc_reg.h>
43 #define C_REDZONE_LEN 224
44 #define C_STK_ALIGN 16
45 #define C_PARAMSAVE_LEN 64
46 #define C_LINKAGE_LEN 48
47 #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c))
50 * The stack layout possibilities (info style); This needs to mach with signal trampoline code
54 * Traditional64with vec: 25
56 * 32bit context with vector 35
58 * 64bit context with vector 45
60 * Dual context with vector 55
67 #define UC_TRAD64_VEC 25
69 #define UC_FLAVOR_VEC 35
70 #define UC_FLAVOR64 40
71 #define UC_FLAVOR64_VEC 45
73 #define UC_DUAL_VEC 55
75 /* The following are valid mcontext sizes */
76 #define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
78 #define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
80 #define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
82 #define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
86 * Arrange for this process to run a signal handler
90 sendsig(p
, catcher
, sig
, mask
, code
)
97 struct mcontext mctx
, *p_mctx
;
98 struct mcontext64 mctx64
, *p_mctx64
;
99 struct ucontext uctx
, *p_uctx
;
100 siginfo_t sinfo
, *p_sinfo
;
101 struct sigacts
*ps
= p
->p_sigacts
;
105 unsigned long state_count
;
108 unsigned long paramp
,linkp
;
109 int infostyle
= UC_TRAD
;
118 int is_64signalregset(void);
120 th_act
= current_act();
121 ut
= get_bsdthread_info(th_act
);
124 if (p
->p_sigacts
->ps_siginfo
& sigmask(sig
)) {
125 infostyle
= UC_FLAVOR
;
127 if(is_64signalregset() && (infostyle
== UC_FLAVOR
)) {
131 if (p
->p_sigacts
->ps_64regset
& sigmask(sig
)) {
134 infostyle
= UC_FLAVOR64
;
136 if (is_64signalregset() && (infostyle
== UC_TRAD
)) {
138 infostyle
= UC_TRAD64
;
141 /* I need this for SIGINFO anyway */
142 flavor
= PPC_THREAD_STATE
;
143 tstate
= (void *)&mctx
.ss
;
144 state_count
= PPC_THREAD_STATE_COUNT
;
145 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
148 if ((ctx32
== 0) || dualcontext
) {
149 flavor
= PPC_THREAD_STATE64
;
150 tstate
= (void *)&mctx64
.ss
;
151 state_count
= PPC_THREAD_STATE64_COUNT
;
152 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
156 if ((ctx32
== 1) || dualcontext
) {
157 flavor
= PPC_EXCEPTION_STATE
;
158 tstate
= (void *)&mctx
.es
;
159 state_count
= PPC_EXCEPTION_STATE_COUNT
;
160 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
164 if ((ctx32
== 0) || dualcontext
) {
165 flavor
= PPC_EXCEPTION_STATE64
;
166 tstate
= (void *)&mctx64
.es
;
167 state_count
= PPC_EXCEPTION_STATE64_COUNT
;
169 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
175 if ((ctx32
== 1) || dualcontext
) {
176 flavor
= PPC_FLOAT_STATE
;
177 tstate
= (void *)&mctx
.fs
;
178 state_count
= PPC_FLOAT_STATE_COUNT
;
179 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
183 if ((ctx32
== 0) || dualcontext
) {
184 flavor
= PPC_FLOAT_STATE
;
185 tstate
= (void *)&mctx64
.fs
;
186 state_count
= PPC_FLOAT_STATE_COUNT
;
187 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
193 if (find_user_vec_curr()) {
196 if ((ctx32
== 1) || dualcontext
) {
197 flavor
= PPC_VECTOR_STATE
;
198 tstate
= (void *)&mctx
.vs
;
199 state_count
= PPC_VECTOR_STATE_COUNT
;
200 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
204 if ((ctx32
== 0) || dualcontext
) {
205 flavor
= PPC_VECTOR_STATE
;
206 tstate
= (void *)&mctx64
.vs
;
207 state_count
= PPC_VECTOR_STATE_COUNT
;
208 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
214 trampact
= ps
->ps_trampact
[sig
];
215 oonstack
= ps
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
217 /* figure out where our new stack lives */
218 if ((ps
->ps_flags
& SAS_ALTSTACK
) && !oonstack
&&
219 (ps
->ps_sigonstack
& sigmask(sig
))) {
220 sp
= (unsigned long)(ps
->ps_sigstk
.ss_sp
);
221 sp
+= ps
->ps_sigstk
.ss_size
;
222 stack_size
= ps
->ps_sigstk
.ss_size
;
223 ps
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
227 sp
= (unsigned int)mctx64
.ss
.r1
;
233 /* put siginfo on top */
235 /* preserve RED ZONE area */
236 sp
= TRUNC_DOWN(sp
, C_REDZONE_LEN
, C_STK_ALIGN
);
238 /* next are the saved registers */
239 if ((ctx32
== 0) || dualcontext
) {
240 sp
-= sizeof(*p_mctx64
);
241 p_mctx64
= (struct mcontext64
*)sp
;
243 if ((ctx32
== 1) || dualcontext
) {
244 sp
-= sizeof(*p_mctx
);
245 p_mctx
= (struct mcontext
*)sp
;
248 /* context goes first on stack */
249 sp
-= sizeof(*p_uctx
);
250 p_uctx
= (struct ucontext
*) sp
;
252 /* this is where siginfo goes on stack */
253 sp
-= sizeof(*p_sinfo
);
254 p_sinfo
= (siginfo_t
*) sp
;
256 /* C calling conventions, create param save and linkage
260 sp
= TRUNC_DOWN(sp
, C_PARAMSAVE_LEN
, C_STK_ALIGN
);
265 uctx
.uc_onstack
= oonstack
;
266 uctx
.uc_sigmask
= mask
;
267 uctx
.uc_stack
.ss_sp
= (char *)sp
;
268 uctx
.uc_stack
.ss_size
= stack_size
;
270 uctx
.uc_stack
.ss_flags
|= SS_ONSTACK
;
274 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE64_COUNT
+ PPC_THREAD_STATE64_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
276 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
279 uctx
.uc_mcsize
+= (size_t)(PPC_VECTOR_STATE_COUNT
* sizeof(int));
282 uctx
.uc_mcontext
= (void *)p_mctx64
;
284 uctx
.uc_mcontext
= (void *)p_mctx
;
287 bzero((caddr_t
)&sinfo
, sizeof(siginfo_t
));
288 sinfo
.si_signo
= sig
;
289 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
290 sinfo
.pad
[0] = (unsigned int)mctx
.ss
.r1
;
294 sinfo
.si_pid
= p
->si_pid
;
296 sinfo
.si_status
= p
->si_status
;
298 sinfo
.si_uid
= p
->si_uid
;
300 sinfo
.si_code
= p
->si_code
;
302 if (sinfo
.si_code
== CLD_EXITED
) {
303 if (WIFEXITED(sinfo
.si_status
))
304 sinfo
.si_code
= CLD_EXITED
;
305 else if (WIFSIGNALED(sinfo
.si_status
)) {
306 if (WCOREDUMP(sinfo
.si_status
))
307 sinfo
.si_code
= CLD_DUMPED
;
309 sinfo
.si_code
= CLD_KILLED
;
314 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
315 if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_ILL_INS_BIT
)))
316 sinfo
.si_code
= ILL_ILLOPC
;
317 else if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_PRV_INS_BIT
)))
318 sinfo
.si_code
= ILL_PRVOPC
;
319 else if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_TRAP_BIT
)))
320 sinfo
.si_code
= ILL_ILLTRP
;
322 sinfo
.si_code
= ILL_NOOP
;
330 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
331 if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_VX
)))
332 sinfo
.si_code
= FPE_FLTINV
;
333 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_OX
)))
334 sinfo
.si_code
= FPE_FLTOVF
;
335 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_UX
)))
336 sinfo
.si_code
= FPE_FLTUND
;
337 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_ZX
)))
338 sinfo
.si_code
= FPE_FLTDIV
;
339 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_XX
)))
340 sinfo
.si_code
= FPE_FLTRES
;
342 sinfo
.si_code
= FPE_NOOP
;
346 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
347 /* on ppc we generate only if EXC_PPC_UNALIGNED */
348 sinfo
.si_code
= BUS_ADRALN
;
352 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
353 /* First check in srr1 and then in dsisr */
354 if (mctx
.ss
.srr1
& (1 << (31 - DSISR_PROT_BIT
)))
355 sinfo
.si_code
= SEGV_ACCERR
;
356 else if (mctx
.es
.dsisr
& (1 << (31 - DSISR_PROT_BIT
)))
357 sinfo
.si_code
= SEGV_ACCERR
;
359 sinfo
.si_code
= SEGV_MAPERR
;
366 /* copy info out to user space */
367 if (copyout((caddr_t
)&uctx
, (caddr_t
)p_uctx
, sizeof(struct ucontext
)))
369 if (copyout((caddr_t
)&sinfo
, (caddr_t
)p_sinfo
, sizeof(siginfo_t
)))
371 if ((ctx32
== 0) || dualcontext
) {
373 if (copyout((caddr_t
)tstate
, (caddr_t
)p_mctx64
, (vec_used
? UC_FLAVOR64_VEC_SIZE
: UC_FLAVOR64_SIZE
)))
376 if ((ctx32
== 1) || dualcontext
) {
378 if (copyout((caddr_t
)tstate
, (caddr_t
)p_mctx
, uctx
.uc_mcsize
))
383 /* Place our arguments in arg registers: rtm dependent */
385 mctx
.ss
.r3
= (unsigned long)catcher
;
386 mctx
.ss
.r4
= (unsigned long)infostyle
;
387 mctx
.ss
.r5
= (unsigned long)sig
;
388 mctx
.ss
.r6
= (unsigned long)p_sinfo
;
389 mctx
.ss
.r7
= (unsigned long)p_uctx
;
391 mctx
.ss
.srr0
= (unsigned long)trampact
;
392 mctx
.ss
.srr1
= get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
394 state_count
= PPC_THREAD_STATE_COUNT
;
395 if ((kretn
= thread_setstatus(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
)) != KERN_SUCCESS
) {
396 panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn
);
401 SIGACTION(p
, SIGILL
) = SIG_DFL
;
402 sig
= sigmask(SIGILL
);
403 p
->p_sigignore
&= ~sig
;
404 p
->p_sigcatch
&= ~sig
;
405 ut
->uu_sigmask
&= ~sig
;
406 /* sendsig is called with signal lock held */
407 psignal_lock(p
, SIGILL
, 0);
412 * System call to cleanup state after a signal
413 * has been taken. Reset signal mask and
414 * stack state from context left by sendsig (above).
415 * Return to previous pc and psl as specified by
416 * context left by sendsig. Check carefully to
417 * make sure that the user has not modified the
418 * psl to gain improper priviledges or to cause
422 #define FOR64_TRANSITION 1
425 #ifdef FOR64_TRANSITION
427 struct osigreturn_args
{
428 struct ucontext
*uctx
;
433 osigreturn(p
, uap
, retval
)
435 struct osigreturn_args
*uap
;
438 struct ucontext uctx
;
439 struct ucontext
*p_uctx
;
440 struct mcontext64 mctx64
;
441 struct mcontext64
*p_64mctx
;
442 struct mcontext
*p_mctx
;
445 struct sigacts
*ps
= p
->p_sigacts
;
447 register sig_t action
;
448 unsigned long state_count
;
449 unsigned int state_flavor
;
452 void *tsptr
, *fptr
, *vptr
, *mactx
;
453 void ppc_checkthreadstate(void *, int);
455 th_act
= current_act();
456 /* lets use the larger one */
457 mactx
= (void *)&mctx64
;
459 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
460 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
464 /* validate the machine context size */
465 switch (uctx
.uc_mcsize
) {
466 case UC_FLAVOR64_VEC_SIZE
:
467 case UC_FLAVOR64_SIZE
:
468 case UC_FLAVOR_VEC_SIZE
:
475 if (error
= copyin(uctx
.uc_mcontext
, mactx
, uctx
.uc_mcsize
)) {
479 if (uctx
.uc_onstack
& 01)
480 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
482 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
484 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
485 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
486 signal_setast(current_act());
489 switch (uctx
.uc_mcsize
) {
490 case UC_FLAVOR64_VEC_SIZE
:
492 case UC_FLAVOR64_SIZE
: {
493 p_64mctx
= (struct mcontext64
*)mactx
;
494 tsptr
= (void *)&p_64mctx
->ss
;
495 fptr
= (void *)&p_64mctx
->fs
;
496 vptr
= (void *)&p_64mctx
->vs
;
497 state_flavor
= PPC_THREAD_STATE64
;
498 state_count
= PPC_THREAD_STATE64_COUNT
;
501 case UC_FLAVOR_VEC_SIZE
:
505 p_mctx
= (struct mcontext
*)mactx
;
506 tsptr
= (void *)&p_mctx
->ss
;
507 fptr
= (void *)&p_mctx
->fs
;
508 vptr
= (void *)&p_mctx
->vs
;
509 state_flavor
= PPC_THREAD_STATE
;
510 state_count
= PPC_THREAD_STATE_COUNT
;
515 /* validate the thread state, set/reset appropriate mode bits in srr1 */
516 (void)ppc_checkthreadstate(tsptr
, state_flavor
);
518 if (thread_setstatus(th_act
, state_flavor
, tsptr
, &state_count
) != KERN_SUCCESS
) {
522 state_count
= PPC_FLOAT_STATE_COUNT
;
523 if (thread_setstatus(th_act
, PPC_FLOAT_STATE
, fptr
, &state_count
) != KERN_SUCCESS
) {
527 mask
= sigmask(SIGFPE
);
528 if (((ut
->uu_sigmask
& mask
) == 0) && (p
->p_sigcatch
& mask
) && ((p
->p_sigignore
& mask
) == 0)) {
529 action
= ps
->ps_sigact
[SIGFPE
];
530 if((action
!= SIG_DFL
) && (action
!= SIG_IGN
)) {
531 thread_enable_fpe(th_act
, 1);
536 state_count
= PPC_VECTOR_STATE_COUNT
;
537 if (thread_setstatus(th_act
, PPC_VECTOR_STATE
, vptr
, &state_count
) != KERN_SUCCESS
) {
541 return (EJUSTRETURN
);
544 #endif /* FOR64_TRANSITION */
546 struct sigreturn_args
{
547 struct ucontext
*uctx
;
553 sigreturn(p
, uap
, retval
)
555 struct sigreturn_args
*uap
;
558 struct ucontext uctx
;
559 struct ucontext
*p_uctx
;
560 char mactx
[sizeof(struct mcontext64
)];
561 struct mcontext
*p_mctx
;
562 struct mcontext64
*p_64mctx
;
565 struct sigacts
*ps
= p
->p_sigacts
;
567 register sig_t action
;
568 unsigned long state_count
;
569 unsigned int state_flavor
;
572 void *tsptr
, *fptr
, *vptr
;
573 int infostyle
= uap
->infostyle
;
574 void ppc_checkthreadstate(void *, int);
576 th_act
= current_act();
578 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
579 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
583 /* validate the machine context size */
584 switch (uctx
.uc_mcsize
) {
585 case UC_FLAVOR64_VEC_SIZE
:
586 case UC_FLAVOR64_SIZE
:
587 case UC_FLAVOR_VEC_SIZE
:
593 if (error
= copyin(uctx
.uc_mcontext
, mactx
, uctx
.uc_mcsize
)) {
597 if (uctx
.uc_onstack
& 01)
598 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
600 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
602 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
603 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
604 signal_setast(current_act());
608 case UC_FLAVOR64_VEC
:
613 p_64mctx
= (struct mcontext64
*)mactx
;
614 tsptr
= (void *)&p_64mctx
->ss
;
615 fptr
= (void *)&p_64mctx
->fs
;
616 vptr
= (void *)&p_64mctx
->vs
;
617 state_flavor
= PPC_THREAD_STATE64
;
618 state_count
= PPC_THREAD_STATE64_COUNT
;
627 p_mctx
= (struct mcontext
*)mactx
;
628 tsptr
= (void *)&p_mctx
->ss
;
629 fptr
= (void *)&p_mctx
->fs
;
630 vptr
= (void *)&p_mctx
->vs
;
631 state_flavor
= PPC_THREAD_STATE
;
632 state_count
= PPC_THREAD_STATE_COUNT
;
637 /* validate the thread state, set/reset appropriate mode bits in srr1 */
638 (void)ppc_checkthreadstate(tsptr
, state_flavor
);
640 if (thread_setstatus(th_act
, state_flavor
, tsptr
, &state_count
) != KERN_SUCCESS
) {
644 state_count
= PPC_FLOAT_STATE_COUNT
;
645 if (thread_setstatus(th_act
, PPC_FLOAT_STATE
, fptr
, &state_count
) != KERN_SUCCESS
) {
649 mask
= sigmask(SIGFPE
);
650 if (((ut
->uu_sigmask
& mask
) == 0) && (p
->p_sigcatch
& mask
) && ((p
->p_sigignore
& mask
) == 0)) {
651 action
= ps
->ps_sigact
[SIGFPE
];
652 if((action
!= SIG_DFL
) && (action
!= SIG_IGN
)) {
653 thread_enable_fpe(th_act
, 1);
658 state_count
= PPC_VECTOR_STATE_COUNT
;
659 if (thread_setstatus(th_act
, PPC_VECTOR_STATE
, vptr
, &state_count
) != KERN_SUCCESS
) {
663 return (EJUSTRETURN
);
667 * machine_exception() performs MD translation
668 * of a mach exception to a unix signal and code.
682 case EXC_BAD_INSTRUCTION
:
683 *unix_signal
= SIGILL
;
688 *unix_signal
= SIGFPE
;
693 if (code
== EXC_PPC_TRAP
) {
694 *unix_signal
= SIGTRAP
;