aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Turner <andrew@FreeBSD.org>2023-01-18 09:30:20 +0000
committerAndrew Turner <andrew@FreeBSD.org>2023-01-18 09:31:35 +0000
commit95dd6974b591ce76bf8d29adcc0dd01b4b281ffd (patch)
tree7bdfcc4cdba9ccd41f11fa9a1d5c455d90c6872b
parent1d577bedbae80ced38ccb834e6835e5fd98bc411 (diff)
downloadsrc-95dd6974b591ce76bf8d29adcc0dd01b4b281ffd.tar.gz
src-95dd6974b591ce76bf8d29adcc0dd01b4b281ffd.zip
Always read the VFP regs in the arm64 fill_fpregs
The PCB_FP_STARTED is used to indicate that the current VFP context has been used since either 1. the start of the thread, or 2. exiting a kernel FP context. When case 2 was added to the kernel this could cause incorrect results to be returned when a thread exits the kernel FP context and fill_fpregs is called before it has restored the VFP state, e.g. by trappin on a userspace VFP instruction. In both of the cases the base save area is still valid so reduce the use of the PCB_FP_STARTED flag check to help decide if we need to store the current threads VFP state. Sponsored by: Arm Ltd Differential Revision: https://reviews.freebsd.org/D37994
-rw-r--r--sys/arm64/arm64/exec_machdep.c17
1 files changed, 9 insertions, 8 deletions
diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c
index 6109a866a2d0..12c23149ec7f 100644
--- a/sys/arm64/arm64/exec_machdep.c
+++ b/sys/arm64/arm64/exec_machdep.c
@@ -153,16 +153,17 @@ fill_fpregs(struct thread *td, struct fpreg *regs)
*/
if (td == curthread)
vfp_save_state(td, pcb);
+ }
- KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
- ("Called fill_fpregs while the kernel is using the VFP"));
- memcpy(regs->fp_q, pcb->pcb_fpustate.vfp_regs,
- sizeof(regs->fp_q));
- regs->fp_cr = pcb->pcb_fpustate.vfp_fpcr;
- regs->fp_sr = pcb->pcb_fpustate.vfp_fpsr;
- } else
+ KASSERT(pcb->pcb_fpusaved == &pcb->pcb_fpustate,
+ ("Called fill_fpregs while the kernel is using the VFP"));
+ memcpy(regs->fp_q, pcb->pcb_fpustate.vfp_regs,
+ sizeof(regs->fp_q));
+ regs->fp_cr = pcb->pcb_fpustate.vfp_fpcr;
+ regs->fp_sr = pcb->pcb_fpustate.vfp_fpsr;
+#else
+ memset(regs, 0, sizeof(*regs));
#endif
- memset(regs, 0, sizeof(*regs));
return (0);
}