Changeset View
Changeset View
Standalone View
Standalone View
sys/arm64/arm64/vfp.c
Show All 27 Lines | |||||
*/ | */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#ifdef VFP | #ifdef VFP | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/limits.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/pcpu.h> | #include <sys/pcpu.h> | ||||
#include <sys/proc.h> | #include <sys/proc.h> | ||||
#include <machine/armreg.h> | #include <machine/armreg.h> | ||||
#include <machine/md_var.h> | #include <machine/md_var.h> | ||||
#include <machine/pcb.h> | #include <machine/pcb.h> | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | vfp_save_state(struct thread *td, struct pcb *pcb) | ||||
if ((cpacr & CPACR_FPEN_MASK) == CPACR_FPEN_TRAP_NONE) { | if ((cpacr & CPACR_FPEN_MASK) == CPACR_FPEN_TRAP_NONE) { | ||||
KASSERT(PCPU_GET(fpcurthread) == td, | KASSERT(PCPU_GET(fpcurthread) == td, | ||||
("Storing an invalid VFP state")); | ("Storing an invalid VFP state")); | ||||
vfp_store(pcb->pcb_fpusaved); | vfp_store(pcb->pcb_fpusaved); | ||||
dsb(ish); | dsb(ish); | ||||
vfp_disable(); | vfp_disable(); | ||||
} | } | ||||
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(); | critical_exit(); | ||||
} | } | ||||
void | void | ||||
vfp_restore_state(void) | vfp_restore_state(void) | ||||
{ | { | ||||
struct pcb *curpcb; | struct pcb *curpcb; | ||||
u_int cpu; | u_int cpu; | ||||
▲ Show 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct pcb *curpcb; | struct pcb *curpcb; | ||||
if ((curthread->td_pflags & TDP_KTHREAD) == 0) | if ((curthread->td_pflags & TDP_KTHREAD) == 0) | ||||
return (0); | return (0); | ||||
curpcb = curthread->td_pcb; | curpcb = curthread->td_pcb; | ||||
return ((curpcb->pcb_fpflags & PCB_FP_KERN) != 0); | return ((curpcb->pcb_fpflags & PCB_FP_KERN) != 0); | ||||
} | } | ||||
#endif | #endif | ||||
andrew: I don't think this is needed in the `!VFP` case. It resets values that should only ever be used… | |||||
Done Inline ActionsIf an interrupt that causes the thread to switch to a new CPU we could end up with an inconsistent state. The simplest fix is to move this critical_enter call to above the bzero. I think it would also work to call vfp_discard first, then clear the state as this will ensure the VFP unit is off. andrew: If an interrupt that causes the thread to switch to a new CPU we could end up with an… |
I don't think this is needed in the !VFP case. It resets values that should only ever be used when the VFP is present and the kernel is built to use it.
If this is the case it could be renamed to vfp_reset_state and moved to be near vfp_save_state.