2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
29 #include <mach/mach_types.h>
30 #include <mach/exception_types.h>
32 #include <sys/param.h>
35 #include <sys/ucontext.h>
37 #include <ppc/signal.h>
38 #include <sys/signalvar.h>
39 #include <sys/kdebug.h>
41 #include <kern/thread.h>
42 #include <kern/thread_act.h>
43 #include <mach/ppc/thread_status.h>
44 #include <ppc/proc_reg.h>
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))
53 * The stack layout possibilities (info style); This needs to mach with signal trampoline code
57 * Traditional64with vec: 25
59 * 32bit context with vector 35
61 * 64bit context with vector 45
63 * Dual context with vector 55
69 #define UC_TRAD64_VEC 25
71 #define UC_FLAVOR_VEC 35
72 #define UC_FLAVOR64 40
73 #define UC_FLAVOR64_VEC 45
75 #define UC_DUAL_VEC 55
77 /* The following are valid mcontext sizes */
78 #define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
80 #define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
82 #define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int))
84 #define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int))
88 * Arrange for this process to run a signal handler
92 sendsig(p
, catcher
, sig
, mask
, code
)
98 struct mcontext mctx
, *p_mctx
;
99 struct mcontext64 mctx64
, *p_mctx64
;
100 struct ucontext uctx
, *p_uctx
;
101 siginfo_t sinfo
, *p_sinfo
;
102 struct sigacts
*ps
= p
->p_sigacts
;
106 unsigned long state_count
;
109 unsigned long paramp
,linkp
;
110 int infostyle
= UC_TRAD
;
119 int is_64signalregset(void);
121 th_act
= current_act();
122 ut
= get_bsdthread_info(th_act
);
125 if (p
->p_sigacts
->ps_siginfo
& sigmask(sig
)) {
126 infostyle
= UC_FLAVOR
;
128 if(is_64signalregset() && (infostyle
== UC_FLAVOR
)) {
132 if (p
->p_sigacts
->ps_64regset
& sigmask(sig
)) {
135 infostyle
= UC_FLAVOR64
;
137 if (is_64signalregset() && (infostyle
== UC_TRAD
)) {
139 infostyle
= UC_TRAD64
;
142 /* I need this for SIGINFO anyway */
143 flavor
= PPC_THREAD_STATE
;
144 tstate
= (void *)&mctx
.ss
;
145 state_count
= PPC_THREAD_STATE_COUNT
;
146 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
149 if ((ctx32
== 0) || dualcontext
) {
150 flavor
= PPC_THREAD_STATE64
;
151 tstate
= (void *)&mctx64
.ss
;
152 state_count
= PPC_THREAD_STATE64_COUNT
;
153 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
157 if ((ctx32
== 1) || dualcontext
) {
158 flavor
= PPC_EXCEPTION_STATE
;
159 tstate
= (void *)&mctx
.es
;
160 state_count
= PPC_EXCEPTION_STATE_COUNT
;
161 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
165 if ((ctx32
== 0) || dualcontext
) {
166 flavor
= PPC_EXCEPTION_STATE64
;
167 tstate
= (void *)&mctx64
.es
;
168 state_count
= PPC_EXCEPTION_STATE64_COUNT
;
170 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
176 if ((ctx32
== 1) || dualcontext
) {
177 flavor
= PPC_FLOAT_STATE
;
178 tstate
= (void *)&mctx
.fs
;
179 state_count
= PPC_FLOAT_STATE_COUNT
;
180 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
184 if ((ctx32
== 0) || dualcontext
) {
185 flavor
= PPC_FLOAT_STATE
;
186 tstate
= (void *)&mctx64
.fs
;
187 state_count
= PPC_FLOAT_STATE_COUNT
;
188 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
195 if (find_user_vec(th_act
)) {
198 if ((ctx32
== 1) || dualcontext
) {
199 flavor
= PPC_VECTOR_STATE
;
200 tstate
= (void *)&mctx
.vs
;
201 state_count
= PPC_VECTOR_STATE_COUNT
;
202 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
207 if ((ctx32
== 0) || dualcontext
) {
208 flavor
= PPC_VECTOR_STATE
;
209 tstate
= (void *)&mctx64
.vs
;
210 state_count
= PPC_VECTOR_STATE_COUNT
;
211 if (thread_getstatus(th_act
, flavor
, (thread_state_t
)tstate
, &state_count
) != KERN_SUCCESS
)
217 trampact
= ps
->ps_trampact
[sig
];
218 oonstack
= ps
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
220 /* figure out where our new stack lives */
221 if ((ps
->ps_flags
& SAS_ALTSTACK
) && !oonstack
&&
222 (ps
->ps_sigonstack
& sigmask(sig
))) {
223 sp
= (unsigned long)(ps
->ps_sigstk
.ss_sp
);
224 sp
+= ps
->ps_sigstk
.ss_size
;
225 stack_size
= ps
->ps_sigstk
.ss_size
;
226 ps
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
230 sp
= (unsigned int)mctx64
.ss
.r1
;
236 /* put siginfo on top */
238 /* preserve RED ZONE area */
239 sp
= TRUNC_DOWN(sp
, C_REDZONE_LEN
, C_STK_ALIGN
);
241 /* next are the saved registers */
242 if ((ctx32
== 0) || dualcontext
) {
243 sp
-= sizeof(*p_mctx64
);
244 p_mctx64
= (struct mcontext64
*)sp
;
246 if ((ctx32
== 1) || dualcontext
) {
247 sp
-= sizeof(*p_mctx
);
248 p_mctx
= (struct mcontext
*)sp
;
251 /* context goes first on stack */
252 sp
-= sizeof(*p_uctx
);
253 p_uctx
= (struct ucontext
*) sp
;
255 /* this is where siginfo goes on stack */
256 sp
-= sizeof(*p_sinfo
);
257 p_sinfo
= (siginfo_t
*) sp
;
259 /* C calling conventions, create param save and linkage
263 sp
= TRUNC_DOWN(sp
, C_PARAMSAVE_LEN
, C_STK_ALIGN
);
268 uctx
.uc_onstack
= oonstack
;
269 uctx
.uc_sigmask
= mask
;
270 uctx
.uc_stack
.ss_sp
= (char *)sp
;
271 uctx
.uc_stack
.ss_size
= stack_size
;
273 uctx
.uc_stack
.ss_flags
|= SS_ONSTACK
;
277 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE64_COUNT
+ PPC_THREAD_STATE64_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
279 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
282 uctx
.uc_mcsize
+= (size_t)(PPC_VECTOR_STATE_COUNT
* sizeof(int));
285 uctx
.uc_mcontext
= (void *)p_mctx64
;
287 uctx
.uc_mcontext
= (void *)p_mctx
;
290 bzero((caddr_t
)&sinfo
, sizeof(siginfo_t
));
291 sinfo
.si_signo
= sig
;
292 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
293 sinfo
.pad
[0] = (unsigned int)mctx
.ss
.r1
;
297 sinfo
.si_pid
= p
->si_pid
;
299 sinfo
.si_status
= p
->si_status
;
301 sinfo
.si_uid
= p
->si_uid
;
303 sinfo
.si_code
= p
->si_code
;
305 if (sinfo
.si_code
== CLD_EXITED
) {
306 if (WIFEXITED(sinfo
.si_status
))
307 sinfo
.si_code
= CLD_EXITED
;
308 else if (WIFSIGNALED(sinfo
.si_status
)) {
309 if (WCOREDUMP(sinfo
.si_status
))
310 sinfo
.si_code
= CLD_DUMPED
;
312 sinfo
.si_code
= CLD_KILLED
;
317 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
318 if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_ILL_INS_BIT
)))
319 sinfo
.si_code
= ILL_ILLOPC
;
320 else if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_PRV_INS_BIT
)))
321 sinfo
.si_code
= ILL_PRVOPC
;
322 else if (mctx
.ss
.srr1
& (1 << (31 - SRR1_PRG_TRAP_BIT
)))
323 sinfo
.si_code
= ILL_ILLTRP
;
325 sinfo
.si_code
= ILL_NOOP
;
333 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
334 if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_VX
)))
335 sinfo
.si_code
= FPE_FLTINV
;
336 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_OX
)))
337 sinfo
.si_code
= FPE_FLTOVF
;
338 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_UX
)))
339 sinfo
.si_code
= FPE_FLTUND
;
340 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_ZX
)))
341 sinfo
.si_code
= FPE_FLTDIV
;
342 else if (mctx
.fs
.fpscr
& (1 << (31 - FPSCR_XX
)))
343 sinfo
.si_code
= FPE_FLTRES
;
345 sinfo
.si_code
= FPE_NOOP
;
349 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
350 /* on ppc we generate only if EXC_PPC_UNALIGNED */
351 sinfo
.si_code
= BUS_ADRALN
;
355 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
356 /* First check in srr1 and then in dsisr */
357 if (mctx
.ss
.srr1
& (1 << (31 - DSISR_PROT_BIT
)))
358 sinfo
.si_code
= SEGV_ACCERR
;
359 else if (mctx
.es
.dsisr
& (1 << (31 - DSISR_PROT_BIT
)))
360 sinfo
.si_code
= SEGV_ACCERR
;
362 sinfo
.si_code
= SEGV_MAPERR
;
369 /* copy info out to user space */
370 if (copyout((caddr_t
)&uctx
, (caddr_t
)p_uctx
, sizeof(struct ucontext
)))
372 if (copyout((caddr_t
)&sinfo
, (caddr_t
)p_sinfo
, sizeof(siginfo_t
)))
374 if ((ctx32
== 0) || dualcontext
) {
376 if (copyout((caddr_t
)tstate
, (caddr_t
)p_mctx64
, uctx
.uc_mcsize
))
379 if ((ctx32
== 1) || dualcontext
) {
381 if (copyout((caddr_t
)tstate
, (caddr_t
)p_mctx
, uctx
.uc_mcsize
))
386 /* Place our arguments in arg registers: rtm dependent */
388 mctx
.ss
.r3
= (unsigned long)catcher
;
389 mctx
.ss
.r4
= (unsigned long)infostyle
;
390 mctx
.ss
.r5
= (unsigned long)sig
;
391 mctx
.ss
.r6
= (unsigned long)p_sinfo
;
392 mctx
.ss
.r7
= (unsigned long)p_uctx
;
394 mctx
.ss
.srr0
= (unsigned long)trampact
;
395 mctx
.ss
.srr1
= get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
397 state_count
= PPC_THREAD_STATE_COUNT
;
398 if (thread_setstatus(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
404 SIGACTION(p
, SIGILL
) = SIG_DFL
;
405 sig
= sigmask(SIGILL
);
406 p
->p_sigignore
&= ~sig
;
407 p
->p_sigcatch
&= ~sig
;
408 ut
->uu_sigmask
&= ~sig
;
409 /* sendsig is called with signal lock held */
410 psignal_lock(p
, SIGILL
, 0);
415 * System call to cleanup state after a signal
416 * has been taken. Reset signal mask and
417 * stack state from context left by sendsig (above).
418 * Return to previous pc and psl as specified by
419 * context left by sendsig. Check carefully to
420 * make sure that the user has not modified the
421 * psl to gain improper priviledges or to cause
425 #define FOR64_TRANSITION 1
427 #ifdef FOR64_TRANSITION
429 struct osigreturn_args
{
430 struct ucontext
*uctx
;
435 osigreturn(p
, uap
, retval
)
437 struct osigreturn_args
*uap
;
440 struct ucontext uctx
;
441 struct ucontext
*p_uctx
;
442 struct mcontext64 mctx64
;
443 struct mcontext64
*p_64mctx
;
444 struct mcontext
*p_mctx
;
447 struct sigacts
*ps
= p
->p_sigacts
;
449 register sig_t action
;
450 unsigned long state_count
;
451 unsigned int state_flavor
;
454 void *tsptr
, *fptr
, *vptr
, *mactx
;
455 void ppc_checkthreadstate(void *, int);
457 th_act
= current_act();
458 /* lets use the larger one */
459 mactx
= (void *)&mctx64
;
461 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
462 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
465 if (error
= copyin(uctx
.uc_mcontext
, mactx
, uctx
.uc_mcsize
)) {
469 if (uctx
.uc_onstack
& 01)
470 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
472 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
474 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
475 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
476 signal_setast(current_act());
479 switch (uctx
.uc_mcsize
) {
480 case UC_FLAVOR64_VEC_SIZE
:
482 case UC_FLAVOR64_SIZE
: {
483 p_64mctx
= (struct mcontext64
*)mactx
;
484 tsptr
= (void *)&p_64mctx
->ss
;
485 fptr
= (void *)&p_64mctx
->fs
;
486 vptr
= (void *)&p_64mctx
->vs
;
487 state_flavor
= PPC_THREAD_STATE64
;
488 state_count
= PPC_THREAD_STATE64_COUNT
;
491 case UC_FLAVOR_VEC_SIZE
:
495 p_mctx
= (struct mcontext
*)mactx
;
496 tsptr
= (void *)&p_mctx
->ss
;
497 fptr
= (void *)&p_mctx
->fs
;
498 vptr
= (void *)&p_mctx
->vs
;
499 state_flavor
= PPC_THREAD_STATE
;
500 state_count
= PPC_THREAD_STATE_COUNT
;
505 /* validate the thread state, set/reset appropriate mode bits in srr1 */
506 (void)ppc_checkthreadstate(tsptr
, state_flavor
);
508 if (thread_setstatus(th_act
, state_flavor
, tsptr
, &state_count
) != KERN_SUCCESS
) {
512 state_count
= PPC_FLOAT_STATE_COUNT
;
513 if (thread_setstatus(th_act
, PPC_FLOAT_STATE
, fptr
, &state_count
) != KERN_SUCCESS
) {
517 mask
= sigmask(SIGFPE
);
518 if (((ut
->uu_sigmask
& mask
) == 0) && (p
->p_sigcatch
& mask
) && ((p
->p_sigignore
& mask
) == 0)) {
519 action
= ps
->ps_sigact
[SIGFPE
];
520 if((action
!= SIG_DFL
) && (action
!= SIG_IGN
)) {
521 thread_enable_fpe(th_act
, 1);
526 state_count
= PPC_VECTOR_STATE_COUNT
;
527 if (thread_setstatus(th_act
, PPC_VECTOR_STATE
, vptr
, &state_count
) != KERN_SUCCESS
) {
531 return (EJUSTRETURN
);
534 #endif /* FOR64_TRANSITION */
536 struct sigreturn_args
{
537 struct ucontext
*uctx
;
543 sigreturn(p
, uap
, retval
)
545 struct sigreturn_args
*uap
;
548 struct ucontext uctx
;
549 struct ucontext
*p_uctx
;
550 char mactx
[sizeof(struct mcontext64
)];
551 struct mcontext
*p_mctx
;
552 struct mcontext64
*p_64mctx
;
555 struct sigacts
*ps
= p
->p_sigacts
;
557 register sig_t action
;
558 unsigned long state_count
;
559 unsigned int state_flavor
;
562 void *tsptr
, *fptr
, *vptr
;
563 int infostyle
= uap
->infostyle
;
564 void ppc_checkthreadstate(void *, int);
566 th_act
= current_act();
568 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
569 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
574 if (error
= copyin(uctx
.uc_mcontext
, mactx
, uctx
.uc_mcsize
)) {
578 if (uctx
.uc_onstack
& 01)
579 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
581 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
583 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
584 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
585 signal_setast(current_act());
589 case UC_FLAVOR64_VEC
:
594 p_64mctx
= (struct mcontext64
*)mactx
;
595 tsptr
= (void *)&p_64mctx
->ss
;
596 fptr
= (void *)&p_64mctx
->fs
;
597 vptr
= (void *)&p_64mctx
->vs
;
598 state_flavor
= PPC_THREAD_STATE64
;
599 state_count
= PPC_THREAD_STATE64_COUNT
;
606 p_mctx
= (struct mcontext
*)mactx
;
607 tsptr
= (void *)&p_mctx
->ss
;
608 fptr
= (void *)&p_mctx
->fs
;
609 vptr
= (void *)&p_mctx
->vs
;
610 state_flavor
= PPC_THREAD_STATE
;
611 state_count
= PPC_THREAD_STATE_COUNT
;
616 /* validate the thread state, set/reset appropriate mode bits in srr1 */
617 (void)ppc_checkthreadstate(tsptr
, state_flavor
);
619 if (thread_setstatus(th_act
, state_flavor
, tsptr
, &state_count
) != KERN_SUCCESS
) {
623 state_count
= PPC_FLOAT_STATE_COUNT
;
624 if (thread_setstatus(th_act
, PPC_FLOAT_STATE
, fptr
, &state_count
) != KERN_SUCCESS
) {
628 mask
= sigmask(SIGFPE
);
629 if (((ut
->uu_sigmask
& mask
) == 0) && (p
->p_sigcatch
& mask
) && ((p
->p_sigignore
& mask
) == 0)) {
630 action
= ps
->ps_sigact
[SIGFPE
];
631 if((action
!= SIG_DFL
) && (action
!= SIG_IGN
)) {
632 thread_enable_fpe(th_act
, 1);
637 state_count
= PPC_VECTOR_STATE_COUNT
;
638 if (thread_setstatus(th_act
, PPC_VECTOR_STATE
, vptr
, &state_count
) != KERN_SUCCESS
) {
642 return (EJUSTRETURN
);
646 * machine_exception() performs MD translation
647 * of a mach exception to a unix signal and code.
661 case EXC_BAD_INSTRUCTION
:
662 *unix_signal
= SIGILL
;
667 *unix_signal
= SIGFPE
;
672 if (code
== EXC_PPC_TRAP
) {
673 *unix_signal
= SIGTRAP
;