aboutsummaryrefslogtreecommitdiff
path: root/sys/arm64
diff options
context:
space:
mode:
authorMichal Meloun <mmel@FreeBSD.org>2021-01-23 20:19:07 +0000
committerMichal Meloun <mmel@FreeBSD.org>2021-02-03 15:27:30 +0000
commit65618fdda0f272a823e6701966421bdca0efa301 (patch)
treec44669bc7fa402f74f068f42efea4d95413c6cc2 /sys/arm64
parentc1b1354789bb15713944f9e6941266de4cb47772 (diff)
downloadsrc-65618fdda0f272a823e6701966421bdca0efa301.tar.gz
src-65618fdda0f272a823e6701966421bdca0efa301.zip
arm64: Initialize VFP control register.
The RW fields in this register reset to architecturally unknown values, so initialize these to the proper rounding and denormal mode. MFC after: 1 week
Diffstat (limited to 'sys/arm64')
-rw-r--r--sys/arm64/arm64/vfp.c4
-rw-r--r--sys/arm64/arm64/vm_machdep.c3
-rw-r--r--sys/arm64/include/md_var.h2
-rw-r--r--sys/arm64/include/vfp.h23
4 files changed, 32 insertions, 0 deletions
diff --git a/sys/arm64/arm64/vfp.c b/sys/arm64/arm64/vfp.c
index 51fba7a8a300..62244ddc80e8 100644
--- a/sys/arm64/arm64/vfp.c
+++ b/sys/arm64/arm64/vfp.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#include <sys/proc.h>
#include <machine/armreg.h>
+#include <machine/md_var.h>
#include <machine/pcb.h>
#include <machine/vfp.h>
@@ -238,6 +239,9 @@ vfp_init(void)
/* Disable to be enabled when it's used */
vfp_disable();
+
+ if (PCPU_GET(cpuid) == 0)
+ thread0.td_pcb->pcb_fpusaved->vfp_fpcr = initial_fpcr;
}
SYSINIT(vfp, SI_SUB_CPU, SI_ORDER_ANY, vfp_init, NULL);
diff --git a/sys/arm64/arm64/vm_machdep.c b/sys/arm64/arm64/vm_machdep.c
index 90d628a7d6ee..9e9b588c7db1 100644
--- a/sys/arm64/arm64/vm_machdep.c
+++ b/sys/arm64/arm64/vm_machdep.c
@@ -55,6 +55,8 @@ __FBSDID("$FreeBSD$");
#include <machine/vfp.h>
#endif
+uint32_t initial_fpcr = VFPCR_DN | VFPCR_FZ;
+
#include <dev/psci/psci.h>
/*
@@ -106,6 +108,7 @@ 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/md_var.h b/sys/arm64/include/md_var.h
index 0132ab0dd8fd..73cf642148b5 100644
--- a/sys/arm64/include/md_var.h
+++ b/sys/arm64/include/md_var.h
@@ -54,4 +54,6 @@ void generic_bs_poke_2(void) __asm(__STRING(generic_bs_poke_2));
void generic_bs_poke_4(void) __asm(__STRING(generic_bs_poke_4));
void generic_bs_poke_8(void) __asm(__STRING(generic_bs_poke_8));
+extern uint32_t initial_fpcr;
+
#endif /* !_MACHINE_MD_VAR_H_ */
diff --git a/sys/arm64/include/vfp.h b/sys/arm64/include/vfp.h
index b4b9bb524d30..b0ba01a2a319 100644
--- a/sys/arm64/include/vfp.h
+++ b/sys/arm64/include/vfp.h
@@ -32,6 +32,29 @@
#ifndef _MACHINE_VFP_H_
#define _MACHINE_VFP_H_
+/* VFPCR */
+#define VFPCR_AHP (0x04000000) /* alt. half-precision: */
+#define VFPCR_DN (0x02000000) /* default NaN enable */
+#define VFPCR_FZ (0x01000000) /* flush to zero enabled */
+
+#define VFPCR_RMODE_OFF 22 /* rounding mode offset */
+#define VFPCR_RMODE_MASK (0x00c00000) /* rounding mode mask */
+#define VFPCR_RMODE_RN (0x00000000) /* round nearest */
+#define VFPCR_RMODE_RPI (0x00400000) /* round to plus infinity */
+#define VFPCR_RMODE_RNI (0x00800000) /* round to neg infinity */
+#define VFPCR_RMODE_RM (0x00c00000) /* round to zero */
+
+#define VFPCR_STRIDE_OFF 20 /* vector stride -1 */
+#define VFPCR_STRIDE_MASK (0x00300000)
+#define VFPCR_LEN_OFF 16 /* vector length -1 */
+#define VFPCR_LEN_MASK (0x00070000)
+#define VFPCR_IDE (0x00008000) /* input subnormal exc enable */
+#define VFPCR_IXE (0x00001000) /* inexact exception enable */
+#define VFPCR_UFE (0x00000800) /* underflow exception enable */
+#define VFPCR_OFE (0x00000400) /* overflow exception enable */
+#define VFPCR_DZE (0x00000200) /* div by zero exception en */
+#define VFPCR_IOE (0x00000100) /* invalid op exec enable */
+
#ifndef LOCORE
struct vfpstate {
__uint128_t vfp_regs[32];