Author: mmel
Date: Sun Mar 26 08:36:56 2017
New Revision: 315974
URL: https://svnweb.freebsd.org/changeset/base/315974

Log:
  Preserve VFP state across signal delivery.
  
  We don't have enouch space to store full VFP context within mcontext
  stucture. Due to this:
   - follow i386/amd64 way and store VFP state outside of the mcontext_t
     but point to it. Use the size of VFP state structure as an 'magic'
     indicator of the saved VFP state presence.
   - teach set_mcontext() about this external storage.
   - for signal delivery, store VFP state to expanded 'struct sigframe'.
  
  Submited by:  Andrew Gierth (initial version)
  PR:           217611
  MFC after:    2 weeks

Modified:
  head/lib/libthread_db/arch/arm/libpthread_md.c
  head/sys/arm/arm/machdep.c
  head/sys/arm/include/frame.h
  head/sys/arm/include/ucontext.h

Modified: head/lib/libthread_db/arch/arm/libpthread_md.c
==============================================================================
--- head/lib/libthread_db/arch/arm/libpthread_md.c      Sun Mar 26 08:36:20 
2017        (r315973)
+++ head/lib/libthread_db/arch/arm/libpthread_md.c      Sun Mar 26 08:36:56 
2017        (r315974)
@@ -90,7 +90,9 @@ pt_fpreg_to_ucontext(const struct fpreg 
        mcontext_t *mc = &uc->uc_mcontext;
 
        /* XXX */
-       memset(&mc->mc_spare, 0, sizeof(mc->mc_spare));
+       mc->mc_vfp_size = 0;
+       mc->mc_vfp_ptr = NULL;
+       memset(mc->mc_spare, 0, sizeof(mc->mc_spare));
 }
 
 void

Modified: head/sys/arm/arm/machdep.c
==============================================================================
--- head/sys/arm/arm/machdep.c  Sun Mar 26 08:36:20 2017        (r315973)
+++ head/sys/arm/arm/machdep.c  Sun Mar 26 08:36:56 2017        (r315974)
@@ -146,105 +146,6 @@ static delay_func *delay_impl;
 static void *delay_arg;
 #endif
 
