diff options
author | Andrew Turner <andrew@FreeBSD.org> | 2023-01-18 09:30:20 +0000 |
---|---|---|
committer | Andrew Turner <andrew@FreeBSD.org> | 2023-01-18 09:31:35 +0000 |
commit | 95dd6974b591ce76bf8d29adcc0dd01b4b281ffd (patch) | |
tree | 7bdfcc4cdba9ccd41f11fa9a1d5c455d90c6872b | |
parent | 1d577bedbae80ced38ccb834e6835e5fd98bc411 (diff) | |
download | src-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.c | 17 |
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); } |