incomplete (as a result of a faulting mandatory RSE load).
mov r9=ar.unat
mov loc0=rp // save return address
mov out0=0 // there is no "oldset"
- adds out1=0,sp // out1=&sigscratch
+ adds out1=8,sp // out1=&sigscratch->ar_pfs
(pSys) mov out2=1 // out2==1 => we're in a syscall
;;
(pNonSys) mov out2=0 // out2==0 => not a syscall
.fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
st8 [sp]=r9,-16 // allocate space for ar.unat and save it
+ st8 [out1]=loc1,-8 // save ar.pfs, out1=&sigscratch
.body
br.call.sptk.many rp=do_notify_resume_user
.ret15: .restore sp
mov loc0=rp // save return address
mov out0=in0 // mask
mov out1=in1 // sigsetsize
- adds out2=0,sp // out2=&sigscratch
+ adds out2=8,sp // out2=&sigscratch->ar_pfs
;;
.fframe 16
.spillpsp ar.unat, 16 // (note that offset is relative to psp+0x10!)
st8 [sp]=r9,-16 // allocate space for ar.unat and save it
+ st8 [out2]=loc1,-8 // save ar.pfs, out2=&sigscratch
.body
br.call.sptk.many rp=ia64_rt_sigsuspend
.ret17: .restore sp
*/
#define SIGTRAMP_SAVES \
- .unwabi @svr4, 's' // mark this as a sigtramp handler (saves scratch regs) \
- .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF \
- .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF \
- .savesp pr, PR_OFF+SIGCONTEXT_OFF \
- .savesp rp, RP_OFF+SIGCONTEXT_OFF \
+ .unwabi @svr4, 's'; /* mark this as a sigtramp handler (saves scratch regs) */ \
+ .savesp ar.unat, UNAT_OFF+SIGCONTEXT_OFF; \
+ .savesp ar.fpsr, FPSR_OFF+SIGCONTEXT_OFF; \
+ .savesp pr, PR_OFF+SIGCONTEXT_OFF; \
+ .savesp rp, RP_OFF+SIGCONTEXT_OFF; \
+ .savesp ar.pfs, CFM_OFF+SIGCONTEXT_OFF; \
.vframesp SP_OFF+SIGCONTEXT_OFF
GLOBAL_ENTRY(ia64_sigtramp)
.spillsp.p p8, ar.rnat, RNAT_OFF+SIGCONTEXT_OFF
(p8) br.cond.spnt setup_rbs // yup -> (clobbers r14, r15, and r16)
back_from_setup_rbs:
-
- .spillreg ar.pfs, r8
- alloc r8=ar.pfs,0,0,3,0 // get CFM0, EC0, and CPL0 into r8
+ alloc r8=ar.pfs,0,0,3,0
ld8 out0=[base0],16 // load arg0 (signum)
adds base1=(ARG1_OFF-(RBS_BASE_OFF+SIGCONTEXT_OFF)),base1
;;
;;
ld8 out2=[base0] // load arg2 (sigcontextp)
ld8 gp=[r17] // get signal handler's global pointer
-
adds base0=(BSP_OFF+SIGCONTEXT_OFF),sp
;;
.spillsp ar.bsp, BSP_OFF+SIGCONTEXT_OFF
- st8 [base0]=r9,(CFM_OFF-BSP_OFF) // save sc_ar_bsp
- dep r8=0,r8,38,26 // clear EC0, CPL0 and reserved bits
- adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
- ;;
- .spillsp ar.pfs, CFM_OFF+SIGCONTEXT_OFF
- st8 [base0]=r8 // save CFM0
+ st8 [base0]=r9 // save sc_ar_bsp
adds base0=(FR6_OFF+SIGCONTEXT_OFF),sp
+ adds base1=(FR6_OFF+16+SIGCONTEXT_OFF),sp
;;
stf.spill [base0]=f6,32
stf.spill [base1]=f7,32
ld8 r15=[base0],(CFM_OFF-BSP_OFF) // fetch sc_ar_bsp and advance to CFM_OFF
mov r14=ar.bsp
;;
- ld8 r8=[base0] // restore (perhaps modified) CFM0, EC0, and CPL0
cmp.ne p8,p0=r14,r15 // do we need to restore the rbs?
(p8) br.cond.spnt restore_rbs // yup -> (clobbers r14-r18, f6 & f7)
;;
struct sigscratch {
unsigned long scratch_unat; /* ar.unat for the general registers saved in pt */
- unsigned long pad;
+ unsigned long ar_pfs; /* for syscalls, the user-level function-state */
struct pt_regs pt;
};
static long
setup_sigcontext (struct sigcontext *sc, sigset_t *mask, struct sigscratch *scr)
{
- unsigned long flags = 0, ifs, nat;
+ unsigned long flags = 0, ifs, cfm, nat;
long err;
ifs = scr->pt.cr_ifs;
if ((ifs & (1UL << 63)) == 0) {
/* if cr_ifs isn't valid, we got here through a syscall */
flags |= IA64_SC_FLAG_IN_SYSCALL;
- }
+ cfm = scr->ar_pfs & ((1UL << 38) - 1);
+ } else
+ cfm = ifs & ((1UL << 38) - 1);
ia64_flush_fph(current);
if ((current->thread.flags & IA64_THREAD_FPH_VALID)) {
flags |= IA64_SC_FLAG_FPH_VALID;
err |= __put_user(nat, &sc->sc_nat);
err |= PUT_SIGSET(mask, &sc->sc_mask);
+ err |= __put_user(cfm, &sc->sc_cfm);
err |= __put_user(scr->pt.cr_ipsr & IA64_PSR_UM, &sc->sc_um);
err |= __put_user(scr->pt.ar_rsc, &sc->sc_ar_rsc);
err |= __put_user(scr->pt.ar_ccv, &sc->sc_ar_ccv);
scr->pt.ar_fpsr = FPSR_DEFAULT; /* reset fpsr for signal handler */
scr->pt.cr_iip = tramp_addr;
ia64_psr(&scr->pt)->ri = 0; /* start executing in first slot */
+ /*
+ * Force the interruption function mask to zero. This has no effect when a
+ * system-call got interrupted by a signal (since, in that case, scr->pt_cr_ifs is
+ * ignored), but it has the desirable effect of making it possible to deliver a
+ * signal with an incomplete register frame (which happens when a mandatory RSE
+ * load faults). Furthermore, it has no negative effect on the getting the user's
+ * dirty partition preserved, because that's governed by scr->pt.loadrs.
+ */
+ scr->pt.cr_ifs = (1UL << 63);
/*
* Note: this affects only the NaT bits of the scratch regs (the ones saved in