-void
-sendsig(catcher, ksi, mask)
-       sig_t catcher;
-       ksiginfo_t *ksi;
-       sigset_t *mask;
-{
-       struct thread *td;
-       struct proc *p;
-       struct trapframe *tf;
-       struct sigframe *fp, frame;
-       struct sigacts *psp;
-       struct sysentvec *sysent;
-       int onstack;
-       int sig;
-       int code;
-
-       td = curthread;
-       p = td->td_proc;
-       PROC_LOCK_ASSERT(p, MA_OWNED);
-       sig = ksi->ksi_signo;
-       code = ksi->ksi_code;
-       psp = p->p_sigacts;
-       mtx_assert(&psp->ps_mtx, MA_OWNED);
-       tf = td->td_frame;
-       onstack = sigonstack(tf->tf_usr_sp);
-
-       CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
-           catcher, sig);
-
-       /* Allocate and validate space for the signal handler context. */
-       if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
-           SIGISMEMBER(psp->ps_sigonstack, sig)) {
-               fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
-                   td->td_sigstk.ss_size);
-#if defined(COMPAT_43)
-               td->td_sigstk.ss_flags |= SS_ONSTACK;
-#endif
-       } else
-               fp = (struct sigframe *)td->td_frame->tf_usr_sp;
-
-       /* make room on the stack */
-       fp--;
-
-       /* make the stack aligned */
-       fp = (struct sigframe *)STACKALIGN(fp);
-       /* Populate the siginfo frame. */
-       get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
-       frame.sf_si = ksi->ksi_info;
-       frame.sf_uc.uc_sigmask = *mask;
-       frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
-           ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
-       frame.sf_uc.uc_stack = td->td_sigstk;
-       mtx_unlock(&psp->ps_mtx);
-       PROC_UNLOCK(td->td_proc);
-
-       /* Copy the sigframe out to the user's stack. */
-       if (copyout(&frame, fp, sizeof(*fp)) != 0) {
-               /* Process has trashed its stack. Kill it. */
-               CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
-               PROC_LOCK(p);
-               sigexit(td, SIGILL);
-       }
-
-       /*
-        * Build context to run handler in.  We invoke the handler
-        * directly, only returning via the trampoline.  Note the
-        * trampoline version numbers are coordinated with machine-
-        * dependent code in libc.
-        */
-
-       tf->tf_r0 = sig;
-       tf->tf_r1 = (register_t)&fp->sf_si;
-       tf->tf_r2 = (register_t)&fp->sf_uc;
-
-       /* the trampoline uses r5 as the uc address */
-       tf->tf_r5 = (register_t)&fp->sf_uc;
-       tf->tf_pc = (register_t)catcher;
-       tf->tf_usr_sp = (register_t)fp;
-       sysent = p->p_sysent;
-       if (sysent->sv_sigcode_base != 0)
-               tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base;
-       else
-               tf->tf_usr_lr = (register_t)(sysent->sv_psstrings -
-                   *(sysent->sv_szsigcode));
-       /* Set the mode to enter in the signal handler */
-#if __ARM_ARCH >= 7
-       if ((register_t)catcher & 1)
-               tf->tf_spsr |= PSR_T;
-       else
-               tf->tf_spsr &= ~PSR_T;
-#endif
-
-       CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
-           tf->tf_usr_sp);
-
-       PROC_LOCK(p);
-       mtx_lock(&psp->ps_mtx);
-}
-
 struct kva_md_info kmi;
 
 /*
@@ -488,6 +389,47 @@ exec_setregs(struct thread *td, struct i
        tf->tf_spsr = PSR_USR32_MODE;
 }
 
+
+#ifdef VFP
+/*
+ * Get machine VFP context.
+ */
+static void
+get_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
+{
+       struct pcb *curpcb;
+
+       curpcb = curthread->td_pcb;
+       critical_enter();
+
+       vfp_store(&curpcb->pcb_vfpstate, false);
+       memcpy(vfp->mcv_reg, curpcb->pcb_vfpstate.reg,
+           sizeof(vfp->mcv_reg));
+       vfp->mcv_fpscr = curpcb->pcb_vfpstate.fpscr;
+
+       critical_exit();
+}
+
+/*
+ * Set machine VFP context.
+ */
+static void
+set_vfpcontext(struct thread *td, mcontext_vfp_t *vfp)
+{
+       struct pcb *curpcb;
+
+       curpcb = curthread->td_pcb;
+       critical_enter();
+
+       vfp_discard(td);
+       memcpy(curpcb->pcb_vfpstate.reg, vfp->mcv_reg,
+           sizeof(curpcb->pcb_vfpstate.reg));
+       curpcb->pcb_vfpstate.fpscr = vfp->mcv_fpscr;
+
+       critical_exit();
+}
+#endif
+
 /*
  * Get machine context.
  */
@@ -520,6 +462,10 @@ get_mcontext(struct thread *td, mcontext
        gr[_REG_LR]   = tf->tf_usr_lr;
        gr[_REG_PC]   = tf->tf_pc;
 
+       mcp->mc_vfp_size = 0;
+       mcp->mc_vfp_ptr = NULL;
+       memset(&mcp->mc_spare, 0, sizeof(mcp->mc_spare));
+
        return (0);
 }
 
