X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/43866e378188c25dd1e2208016ab3cbeb086ae6c..55e303ae13a4cf49d70f2294092726f2fffb9ef2:/bsd/dev/ppc/unix_signal.c diff --git a/bsd/dev/ppc/unix_signal.c b/bsd/dev/ppc/unix_signal.c index 2b3fc8318..2bbb6674e 100644 --- a/bsd/dev/ppc/unix_signal.c +++ b/bsd/dev/ppc/unix_signal.c @@ -41,7 +41,6 @@ #include #include #include -#define __ELF__ 0 #include #define C_REDZONE_LEN 224 @@ -50,6 +49,42 @@ #define C_LINKAGE_LEN 48 #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c)) +/* + * The stack layout possibilities (info style); This needs to mach with signal trampoline code + * + * Traditional: 1 + * Traditional64: 20 + * Traditional64with vec: 25 + * 32bit context 30 + * 32bit context with vector 35 + * 64bit context 40 + * 64bit context with vector 45 + * Dual context 50 + * Dual context with vector 55 + * + */ + +#define UC_TRAD 1 +#define UC_TRAD_VEC 6 +#define UC_TRAD64 20 +#define UC_TRAD64_VEC 25 +#define UC_FLAVOR 30 +#define UC_FLAVOR_VEC 35 +#define UC_FLAVOR64 40 +#define UC_FLAVOR64_VEC 45 +#define UC_DUAL 50 +#define UC_DUAL_VEC 55 + + /* The following are valid mcontext sizes */ +#define UC_FLAVOR_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR_VEC_SIZE ((PPC_THREAD_STATE_COUNT + PPC_EXCEPTION_STATE_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR64_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)) + +#define UC_FLAVOR64_VEC_SIZE ((PPC_THREAD_STATE64_COUNT + PPC_EXCEPTION_STATE64_COUNT + PPC_FLOAT_STATE_COUNT + PPC_VECTOR_STATE_COUNT) * sizeof(int)) + + /* * Arrange for this process to run a signal handler */ @@ -61,7 +96,9 @@ sendsig(p, catcher, sig, mask, code) int sig, mask; u_long code; { + kern_return_t kretn; struct mcontext mctx, *p_mctx; + struct mcontext64 mctx64, *p_mctx64; struct ucontext uctx, *p_uctx; siginfo_t sinfo, *p_sinfo; struct sigacts *ps = p->p_sigacts; @@ -72,42 +109,114 @@ sendsig(p, catcher, sig, mask, code) thread_act_t th_act; struct uthread *ut; unsigned long paramp,linkp; - int infostyle = 1; + int infostyle = UC_TRAD; + int dualcontext =0; sig_t trampact; int vec_used = 0; int stack_size = 0; int stack_flags = 0; + void * tstate; + int flavor; + int ctx32 = 1; + int is_64signalregset(void); th_act = current_act(); ut = get_bsdthread_info(th_act); - state_count = PPC_EXCEPTION_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count) != KERN_SUCCESS) { - goto bad; - } + + if (p->p_sigacts->ps_siginfo & sigmask(sig)) { + infostyle = UC_FLAVOR; + } + if(is_64signalregset() && (infostyle == UC_FLAVOR)) { + dualcontext = 1; + infostyle = UC_DUAL; + } + if (p->p_sigacts->ps_64regset & sigmask(sig)) { + dualcontext = 0; + ctx32 = 0; + infostyle = UC_FLAVOR64; + } + if (is_64signalregset() && (infostyle == UC_TRAD)) { + ctx32=0; + infostyle = UC_TRAD64; + } + + /* I need this for SIGINFO anyway */ + flavor = PPC_THREAD_STATE; + tstate = (void *)&mctx.ss; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { - goto bad; - } - state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) goto bad; - } - vec_save(th_act); - if (find_user_vec(th_act)) { - vec_used = 1; - state_count = PPC_VECTOR_STATE_COUNT; - if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { - goto bad; - } - + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_THREAD_STATE64; + tstate = (void *)&mctx64.ss; + state_count = PPC_THREAD_STATE64_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; } + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_EXCEPTION_STATE; + tstate = (void *)&mctx.es; + state_count = PPC_EXCEPTION_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_EXCEPTION_STATE64; + tstate = (void *)&mctx64.es; + state_count = PPC_EXCEPTION_STATE64_COUNT; + + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + + } + + + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_FLOAT_STATE; + tstate = (void *)&mctx.fs; + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_FLOAT_STATE; + tstate = (void *)&mctx64.fs; + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + + } + + + if (find_user_vec_curr()) { + vec_used = 1; + + if ((ctx32 == 1) || dualcontext) { + flavor = PPC_VECTOR_STATE; + tstate = (void *)&mctx.vs; + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + infostyle += 5; + } + + if ((ctx32 == 0) || dualcontext) { + flavor = PPC_VECTOR_STATE; + tstate = (void *)&mctx64.vs; + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_getstatus(th_act, flavor, (thread_state_t)tstate, &state_count) != KERN_SUCCESS) + goto bad; + infostyle += 5; + } + } + trampact = ps->ps_trampact[sig]; oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; - if (p->p_sigacts->ps_siginfo & sigmask(sig)) - infostyle = 2; /* figure out where our new stack lives */ if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && @@ -117,13 +226,30 @@ sendsig(p, catcher, sig, mask, code) stack_size = ps->ps_sigstk.ss_size; ps->ps_sigstk.ss_flags |= SA_ONSTACK; } - else - sp = mctx.ss.r1; + else { + if (ctx32 == 0) + sp = (unsigned int)mctx64.ss.r1; + else + sp = mctx.ss.r1; + } + + /* put siginfo on top */ + /* preserve RED ZONE area */ sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN); - /* context goes first on stack */ + /* next are the saved registers */ + if ((ctx32 == 0) || dualcontext) { + sp -= sizeof(*p_mctx64); + p_mctx64 = (struct mcontext64 *)sp; + } + if ((ctx32 == 1) || dualcontext) { + sp -= sizeof(*p_mctx); + p_mctx = (struct mcontext *)sp; + } + + /* context goes first on stack */ sp -= sizeof(*p_uctx); p_uctx = (struct ucontext *) sp; @@ -131,13 +257,9 @@ sendsig(p, catcher, sig, mask, code) sp -= sizeof(*p_sinfo); p_sinfo = (siginfo_t *) sp; - /* next are the saved registers */ - sp -= sizeof(*p_mctx); - p_mctx = (struct mcontext *)sp; - /* C calling conventions, create param save and linkage - * areas - */ + * areas + */ sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN); paramp = sp; @@ -152,14 +274,25 @@ sendsig(p, catcher, sig, mask, code) uctx.uc_stack.ss_flags |= SS_ONSTACK; uctx.uc_link = 0; - uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + if (ctx32 == 0) + uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE64_COUNT + PPC_THREAD_STATE64_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + else + uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + if (vec_used) uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int)); - uctx.uc_mcontext = p_mctx; + + if (ctx32 == 0) + uctx.uc_mcontext = (void *)p_mctx64; + else + uctx.uc_mcontext = (void *)p_mctx; /* setup siginfo */ bzero((caddr_t)&sinfo, sizeof(siginfo_t)); sinfo.si_signo = sig; + sinfo.si_addr = (void *)mctx.ss.srr0; + sinfo.pad[0] = (unsigned int)mctx.ss.r1; + switch (sig) { case SIGCHLD: sinfo.si_pid = p->si_pid; @@ -233,13 +366,23 @@ sendsig(p, catcher, sig, mask, code) break; } + /* copy info out to user space */ if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext))) goto bad; if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t))) goto bad; - if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize)) + if ((ctx32 == 0) || dualcontext) { + tstate = &mctx64; + if (copyout((caddr_t)tstate, (caddr_t)p_mctx64, uctx.uc_mcsize)) + goto bad; + } + if ((ctx32 == 1) || dualcontext) { + tstate = &mctx; + if (copyout((caddr_t)tstate, (caddr_t)p_mctx, uctx.uc_mcsize)) goto bad; + } + /* Place our arguments in arg registers: rtm dependent */ @@ -253,10 +396,9 @@ sendsig(p, catcher, sig, mask, code) mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */ mctx.ss.r1 = sp; state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { - goto bad; + if ((kretn = thread_setstatus(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count)) != KERN_SUCCESS) { + panic("sendsig: thread_setstatus failed, ret = %08X\n", kretn); } - return; bad: @@ -280,8 +422,122 @@ bad: * psl to gain improper priviledges or to cause * a machine fault. */ + +#define FOR64_TRANSITION 1 + + +#ifdef FOR64_TRANSITION + +struct osigreturn_args { + struct ucontext *uctx; +}; + +/* ARGSUSED */ +int +osigreturn(p, uap, retval) + struct proc *p; + struct osigreturn_args *uap; + int *retval; +{ + struct ucontext uctx; + struct ucontext *p_uctx; + struct mcontext64 mctx64; + struct mcontext64 *p_64mctx; + struct mcontext *p_mctx; + int error; + thread_act_t th_act; + struct sigacts *ps = p->p_sigacts; + sigset_t mask; + register sig_t action; + unsigned long state_count; + unsigned int state_flavor; + struct uthread * ut; + int vec_used = 0; + void *tsptr, *fptr, *vptr, *mactx; + void ppc_checkthreadstate(void *, int); + + th_act = current_act(); + /* lets use the larger one */ + mactx = (void *)&mctx64; + + ut = (struct uthread *)get_bsdthread_info(th_act); + if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { + return(error); + } + if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) { + return(error); + } + + if (uctx.uc_onstack & 01) + p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; + else + p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; + + ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; + if (ut->uu_siglist & ~ut->uu_sigmask) + signal_setast(current_act()); + + vec_used = 0; + switch (uctx.uc_mcsize) { + case UC_FLAVOR64_VEC_SIZE : + vec_used = 1; + case UC_FLAVOR64_SIZE : { + p_64mctx = (struct mcontext64 *)mactx; + tsptr = (void *)&p_64mctx->ss; + fptr = (void *)&p_64mctx->fs; + vptr = (void *)&p_64mctx->vs; + state_flavor = PPC_THREAD_STATE64; + state_count = PPC_THREAD_STATE64_COUNT; + } + break; + case UC_FLAVOR_VEC_SIZE : + vec_used = 1; + case UC_FLAVOR_SIZE: + default: { + p_mctx = (struct mcontext *)mactx; + tsptr = (void *)&p_mctx->ss; + fptr = (void *)&p_mctx->fs; + vptr = (void *)&p_mctx->vs; + state_flavor = PPC_THREAD_STATE; + state_count = PPC_THREAD_STATE_COUNT; + } + break; + } /* switch () */ + + /* validate the thread state, set/reset appropriate mode bits in srr1 */ + (void)ppc_checkthreadstate(tsptr, state_flavor); + + if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + + state_count = PPC_FLOAT_STATE_COUNT; + if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + + mask = sigmask(SIGFPE); + if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) { + action = ps->ps_sigact[SIGFPE]; + if((action != SIG_DFL) && (action != SIG_IGN)) { + thread_enable_fpe(th_act, 1); + } + } + + if (vec_used) { + state_count = PPC_VECTOR_STATE_COUNT; + if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) { + return(EINVAL); + } + } + return (EJUSTRETURN); +} + +#endif /* FOR64_TRANSITION */ + struct sigreturn_args { struct ucontext *uctx; + int infostyle; }; /* ARGSUSED */ @@ -291,19 +547,23 @@ sigreturn(p, uap, retval) struct sigreturn_args *uap; int *retval; { - struct ucontext uctx, *p_uctx; - struct mcontext mctx, *p_mctx; + struct ucontext uctx; + struct ucontext *p_uctx; + char mactx[sizeof(struct mcontext64)]; + struct mcontext *p_mctx; + struct mcontext64 *p_64mctx; int error; thread_act_t th_act; - struct ppc_float_state fs; - struct ppc_exception_state es; struct sigacts *ps = p->p_sigacts; sigset_t mask; register sig_t action; unsigned long state_count; - unsigned int nbits, rbits; + unsigned int state_flavor; struct uthread * ut; int vec_used = 0; + void *tsptr, *fptr, *vptr; + int infostyle = uap->infostyle; + void ppc_checkthreadstate(void *, int); th_act = current_act(); @@ -311,7 +571,9 @@ sigreturn(p, uap, retval) if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { return(error); } - if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) { + + + if (error = copyin(uctx.uc_mcontext, mactx, uctx.uc_mcsize)) { return(error); } @@ -319,32 +581,51 @@ sigreturn(p, uap, retval) p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; else p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; - ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; - + ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; if (ut->uu_siglist & ~ut->uu_sigmask) signal_setast(current_act()); - nbits = get_msr_nbits(); - rbits = get_msr_rbits(); - /* adjust the critical fields */ - /* make sure naughty bits are off */ - mctx.ss.srr1 &= ~(nbits); - /* make sure necessary bits are on */ - mctx.ss.srr1 |= (rbits); + vec_used = 0; + switch (infostyle) { + case UC_FLAVOR64_VEC: + case UC_TRAD64_VEC: + vec_used = 1; + case UC_TRAD64: + case UC_FLAVOR64: { + p_64mctx = (struct mcontext64 *)mactx; + tsptr = (void *)&p_64mctx->ss; + fptr = (void *)&p_64mctx->fs; + vptr = (void *)&p_64mctx->vs; + state_flavor = PPC_THREAD_STATE64; + state_count = PPC_THREAD_STATE64_COUNT; + } + break; + case UC_FLAVOR_VEC : + case UC_TRAD_VEC : + vec_used = 1; + case UC_FLAVOR : + case UC_TRAD : + default: { + p_mctx = (struct mcontext *)mactx; + tsptr = (void *)&p_mctx->ss; + fptr = (void *)&p_mctx->fs; + vptr = (void *)&p_mctx->vs; + state_flavor = PPC_THREAD_STATE; + state_count = PPC_THREAD_STATE_COUNT; + } + break; + } /* switch () */ - state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); + /* validate the thread state, set/reset appropriate mode bits in srr1 */ + (void)ppc_checkthreadstate(tsptr, state_flavor); - if (uctx.uc_mcsize > state_count) - vec_used = 1; - - state_count = PPC_THREAD_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, state_flavor, tsptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } state_count = PPC_FLOAT_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_FLOAT_STATE, fptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } @@ -358,11 +639,10 @@ sigreturn(p, uap, retval) if (vec_used) { state_count = PPC_VECTOR_STATE_COUNT; - if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { + if (thread_setstatus(th_act, PPC_VECTOR_STATE, vptr, &state_count) != KERN_SUCCESS) { return(EINVAL); } } - return (EJUSTRETURN); }