Module Name: src
Committed By: matt
Date: Sun Aug 12 05:05:48 UTC 2012
Modified Files:
src/sys/arch/arm/arm: arm_machdep.c undefined.c
src/sys/arch/arm/arm32: cpu.c cpuswitch.S sys_machdep.c vm_machdep.c
src/sys/arch/arm/conf: files.arm
src/sys/arch/arm/include: cpu.h pcb.h proc.h sysarch.h types.h
src/sys/arch/arm/vfp: vfp_init.c
Removed Files:
src/sys/arch/arm/include: vfpvar.h
Log Message:
Rework VFP support to use PCU.
Add emulation of instruction which save/restore the VFP FPSCR.
Add a sysarch hook to VFP FPSCR manipulation.
[The emulation will be used by libc to store/fetch exception modes and
rounding mode on a per-thread basis.]
To generate a diff of this commit:
cvs rdiff -u -r1.31 -r1.32 src/sys/arch/arm/arm/arm_machdep.c
cvs rdiff -u -r1.45 -r1.46 src/sys/arch/arm/arm/undefined.c
cvs rdiff -u -r1.82 -r1.83 src/sys/arch/arm/arm32/cpu.c
cvs rdiff -u -r1.63 -r1.64 src/sys/arch/arm/arm32/cpuswitch.S
cvs rdiff -u -r1.14 -r1.15 src/sys/arch/arm/arm32/sys_machdep.c
cvs rdiff -u -r1.57 -r1.58 src/sys/arch/arm/arm32/vm_machdep.c
cvs rdiff -u -r1.107 -r1.108 src/sys/arch/arm/conf/files.arm
cvs rdiff -u -r1.65 -r1.66 src/sys/arch/arm/include/cpu.h
cvs rdiff -u -r1.21 -r1.22 src/sys/arch/arm/include/pcb.h
cvs rdiff -u -r1.10 -r1.11 src/sys/arch/arm/include/proc.h
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/include/sysarch.h
cvs rdiff -u -r1.22 -r1.23 src/sys/arch/arm/include/types.h
cvs rdiff -u -r1.1 -r0 src/sys/arch/arm/include/vfpvar.h
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/vfp/vfp_init.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/arm/arm_machdep.c
diff -u src/sys/arch/arm/arm/arm_machdep.c:1.31 src/sys/arch/arm/arm/arm_machdep.c:1.32
--- src/sys/arch/arm/arm/arm_machdep.c:1.31 Sun Feb 19 21:06:04 2012
+++ src/sys/arch/arm/arm/arm_machdep.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: arm_machdep.c,v 1.31 2012/02/19 21:06:04 rmind Exp $ */
+/* $NetBSD: arm_machdep.c,v 1.32 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
@@ -78,7 +78,7 @@
#include <sys/param.h>
-__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.31 2012/02/19 21:06:04 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: arm_machdep.c,v 1.32 2012/08/12 05:05:47 matt Exp $");
#include <sys/exec.h>
#include <sys/proc.h>
@@ -109,6 +109,12 @@ struct cpu_info cpu_info_store = {
#endif
};
+const pcu_ops_t * const pcu_ops_md_defs[PCU_UNIT_COUNT] = {
+#if defined(FPU_VFP)
+ [PCU_FPU] = &arm_vfp_ops,
+#endif
+};
+
/*
* The ARM architecture places the vector page at address 0.
* Later ARM architecture versions, however, allow it to be
@@ -174,9 +180,7 @@ setregs(struct lwp *l, struct exec_packa
#endif
pcb->pcb_flags = 0;
#ifdef FPU_VFP
- l->l_md.md_flags &= ~MDP_VFPUSED;
- if (pcb->pcb_vfpcpu != NULL)
- vfp_saveregs_lwp(l, 0);
+ vfp_discardcontext();
#endif
}
Index: src/sys/arch/arm/arm/undefined.c
diff -u src/sys/arch/arm/arm/undefined.c:1.45 src/sys/arch/arm/arm/undefined.c:1.46
--- src/sys/arch/arm/arm/undefined.c:1.45 Sat Aug 11 07:05:57 2012
+++ src/sys/arch/arm/arm/undefined.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: undefined.c,v 1.45 2012/08/11 07:05:57 matt Exp $ */
+/* $NetBSD: undefined.c,v 1.46 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 2001 Ben Harris.
@@ -54,9 +54,9 @@
#include <sys/kgdb.h>
#endif
-__KERNEL_RCSID(0, "$NetBSD: undefined.c,v 1.45 2012/08/11 07:05:57 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: undefined.c,v 1.46 2012/08/12 05:05:47 matt Exp $");
-#include <sys/malloc.h>
+#include <sys/kmem.h>
#include <sys/queue.h>
#include <sys/signal.h>
#include <sys/systm.h>
@@ -99,8 +99,7 @@ install_coproc_handler(int coproc, undef
KASSERT(coproc >= 0 && coproc < NUM_UNKNOWN_HANDLERS);
KASSERT(handler != NULL); /* Used to be legal. */
- /* XXX: M_TEMP??? */
- uh = malloc(sizeof(*uh), M_TEMP, M_WAITOK);
+ uh = kmem_alloc(sizeof(*uh), KM_SLEEP);
uh->uh_handler = handler;
install_coproc_handler_static(coproc, uh);
return uh;
@@ -119,7 +118,7 @@ remove_coproc_handler(void *cookie)
struct undefined_handler *uh = cookie;
LIST_REMOVE(uh, uh_link);
- free(uh, M_TEMP);
+ kmem_free(uh, sizeof(*uh));
}
static struct evcnt cp15_ev =
Index: src/sys/arch/arm/arm32/cpu.c
diff -u src/sys/arch/arm/arm32/cpu.c:1.82 src/sys/arch/arm/arm32/cpu.c:1.83
--- src/sys/arch/arm/arm32/cpu.c:1.82 Sat Jul 14 07:55:28 2012
+++ src/sys/arch/arm/arm32/cpu.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: cpu.c,v 1.82 2012/07/14 07:55:28 matt Exp $ */
+/* $NetBSD: cpu.c,v 1.83 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1995 Mark Brinicombe.
@@ -46,7 +46,7 @@
#include <sys/param.h>
-__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.82 2012/07/14 07:55:28 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.83 2012/08/12 05:05:47 matt Exp $");
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -64,10 +64,6 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.82
#include <arm/fpe-arm/armfpe.h>
#endif
-#ifdef FPU_VFP
-#include <arm/vfpvar.h>
-#endif
-
char cpu_model[256];
/* Prototypes */
@@ -161,9 +157,7 @@ cpu_attach(struct device *dv)
initialise_arm_fpe();
#endif
-#ifdef FPU_VFP
vfp_attach();
-#endif
}
enum cpu_class {
Index: src/sys/arch/arm/arm32/cpuswitch.S
diff -u src/sys/arch/arm/arm32/cpuswitch.S:1.63 src/sys/arch/arm/arm32/cpuswitch.S:1.64
--- src/sys/arch/arm/arm32/cpuswitch.S:1.63 Thu Apr 7 10:03:47 2011
+++ src/sys/arch/arm/arm32/cpuswitch.S Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: cpuswitch.S,v 1.63 2011/04/07 10:03:47 matt Exp $ */
+/* $NetBSD: cpuswitch.S,v 1.64 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright 2003 Wasabi Systems, Inc.
@@ -89,7 +89,7 @@
#include <machine/asm.h>
#include <machine/cpu.h>
- RCSID("$NetBSD: cpuswitch.S,v 1.63 2011/04/07 10:03:47 matt Exp $")
+ RCSID("$NetBSD: cpuswitch.S,v 1.64 2012/08/12 05:05:47 matt Exp $")
/* LINTSTUB: include <sys/param.h> */
@@ -235,15 +235,6 @@ ENTRY(cpu_switchto)
/* rem: r7 = new pcb */
/* rem: interrupts are enabled */
-#ifdef FPU_VFP
- /*
- * Now's a good time to 'save' the VFP context. Note that we
- * don't really force a save here, which can save time if we
- * end up restarting the same context.
- */
- bl _C_LABEL(vfp_savecontext)
-#endif
-
/* Restore saved context */
.Ldo_switch:
@@ -290,10 +281,6 @@ ENTRY(cpu_switchto)
/* rem: r6 = new lwp */
/* rem: r7 = new pcb */
-#ifdef FPU_VFP
- mov r0, r6
- bl _C_LABEL(vfp_loadcontext)
-#endif
#ifdef ARMFPE
add r0, r7, #(PCB_SIZE) & 0x00ff
add r0, r0, #(PCB_SIZE) & 0xff00
Index: src/sys/arch/arm/arm32/sys_machdep.c
diff -u src/sys/arch/arm/arm32/sys_machdep.c:1.14 src/sys/arch/arm/arm32/sys_machdep.c:1.15
--- src/sys/arch/arm/arm32/sys_machdep.c:1.14 Thu Nov 17 15:02:22 2011
+++ src/sys/arch/arm/arm32/sys_machdep.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: sys_machdep.c,v 1.14 2011/11/17 15:02:22 joerg Exp $ */
+/* $NetBSD: sys_machdep.c,v 1.15 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1995-1997 Mark Brinicombe.
@@ -41,7 +41,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.14 2011/11/17 15:02:22 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_machdep.c,v 1.15 2012/08/12 05:05:47 matt Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -54,10 +54,13 @@ __KERNEL_RCSID(0, "$NetBSD: sys_machdep.
#include <sys/syscallargs.h>
#include <machine/sysarch.h>
+#include <machine/pcb.h>
+#include <arm/vfpreg.h>
/* Prototypes */
static int arm32_sync_icache(struct lwp *, const void *, register_t *);
static int arm32_drain_writebuf(struct lwp *, const void *, register_t *);
+static int arm32_vfp_fpscr(struct lwp *, const void *, register_t *);
static int
arm32_sync_icache(struct lwp *l, const void *args, register_t *retval)
@@ -86,6 +89,34 @@ arm32_drain_writebuf(struct lwp *l, cons
return(0);
}
+static int
+arm32_vfp_fpscr(struct lwp *l, const void *uap, register_t *retval)
+{
+ struct pcb * const pcb = lwp_getpcb(l);
+
+#ifdef FPU_VFP
+ /*
+ * Save the current VFP state (to make sure the FPSCR copy is
+ * up to date).
+ */
+ vfp_savecontext();
+#endif
+
+ retval[0] = pcb->pcb_vfp.vfp_fpscr;
+ if (uap) {
+ struct arm_vfp_fpscr_args ua;
+ int error;
+ if ((error = copyin(uap, &ua, sizeof(ua))) != 0)
+ return (error);
+ if (((ua.fpscr_clear|ua.fpscr_set) & ~VFP_FPSCR_RMODE) != 0)
+ return EINVAL;
+ pcb->pcb_vfp.vfp_fpscr &= ~ua.fpscr_clear;
+ pcb->pcb_vfp.vfp_fpscr |= ua.fpscr_set;
+ }
+
+ return 0;
+}
+
int
sys_sysarch(struct lwp *l, const struct sys_sysarch_args *uap, register_t *retval)
{
@@ -104,6 +135,10 @@ sys_sysarch(struct lwp *l, const struct
error = arm32_drain_writebuf(l, SCARG(uap, parms), retval);
break;
+ case ARM_VFP_FPSCR :
+ error = arm32_vfp_fpscr(l, SCARG(uap, parms), retval);
+ break;
+
default:
error = EINVAL;
break;
Index: src/sys/arch/arm/arm32/vm_machdep.c
diff -u src/sys/arch/arm/arm32/vm_machdep.c:1.57 src/sys/arch/arm/arm32/vm_machdep.c:1.58
--- src/sys/arch/arm/arm32/vm_machdep.c:1.57 Fri Aug 3 07:59:22 2012
+++ src/sys/arch/arm/arm32/vm_machdep.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: vm_machdep.c,v 1.57 2012/08/03 07:59:22 matt Exp $ */
+/* $NetBSD: vm_machdep.c,v 1.58 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1994-1998 Mark Brinicombe.
@@ -44,7 +44,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.57 2012/08/03 07:59:22 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vm_machdep.c,v 1.58 2012/08/12 05:05:47 matt Exp $");
#include "opt_armfpe.h"
#include "opt_pmap_debug.h"
@@ -137,16 +137,7 @@ cpu_lwp_fork(struct lwp *l1, struct lwp
}
#endif
- l2->l_md.md_flags = l1->l_md.md_flags & MDP_VFPUSED;
-
-#ifdef FPU_VFP
- /*
- * Copy the floating point state from the VFP to the PCB
- * if this process has state stored there.
- */
- if (pcb1->pcb_vfpcpu != NULL)
- vfp_saveregs_lwp(l1, 1);
-#endif
+ l2->l_md.md_flags = l1->l_md.md_flags & MDLWP_VFPUSED;
/* Copy the pcb */
*pcb2 = *pcb1;
@@ -209,22 +200,12 @@ cpu_lwp_fork(struct lwp *l1, struct lwp
void
cpu_lwp_free(struct lwp *l, int proc)
{
-#ifdef FPU_VFP
- struct pcb *pcb;
-#endif
-
#ifdef ARMFPE
/* Abort any active FP operation and deactivate the context */
arm_fpe_core_abort(FP_CONTEXT(l), NULL, NULL);
arm_fpe_core_changecontext(0);
#endif /* ARMFPE */
-#ifdef FPU_VFP
- pcb = lwp_getpcb(l);
- if (pcb->pcb_vfpcpu != NULL)
- vfp_saveregs_lwp(l, 0);
-#endif
-
#ifdef STACKCHECKS
/* Report how much stack has been used - debugging */
if (l) {
Index: src/sys/arch/arm/conf/files.arm
diff -u src/sys/arch/arm/conf/files.arm:1.107 src/sys/arch/arm/conf/files.arm:1.108
--- src/sys/arch/arm/conf/files.arm:1.107 Fri Aug 3 07:59:22 2012
+++ src/sys/arch/arm/conf/files.arm Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-# $NetBSD: files.arm,v 1.107 2012/08/03 07:59:22 matt Exp $
+# $NetBSD: files.arm,v 1.108 2012/08/12 05:05:47 matt Exp $
# temporary define to allow easy moving to ../arch/arm/arm32
defflag ARM32
@@ -54,7 +54,7 @@ file arch/arm/fpe-arm/armfpe_init.c arm
file arch/arm/fpe-arm/armfpe.S armfpe
# VFP support
-file arch/arm/vfp/vfp_init.c fpu_vfp
+file arch/arm/vfp/vfp_init.c arm32
# PMAP_DEBUG (heavily abused option)
defflag PMAP_DEBUG
Index: src/sys/arch/arm/include/cpu.h
diff -u src/sys/arch/arm/include/cpu.h:1.65 src/sys/arch/arm/include/cpu.h:1.66
--- src/sys/arch/arm/include/cpu.h:1.65 Thu Aug 2 15:56:07 2012
+++ src/sys/arch/arm/include/cpu.h Sun Aug 12 05:05:47 2012
@@ -78,9 +78,6 @@
#ifndef _LOCORE
#include <machine/frame.h>
#include <machine/pcb.h>
-#ifdef FPU_VFP
-#include <arm/vfpvar.h>
-#endif
#endif /* !_LOCORE */
#include <arm/armreg.h>
@@ -258,12 +255,10 @@ struct cpu_info {
struct evcnt ci_arm700bugcount;
int32_t ci_mtx_count;
int ci_mtx_oldspl;
+ uint32_t ci_vfp_id;
#ifdef MULTIPROCESSOR
MP_CPU_INFO_MEMBERS
#endif
-#ifdef FPU_VFP
- struct vfp_info ci_vfp;
-#endif
};
#ifndef MULTIPROCESSOR
@@ -397,6 +392,12 @@ void swi_handler(trapframe_t *);
/* arm_machdep.c */
void ucas_ras_check(trapframe_t *);
+/* vfp_init.c */
+void vfp_attach(void);
+void vfp_discardcontext(void);
+void vfp_savecontext(void);
+extern const pcu_ops_t arm_vfp_ops;
+
#endif /* !_LOCORE */
#endif /* _KERNEL */
Index: src/sys/arch/arm/include/pcb.h
diff -u src/sys/arch/arm/include/pcb.h:1.21 src/sys/arch/arm/include/pcb.h:1.22
--- src/sys/arch/arm/include/pcb.h:1.21 Wed Aug 8 16:09:42 2012
+++ src/sys/arch/arm/include/pcb.h Sun Aug 12 05:05:47 2012
@@ -94,7 +94,6 @@ struct pcb {
} pcb_un;
struct fpe_sp_state pcb_fpstate; /* FPA Floating Point state */
struct vfpreg pcb_vfp; /* VFP registers */
- struct cpu_info *pcb_vfpcpu; /* CPU holding VFP state */
};
#define pcb_ff pcb_fpstate /* for arm26 */
Index: src/sys/arch/arm/include/proc.h
diff -u src/sys/arch/arm/include/proc.h:1.10 src/sys/arch/arm/include/proc.h:1.11
--- src/sys/arch/arm/include/proc.h:1.10 Fri Jan 14 02:06:24 2011
+++ src/sys/arch/arm/include/proc.h Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: proc.h,v 1.10 2011/01/14 02:06:24 rmind Exp $ */
+/* $NetBSD: proc.h,v 1.11 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1994 Mark Brinicombe.
@@ -47,7 +47,7 @@ struct mdlwp {
};
/* Flags setttings for md_flags */
-#define MDP_VFPUSED 0x00000001 /* Process used the VFP */
+#define MDLWP_VFPUSED 0x00000001 /* Process used the VFP */
struct mdproc {
Index: src/sys/arch/arm/include/sysarch.h
diff -u src/sys/arch/arm/include/sysarch.h:1.7 src/sys/arch/arm/include/sysarch.h:1.8
--- src/sys/arch/arm/include/sysarch.h:1.7 Sat Mar 14 14:45:55 2009
+++ src/sys/arch/arm/include/sysarch.h Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: sysarch.h,v 1.7 2009/03/14 14:45:55 dsl Exp $ */
+/* $NetBSD: sysarch.h,v 1.8 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1996-1997 Mark Brinicombe.
@@ -48,12 +48,18 @@
#define ARM_SYNC_ICACHE 0
#define ARM_DRAIN_WRITEBUF 1
+#define ARM_VFP_FPSCR 2
struct arm_sync_icache_args {
uintptr_t addr; /* Virtual start address */
size_t len; /* Region size */
};
+struct arm_vfp_fpscr_args {
+ uint32_t fpscr_clear; /* bits to clear */
+ uint32_t fpscr_set; /* bits to set */
+};
+
#ifndef _KERNEL
__BEGIN_DECLS
int arm_sync_icache(u_int addr, int len);
Index: src/sys/arch/arm/include/types.h
diff -u src/sys/arch/arm/include/types.h:1.22 src/sys/arch/arm/include/types.h:1.23
--- src/sys/arch/arm/include/types.h:1.22 Fri Aug 3 07:59:23 2012
+++ src/sys/arch/arm/include/types.h Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: types.h,v 1.22 2012/08/03 07:59:23 matt Exp $ */
+/* $NetBSD: types.h,v 1.23 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 1990 The Regents of the University of California.
@@ -89,6 +89,11 @@ typedef volatile int __cpu_simple_lock_
#define __HAVE_COMMON___TLS_GET_ADDR
#define __HAVE_TLS_VARIANT_I
+#if defined(_KERNEL) || defined(_KMEMUSER)
+#define PCU_FPU 0
+#define PCU_UNIT_COUNT 1
+#endif
+
#if defined(_KERNEL)
#define __HAVE_RAS
#endif
Index: src/sys/arch/arm/vfp/vfp_init.c
diff -u src/sys/arch/arm/vfp/vfp_init.c:1.3 src/sys/arch/arm/vfp/vfp_init.c:1.4
--- src/sys/arch/arm/vfp/vfp_init.c:1.3 Sat Nov 21 20:32:28 2009
+++ src/sys/arch/arm/vfp/vfp_init.c Sun Aug 12 05:05:47 2012
@@ -1,4 +1,4 @@
-/* $NetBSD: vfp_init.c,v 1.3 2009/11/21 20:32:28 rmind Exp $ */
+/* $NetBSD: vfp_init.c,v 1.4 2012/08/12 05:05:47 matt Exp $ */
/*
* Copyright (c) 2008 ARM Ltd
@@ -34,11 +34,9 @@
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
+#include <sys/cpu.h>
#include <arm/undefined.h>
-#include <machine/cpu.h>
-
-#include <arm/vfpvar.h>
#include <arm/vfpreg.h>
/*
@@ -46,20 +44,50 @@
*/
/* FMRX <X>, fpsid */
-#define read_fpsid(X) __asm __volatile("mrc p10, 7, %0, c0, c0, 0" \
- : "=r" (*(X)) : : "memory")
-/* FMRX <X>, fpscr */
-#define read_fpscr(X) __asm __volatile("mrc p10, 7, %0, c1, c0, 0" \
- : "=r" (*(X)))
+static inline uint32_t
+read_fpsid(void)
+{
+ uint32_t rv;
+ __asm __volatile("mrc p10, 7, %0, c0, c0, 0" : "=r" (rv));
+ return rv;
+}
+
+/* FMRX <X>, fpexc */
+static inline uint32_t
+read_fpscr(void)
+{
+ uint32_t rv;
+ __asm __volatile("mrc p10, 7, %0, c1, c0, 0" : "=r" (rv));
+ return rv;
+}
+
/* FMRX <X>, fpexc */
-#define read_fpexc(X) __asm __volatile("mrc p10, 7, %0, c8, c0, 0" \
- : "=r" (*(X)))
+static inline uint32_t
+read_fpexc(void)
+{
+ uint32_t rv;
+ __asm __volatile("mrc p10, 7, %0, c8, c0, 0" : "=r" (rv));
+ return rv;
+}
+
/* FMRX <X>, fpinst */
-#define read_fpinst(X) __asm __volatile("mrc p10, 7, %0, c9, c0, 0" \
- : "=r" (*(X)))
+static inline uint32_t
+read_fpinst(void)
+{
+ uint32_t rv;
+ __asm __volatile("mrc p10, 7, %0, c9, c0, 0" : "=r" (rv));
+ return rv;
+}
+
/* FMRX <X>, fpinst2 */
-#define read_fpinst2(X) __asm __volatile("mrc p10, 7, %0, c10, c0, 0" \
- : "=r" (*(X)))
+static inline uint32_t
+read_fpinst2(void)
+{
+ uint32_t rv;
+ __asm __volatile("mrc p10, 7, %0, c10, c0, 0" : "=r" (rv));
+ return rv;
+}
+
/* FSTMD <X>, {d0-d15} */
#define save_vfpregs(X) __asm __volatile("stc p11, c0, [%0], {32}" : \
: "r" (X) : "memory")
@@ -80,10 +108,22 @@
#define load_vfpregs(X) __asm __volatile("ldc p11, c0, [%0], {32}" : \
: "r" (X) : "memory");
+#ifdef FPU_VFP
+
/* The real handler for VFP bounces. */
static int vfp_handler(u_int, u_int, trapframe_t *, int);
+static int vfp_handler(u_int, u_int, trapframe_t *, int);
-static void vfp_load_regs(struct vfpreg *);
+static void vfp_state_load(lwp_t *, bool);
+static void vfp_state_save(lwp_t *);
+static void vfp_state_release(lwp_t *);
+
+const pcu_ops_t arm_vfp_ops = {
+ .pcu_id = PCU_FPU,
+ .pcu_state_load = vfp_state_load,
+ .pcu_state_save = vfp_state_save,
+ .pcu_state_release = vfp_state_release,
+};
struct evcnt vfpevent_use;
struct evcnt vfpevent_reuse;
@@ -98,51 +138,114 @@ struct evcnt vfpevent_reuse;
static int undefined_test;
static int
-vfp_test(u_int address, u_int instruction, trapframe_t *frame, int fault_code)
+vfp_test(u_int address, u_int insn, trapframe_t *frame, int fault_code)
{
frame->tf_pc += INSN_SIZE;
++undefined_test;
- return(0);
+ return 0;
+}
+
+#endif /* FPU_VFP */
+
+struct evcnt vfp_fpscr_ev =
+ EVCNT_INITIALIZER(EVCNT_TYPE_TRAP, NULL, "VFP", "FPSCR traps");
+EVCNT_ATTACH_STATIC(vfp_fpscr_ev);
+
+static int
+vfp_fpscr_handler(u_int address, u_int insn, trapframe_t *frame, int fault_code)
+{
+ struct lwp * const l = curlwp;
+ const u_int regno = (insn >> 12) & 0xf;
+ /*
+ * Only match move to/from the FPSCR register and we
+ * can't be using the SP,LR,PC as a source.
+ */
+ if ((insn & 0xffef0fff) != 0xeee10a10 || regno > 12)
+ return 1;
+
+ struct pcb * const pcb = lwp_getpcb(l);
+
+#ifdef FPU_VFP
+ /*
+ * If FPU is valid somewhere, let's just reenable VFP and
+ * retry the instruction (only safe thing to do since the
+ * pcb has a stale copy).
+ */
+ if (pcb->pcb_vfp.vfp_fpexc & VFP_FPEXC_EN)
+ return 1;
+#endif
+
+ if (__predict_false((l->l_md.md_flags & MDLWP_VFPUSED) == 0)) {
+ l->l_md.md_flags |= MDLWP_VFPUSED;
+ pcb->pcb_vfp.vfp_fpscr =
+ (VFP_FPSCR_DN | VFP_FPSCR_FZ); /* Runfast */
+ }
+
+ /*
+ * We know know the pcb has the saved copy.
+ */
+ register_t * const regp = &frame->tf_r0 + regno;
+ if (insn & 0x00100000) {
+ *regp = pcb->pcb_vfp.vfp_fpscr;
+ } else {
+ pcb->pcb_vfp.vfp_fpscr = *regp;
+ }
+
+ vfp_fpscr_ev.ev_count++;
+
+ frame->tf_pc += INSN_SIZE;
+ return 0;
}
+#ifndef FPU_VFP
+/*
+ * If we don't want VFP support, we still need to handle emulating VFP FPSCR
+ * instructions.
+ */
void
vfp_attach(void)
{
- void *uh;
- uint32_t fpsid;
+ install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
+}
+
+#else
+void
+vfp_attach(void)
+{
+ struct cpu_info * const ci = curcpu();
const char *model = NULL;
+ void *uh;
uh = install_coproc_handler(VFP_COPROC, vfp_test);
undefined_test = 0;
- read_fpsid(&fpsid);
+ const uint32_t fpsid = read_fpsid();
remove_coproc_handler(uh);
if (undefined_test != 0) {
- aprint_normal("%s: No VFP detected\n",
- curcpu()->ci_dev->dv_xname);
- curcpu()->ci_vfp.vfp_id = 0;
+ aprint_normal_dev(ci->ci_dev, "No VFP detected\n");
+ install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
+ ci->ci_vfp_id = 0;
return;
}
- curcpu()->ci_vfp.vfp_id = fpsid;
- switch (fpsid & ~ VFP_FPSID_REV_MSK)
- {
- case FPU_VFP10_ARM10E:
- model = "VFP10 R1";
- break;
- case FPU_VFP11_ARM11:
- model = "VFP11";
- break;
- default:
- aprint_normal("%s: unrecognized VFP version %x\n",
- curcpu()->ci_dev->dv_xname, fpsid);
- fpsid = 0; /* Not recognised. */
- return;
- }
+ ci->ci_vfp_id = fpsid;
+ switch (fpsid & ~ VFP_FPSID_REV_MSK) {
+ case FPU_VFP10_ARM10E:
+ model = "VFP10 R1";
+ break;
+ case FPU_VFP11_ARM11:
+ model = "VFP11";
+ break;
+ default:
+ aprint_normal_dev(ci->ci_dev, "unrecognized VFP version %x\n",
+ fpsid);
+ install_coproc_handler(VFP_COPROC, vfp_fpscr_handler);
+ return;
+ }
if (fpsid != 0) {
aprint_normal("vfp%d at %s: %s\n",
@@ -158,54 +261,38 @@ vfp_attach(void)
}
/* The real handler for VFP bounces. */
-static int vfp_handler(u_int address, u_int instruction, trapframe_t *frame,
+static int
+vfp_handler(u_int address, u_int insn, trapframe_t *frame,
int fault_code)
{
- struct cpu_info *ci = curcpu();
- struct pcb *pcb;
- struct lwp *l;
+ struct cpu_info * const ci = curcpu();
/* This shouldn't ever happen. */
if (fault_code != FAULT_USER)
panic("VFP fault in non-user mode");
- if (ci->ci_vfp.vfp_id == 0)
+ if (ci->ci_vfp_id == 0)
/* No VFP detected, just fault. */
return 1;
- l = curlwp;
- pcb = lwp_getpcb(l);
-
- if ((l->l_md.md_flags & MDP_VFPUSED) && ci->ci_vfp.vfp_fpcurlwp == l) {
- uint32_t fpexc;
-
- printf("VFP bounce @%x (insn=%x) lwp=%p\n", address,
- instruction, l);
- read_fpexc(&fpexc);
- if ((fpexc & VFP_FPEXC_EN) == 0)
- printf("vfp not enabled\n");
- vfp_saveregs_lwp(l, 1);
- printf(" fpexc = 0x%08x fpscr = 0x%08x\n", fpexc,
- pcb->pcb_vfp.vfp_fpscr);
- printf(" fpinst = 0x%08x fpinst2 = 0x%08x\n",
- pcb->pcb_vfp.vfp_fpinst,
- pcb->pcb_vfp.vfp_fpinst2);
- return 1;
- }
-
- if (ci->ci_vfp.vfp_fpcurlwp != NULL)
- vfp_saveregs_cpu(ci, 1);
-
- KDASSERT(ci->ci_vfp.vfp_fpcurlwp == NULL);
-
- KDASSERT(pcb->pcb_vfpcpu == NULL);
+ /*
+ * If we are just changing/fetching FPSCR, don't bother loading it.
+ */
+ if (!vfp_fpscr_handler(address, insn, frame, fault_code))
+ return 0;
-// VFPCPU_LOCK(pcb, s);
+ pcu_load(&arm_vfp_ops);
- pcb->pcb_vfpcpu = ci;
- ci->ci_vfp.vfp_fpcurlwp = l;
+ /* Need to restart the faulted instruction. */
+// frame->tf_pc -= INSN_SIZE;
+ return 0;
+}
-// VFPCPU_UNLOCK(pcb, s);
+static void
+vfp_state_load(lwp_t *l, bool used)
+{
+ struct pcb * const pcb = lwp_getpcb(l);
+ struct vfpreg * const fregs = &pcb->pcb_vfp;
/*
* Instrument VFP usage -- if a process has not previously
@@ -215,150 +302,128 @@ static int vfp_handler(u_int address, u_
* If a process has used the VFP, count a "used VFP, and took
* a trap to use it again" event.
*/
- if ((l->l_md.md_flags & MDP_VFPUSED) == 0) {
+ if (__predict_false((l->l_md.md_flags & MDLWP_VFPUSED) == 0)) {
vfpevent_use.ev_count++;
- l->l_md.md_flags |= MDP_VFPUSED;
+ l->l_md.md_flags |= MDLWP_VFPUSED;
pcb->pcb_vfp.vfp_fpscr =
(VFP_FPSCR_DN | VFP_FPSCR_FZ); /* Runfast */
- } else
+ } else {
vfpevent_reuse.ev_count++;
+ }
- vfp_load_regs(&pcb->pcb_vfp);
-
- /* Need to restart the faulted instruction. */
-// frame->tf_pc -= INSN_SIZE;
- return 0;
-}
-
-static void
-vfp_load_regs(struct vfpreg *fregs)
-{
- uint32_t fpexc;
+ if (fregs->vfp_fpexc & VFP_FPEXC_EN) {
+ /*
+ * If we think the VFP is enabled, it must have be disabled by
+ * vfp_state_release for another LWP so we can just restore
+ * FPEXC and return since our VFP state is still loaded.
+ */
+ write_fpexc(fregs->vfp_fpexc);
+ return;
+ }
/* Enable the VFP (so that we can write the registers). */
- read_fpexc(&fpexc);
+ uint32_t fpexc = read_fpexc();
KDASSERT((fpexc & VFP_FPEXC_EX) == 0);
write_fpexc(fpexc | VFP_FPEXC_EN);
load_vfpregs(fregs->vfp_regs);
write_fpscr(fregs->vfp_fpscr);
+
if (fregs->vfp_fpexc & VFP_FPEXC_EX) {
+ struct cpu_info * const ci = curcpu();
/* Need to restore the exception handling state. */
- switch (curcpu()->ci_vfp.vfp_id) {
+ switch (ci->ci_vfp_id) {
case FPU_VFP10_ARM10E:
case FPU_VFP11_ARM11:
write_fpinst2(fregs->vfp_fpinst2);
write_fpinst(fregs->vfp_fpinst);
break;
default:
- panic("vfp_load_regs: Unsupported VFP");
+ panic("%s: Unsupported VFP %#x",
+ __func__, ci->ci_vfp_id);
}
}
- /* Finally, restore the FPEXC and enable the VFP. */
- write_fpexc(fregs->vfp_fpexc | VFP_FPEXC_EN);
+
+ /* Finally, restore the FPEXC but don't enable the VFP. */
+ fregs->vfp_fpexc |= VFP_FPEXC_EN;
+ write_fpexc(fregs->vfp_fpexc);
}
void
-vfp_saveregs_cpu(struct cpu_info *ci, int save)
+vfp_state_save(lwp_t *l)
{
- struct lwp *l;
- struct pcb *pcb;
- uint32_t fpexc;
+ struct pcb * const pcb = lwp_getpcb(l);
+ struct vfpreg * const fregs = &pcb->pcb_vfp;
- KDASSERT(ci == curcpu());
-
- l = ci->ci_vfp.vfp_fpcurlwp;
- if (l == NULL)
+ /*
+ * If it's already disabled, then the state has been saved
+ * (or discarded).
+ */
+ if ((fregs->vfp_fpexc & VFP_FPEXC_EN) == 0)
return;
- pcb = lwp_getpcb(l);
- read_fpexc(&fpexc);
-
- if (save) {
- struct vfpreg *fregs = &pcb->pcb_vfp;
-
- /*
- * Enable the VFP (so we can read the registers).
- * Make sure the exception bit is cleared so that we can
- * safely dump the registers.
- */
- write_fpexc((fpexc | VFP_FPEXC_EN) & ~VFP_FPEXC_EX);
+ /*
+ * Enable the VFP (so we can read the registers).
+ * Make sure the exception bit is cleared so that we can
+ * safely dump the registers.
+ */
+ uint32_t fpexc = read_fpexc();
+ write_fpexc((fpexc | VFP_FPEXC_EN) & ~VFP_FPEXC_EX);
- fregs->vfp_fpexc = fpexc;
- if (fpexc & VFP_FPEXC_EX) {
- /* Need to save the exception handling state */
- switch (ci->ci_vfp.vfp_id) {
- case FPU_VFP10_ARM10E:
- case FPU_VFP11_ARM11:
- read_fpinst(&fregs->vfp_fpinst);
- read_fpinst2(&fregs->vfp_fpinst2);
- break;
- default:
- panic("vfp_saveregs_cpu: Unsupported VFP");
- }
+ fregs->vfp_fpexc = fpexc;
+ if (fpexc & VFP_FPEXC_EX) {
+ struct cpu_info * const ci = curcpu();
+ /* Need to save the exception handling state */
+ switch (ci->ci_vfp_id) {
+ case FPU_VFP10_ARM10E:
+ case FPU_VFP11_ARM11:
+ fregs->vfp_fpinst = read_fpinst();
+ fregs->vfp_fpinst2 = read_fpinst2();
+ break;
+ default:
+ panic("%s: Unsupported VFP %#x",
+ __func__, ci->ci_vfp_id);
}
- read_fpscr(&fregs->vfp_fpscr);
- save_vfpregs(fregs->vfp_regs);
}
- /* Disable the VFP. */
- write_fpexc(fpexc & ~VFP_FPEXC_EN);
-// VFPCPU_LOCK(pcb, s);
+ fregs->vfp_fpscr = read_fpscr();
+ save_vfpregs(fregs->vfp_regs);
- pcb->pcb_vfpcpu = NULL;
- ci->ci_vfp.vfp_fpcurlwp = NULL;
-// VFPCPU_UNLOCK(pcb, s);
+ /* Disable the VFP. */
+ write_fpexc(fpexc);
}
void
-vfp_saveregs_lwp(struct lwp *l, int save)
+vfp_state_release(lwp_t *l)
{
- struct cpu_info *ci = curcpu();
- struct cpu_info *oci;
- struct pcb *pcb;
-
- pcb = lwp_getpcb(l);
- KDASSERT(pcb != NULL);
-
-// VFPCPU_LOCK(pcb, s);
+ struct pcb * const pcb = lwp_getpcb(l);
- oci = pcb->pcb_vfpcpu;
- if (oci == NULL) {
- // VFPCPU_UNLOCK(pcb, s);
- return;
- }
+ /*
+ * Now mark the VFP as disabled (and our state has been already
+ * saved or is being discarded).
+ */
+ pcb->pcb_vfp.vfp_fpexc &= ~VFP_FPEXC_EN;
-#if defined(MULTIPROCESSOR)
/*
- * On a multiprocessor system this is where we would send an IPI
- * to the processor holding the VFP state for this process.
+ * Turn off the FPU so the next time a VFP instruction is issued
+ * an exception happens. We don't know if this LWP's state was
+ * loaded but if we turned off the FPU for some other LWP, when
+ * pcu_load invokes vfp_state_load it will see that VFP_FPEXC_EN
+ * is still set so it just restroe fpexc and return since its
+ * contents are still sitting in the VFP.
*/
-#error MULTIPROCESSOR
-#else
- KASSERT(ci->ci_vfp.vfp_fpcurlwp == l);
-// VFPCPU_UNLOCK(pcb, s);
- vfp_saveregs_cpu(ci, save);
-#endif
+ write_fpexc(read_fpexc() & ~VFP_FPEXC_EN);
}
void
vfp_savecontext(void)
{
- struct cpu_info *ci = curcpu();
- uint32_t fpexc;
-
- if (ci->ci_vfp.vfp_fpcurlwp != NULL) {
- read_fpexc(&fpexc);
- write_fpexc(fpexc & ~VFP_FPEXC_EN);
- }
+ pcu_save(&arm_vfp_ops);
}
void
-vfp_loadcontext(struct lwp *l)
+vfp_discardcontext(void)
{
- uint32_t fpexc;
-
- if (curcpu()->ci_vfp.vfp_fpcurlwp == l) {
- read_fpexc(&fpexc);
- write_fpexc(fpexc | VFP_FPEXC_EN);
- }
+ pcu_discard(&arm_vfp_ops);
}
+
+#endif /* FPU_VFP */