@@ -532,9 +478,29 @@ get_mcontext(struct thread *td, mcontext
 int
 set_mcontext(struct thread *td, mcontext_t *mcp)
 {
+       mcontext_vfp_t mc_vfp, *vfp;
        struct trapframe *tf = td->td_frame;
        const __greg_t *gr = mcp->__gregs;
 
+#ifdef WITNESS
+       if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_size != sizeof(mc_vfp)) {
+               printf("%s: %s: Malformed mc_vfp_size: %d (0x%08X)\n",
+                   td->td_proc->p_comm, __func__,
+                   mcp->mc_vfp_size, mcp->mc_vfp_size);
+       } else if (mcp->mc_vfp_size != 0 && mcp->mc_vfp_ptr == NULL) {
+               printf("%s: %s: c_vfp_size != 0 but mc_vfp_ptr == NULL\n",
+                   td->td_proc->p_comm, __func__);
+       }
+#endif
+
+       if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != NULL) {
+               if (copyin(mcp->mc_vfp_ptr, &mc_vfp, sizeof(mc_vfp)) != 0)
+                       return (EFAULT);
+               vfp = &mc_vfp;
+       } else {
+               vfp = NULL;
+       }
+
        tf->tf_r0 = gr[_REG_R0];
        tf->tf_r1 = gr[_REG_R1];
        tf->tf_r2 = gr[_REG_R2];
@@ -552,10 +518,120 @@ set_mcontext(struct thread *td, mcontext
        tf->tf_usr_lr = gr[_REG_LR];
        tf->tf_pc = gr[_REG_PC];
        tf->tf_spsr = gr[_REG_CPSR];
-
+#ifdef VFP
+       if (vfp != NULL)
+               set_vfpcontext(td, vfp);
+#endif
        return (0);
 }
 
+void
+sendsig(catcher, ksi, mask)
+       sig_t catcher;
+       ksiginfo_t *ksi;
+       sigset_t *mask;
+{
+       struct thread *td;
+       struct proc *p;
+       struct trapframe *tf;
+       struct sigframe *fp, frame;
+       struct sigacts *psp;
+       struct sysentvec *sysent;
+       int onstack;
+       int sig;
+       int code;
+
+       td = curthread;
+       p = td->td_proc;
+       PROC_LOCK_ASSERT(p, MA_OWNED);
+       sig = ksi->ksi_signo;
+       code = ksi->ksi_code;
+       psp = p->p_sigacts;
+       mtx_assert(&psp->ps_mtx, MA_OWNED);
+       tf = td->td_frame;
+       onstack = sigonstack(tf->tf_usr_sp);
+
+       CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm,
+           catcher, sig);
+
+       /* Allocate and validate space for the signal handler context. */
+       if ((td->td_pflags & TDP_ALTSTACK) != 0 && !(onstack) &&
+           SIGISMEMBER(psp->ps_sigonstack, sig)) {
+               fp = (struct sigframe *)((uintptr_t)td->td_sigstk.ss_sp +
+                   td->td_sigstk.ss_size);
+#if defined(COMPAT_43)
+               td->td_sigstk.ss_flags |= SS_ONSTACK;
+#endif
+       } else
+               fp = (struct sigframe *)td->td_frame->tf_usr_sp;
+
+       /* make room on the stack */
+       fp--;
+
+       /* make the stack aligned */
+       fp = (struct sigframe *)STACKALIGN(fp);
+       /* Populate the siginfo frame. */
+       get_mcontext(td, &frame.sf_uc.uc_mcontext, 0);
+#ifdef VFP
+       get_vfpcontext(td, &frame.sf_vfp);
+       frame.sf_uc.uc_mcontext.mc_vfp_size = sizeof(fp->sf_vfp);
+       frame.sf_uc.uc_mcontext.mc_vfp_ptr = &fp->sf_vfp;
+#else
+       frame.sf_uc.uc_mcontext.mc_vfp_size = 0;
+       frame.sf_uc.uc_mcontext.mc_vfp_ptr = NULL;
+#endif
+       frame.sf_si = ksi->ksi_info;
+       frame.sf_uc.uc_sigmask = *mask;
+       frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK )
+           ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE;
+       frame.sf_uc.uc_stack = td->td_sigstk;
+       mtx_unlock(&psp->ps_mtx);
+       PROC_UNLOCK(td->td_proc);
+
+       /* Copy the sigframe out to the user's stack. */
+       if (copyout(&frame, fp, sizeof(*fp)) != 0) {
+               /* Process has trashed its stack. Kill it. */
+               CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp);
+               PROC_LOCK(p);
+               sigexit(td, SIGILL);
+       }
+
+       /*
+        * Build context to run handler in.  We invoke the handler
+        * directly, only returning via the trampoline.  Note the
+        * trampoline version numbers are coordinated with machine-
+        * dependent code in libc.
+        */
+
+       tf->tf_r0 = sig;
+       tf->tf_r1 = (register_t)&fp->sf_si;
+       tf->tf_r2 = (register_t)&fp->sf_uc;
+
+       /* the trampoline uses r5 as the uc address */
+       tf->tf_r5 = (register_t)&fp->sf_uc;
+       tf->tf_pc = (register_t)catcher;
+       tf->tf_usr_sp = (register_t)fp;
+       sysent = p->p_sysent;
+       if (sysent->sv_sigcode_base != 0)
+               tf->tf_usr_lr = (register_t)sysent->sv_sigcode_base;
+       else
+               tf->tf_usr_lr = (register_t)(sysent->sv_psstrings -
+                   *(sysent->sv_szsigcode));
+       /* Set the mode to enter in the signal handler */
+#if __ARM_ARCH >= 7
+       if ((register_t)catcher & 1)
+               tf->tf_spsr |= PSR_T;
+       else
+               tf->tf_spsr &= ~PSR_T;
+#endif
+
+       CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_usr_lr,
+           tf->tf_usr_sp);
+
+       PROC_LOCK(p);
+       mtx_lock(&psp->ps_mtx);
+}
+
 int
 sys_sigreturn(td, uap)
        struct thread *td;
