diff --git a/sys/arm64/arm64/elf32_machdep.c b/sys/arm64/arm64/elf32_machdep.c index 916633650d69..84b62caf8590 100644 --- a/sys/arm64/arm64/elf32_machdep.c +++ b/sys/arm64/arm64/elf32_machdep.c @@ -51,6 +51,9 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef VFP +#include +#endif #include @@ -251,6 +254,10 @@ freebsd32_setregs(struct thread *td, struct image_params *imgp, tf->tf_x[14] = imgp->entry_addr; tf->tf_elr = imgp->entry_addr; tf->tf_spsr = PSR_M_32; + +#ifdef VFP + vfp_reset_state(td, td->td_pcb); +#endif } void diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c index 73b06beeba7e..91f0a31ebe36 100644 --- a/sys/arm64/arm64/machdep.c +++ b/sys/arm64/arm64/machdep.c @@ -552,6 +552,7 @@ void exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack) { struct trapframe *tf = td->td_frame; + struct pcb *pcb = td->td_pcb; memset(tf, 0, sizeof(struct trapframe)); @@ -559,6 +560,12 @@ exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack) tf->tf_sp = STACKALIGN(stack); tf->tf_lr = imgp->entry_addr; tf->tf_elr = imgp->entry_addr; + +#ifdef VFP + vfp_reset_state(td, pcb); +#endif + + /* TODO: Shouldn't we also reset pcb_dbg_regs? */ } /* Sanity check these are the same size, they will be memcpy'd to and fro */ diff --git a/sys/arm64/arm64/vfp.c b/sys/arm64/arm64/vfp.c index 23c782c6dccb..5fa420e668c1 100644 --- a/sys/arm64/arm64/vfp.c +++ b/sys/arm64/arm64/vfp.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #ifdef VFP #include #include +#include #include #include #include @@ -199,6 +200,26 @@ vfp_save_state(struct thread *td, struct pcb *pcb) critical_exit(); } +/* + * Reset the FP state to avoid leaking state from the parent process across + * execve() (and to ensure that we get a consistent floating point environment + * in every new process). + */ +void +vfp_reset_state(struct thread *td, struct pcb *pcb) +{ + critical_enter(); + bzero(&pcb->pcb_fpustate.vfp_regs, sizeof(pcb->pcb_fpustate.vfp_regs)); + KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate, + ("pcb_fpusaved should point to pcb_fpustate.")); + pcb->pcb_fpustate.vfp_fpcr = initial_fpcr; + pcb->pcb_fpustate.vfp_fpsr = 0; + pcb->pcb_vfpcpu = UINT_MAX; + pcb->pcb_fpflags = 0; + vfp_discard(td); + critical_exit(); +} + void vfp_restore_state(void) { diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c index 9a496b40ec98..0193048e2697 100644 --- a/sys/arm64/arm64/vm_machdep.c +++ b/sys/arm64/arm64/vm_machdep.c @@ -108,7 +108,6 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) td2->td_pcb->pcb_sp = (uintptr_t)td2->td_frame; td2->td_pcb->pcb_fpusaved = &td2->td_pcb->pcb_fpustate; td2->td_pcb->pcb_vfpcpu = UINT_MAX; - td2->td_pcb->pcb_fpusaved->vfp_fpcr = initial_fpcr; /* Setup to release spin count in fork_exit(). */ td2->td_md.md_spinlock_count = 1; diff --git a/sys/arm64/include/vfp.h b/sys/arm64/include/vfp.h index b0ba01a2a319..3632e5eaa396 100644 --- a/sys/arm64/include/vfp.h +++ b/sys/arm64/include/vfp.h @@ -68,6 +68,7 @@ struct thread; void vfp_init(void); void vfp_discard(struct thread *); +void vfp_reset_state(struct thread *, struct pcb *); void vfp_restore_state(void); void vfp_save_state(struct thread *, struct pcb *); diff --git a/sys/arm64/linux/linux_sysvec.c b/sys/arm64/linux/linux_sysvec.c index 1d628ffe6ecb..67feacfa876b 100644 --- a/sys/arm64/linux/linux_sysvec.c +++ b/sys/arm64/linux/linux_sysvec.c @@ -57,6 +57,10 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef VFP +#include +#endif + MODULE_VERSION(linux64elf, 1); const char *linux_kplatform; @@ -360,6 +364,10 @@ linux_exec_setregs(struct thread *td, struct image_params *imgp, regs->tf_lr = 0xffffffffffffffff; #endif regs->tf_elr = imgp->entry_addr; + +#ifdef VFP + vfp_reset_state(td, td->td_pcb); +#endif } int