@@ -578,7 +654,7 @@ sys_sigreturn(td, uap)
        if ((spsr & PSR_MODE) != PSR_USR32_MODE ||
            (spsr & (PSR_I | PSR_F)) != 0)
                return (EINVAL);
-               /* Restore register context. */
+       /* Restore register context. */
        set_mcontext(td, &uc.uc_mcontext);
 
        /* Restore signal mask. */

Modified: head/sys/arm/include/frame.h
==============================================================================
--- head/sys/arm/include/frame.h        Sun Mar 26 08:36:20 2017        
(r315973)
+++ head/sys/arm/include/frame.h        Sun Mar 26 08:36:56 2017        
(r315974)
@@ -94,6 +94,7 @@ struct trapframe {
 struct sigframe {
        siginfo_t       sf_si;          /* actual saved siginfo */
        ucontext_t      sf_uc;          /* actual saved ucontext */
+       mcontext_vfp_t  sf_vfp;         /* actual saved VFP context */
 };
 
 

Modified: head/sys/arm/include/ucontext.h
==============================================================================
--- head/sys/arm/include/ucontext.h     Sun Mar 26 08:36:20 2017        
(r315973)
+++ head/sys/arm/include/ucontext.h     Sun Mar 26 08:36:56 2017        
(r315974)
@@ -63,6 +63,14 @@ typedef __greg_t     __gregset_t[_NGREG];
 #define _REG_LR                _REG_R14
 #define _REG_PC                _REG_R15
 
+/*
+ * Floating point register state
+ */
+typedef struct {
+       __uint64_t      mcv_reg[32];
+       __uint32_t      mcv_fpscr;
+} mcontext_vfp_t;
+
 typedef struct {
        __gregset_t     __gregs;
 
@@ -70,7 +78,10 @@ typedef struct {
         * Originally, rest of this structure was named __fpu, 35 * 4 bytes
         * long, never accessed from kernel. 
         */
-       unsigned int    mc_spare[35];
+       size_t          mc_vfp_size;
+       void            *mc_vfp_ptr;
+       unsigned int    mc_spare[33];
 } mcontext_t;
 
+#define UC_
 #endif /* !_MACHINE_MCONTEXT_H_ */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to