-/* $OpenBSD: cpu.c,v 1.44 2018/01/15 14:11:16 kettenis Exp $ */
+/* $OpenBSD: cpu.c,v 1.45 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $ */
#include <arm/cpuconf.h>
#include <arm/undefined.h>
+#include <arm/vfp.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_clock.h>
identify_arm_cpu(dev, ci);
+ vfp_init();
+
if (OF_getproplen(faa->fa_node, "clocks") > 0) {
cpu_node = faa->fa_node;
cpu_cpuspeed = cpu_clockspeed;
-/* $OpenBSD: exception.S,v 1.6 2016/09/21 11:33:05 kettenis Exp $ */
+/* $OpenBSD: exception.S,v 1.7 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: exception.S,v 1.13 2003/10/31 16:30:15 scw Exp $ */
/*
.text
.align 2
+#define RESTOREVFP \
+ ldr r0, [sp] /* Get the SPSR from stack */ ;\
+ and r0, r0, #(PSR_MODE) /* Returning to USR mode? */ ;\
+ cmp r0, #(PSR_USR32_MODE) ;\
+ bne 1f ;\
+ bl _C_LABEL(vfp_enable) ;\
+1:
+
AST_LOCALS
/*
exception_exit:
DO_AST
+ RESTOREVFP
PULLFRAMEFROMSVCANDEXIT
/*
-/* $OpenBSD: fault.c,v 1.31 2018/01/15 14:11:16 kettenis Exp $ */
+/* $OpenBSD: fault.c,v 1.32 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */
/*
#include <arm/db_machdep.h>
#include <arch/arm/arm/disassem.h>
#include <arm/machdep.h>
+#include <arm/vfp.h>
#ifdef DEBUG
int last_fault_code; /* For the benefit of pmap_fault_fixup() */
/* Update vmmeter statistics */
uvmexp.traps++;
+ /* Before enabling interrupts, save FPU state */
+ vfp_save();
+
/* Re-enable interrupts if they were enabled previously */
if (__predict_true((tf->tf_spsr & PSR_I) == 0))
enable_interrupts(PSR_I);
if (__predict_false(!TRAP_USERMODE(tf)))
dab_fatal(tf, fsr, far, NULL, NULL);
+ /* Before enabling interrupts, save FPU state */
+ vfp_save();
+
/*
* Enable IRQ's (disabled by the abort) This always comes
* from user mode so we know interrupts were not disabled.
-/* $OpenBSD: irq_dispatch.S,v 1.13 2017/01/06 00:06:02 jsg Exp $ */
+/* $OpenBSD: irq_dispatch.S,v 1.14 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: irq_dispatch.S,v 1.5 2003/10/30 08:57:24 scw Exp $ */
/*
.Lcpu_info_primary:
.word _C_LABEL(cpu_info_primary)
+#define STOREVFP \
+ bl _C_LABEL(vfp_save)
+
AST_LOCALS
ASENTRY_NP(irq_entry)
PUSHFRAMEINSVC /* Push an interrupt frame */
+ STOREVFP /* save fpu state before irq handler */
+
/*
* Increment the interrupt nesting depth and call the interrupt
* dispatch routine. We've pushed a frame, so we can safely use
-/* $OpenBSD: syscall.c,v 1.18 2016/01/31 00:14:50 jsg Exp $ */
+/* $OpenBSD: syscall.c,v 1.19 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: syscall.c,v 1.24 2003/11/14 19:03:17 scw Exp $ */
/*-
#include <machine/frame.h>
#include <machine/pcb.h>
#include <arm/swi.h>
+#include <arm/vfp.h>
#define MAXARGS 8
uvmexp.syscalls++;
+ /* Before enabling interrupts, save FPU state */
+ vfp_save();
+
/* Re-enable interrupts if they were enabled previously */
if (__predict_true((frame->tf_spsr & PSR_I) == 0))
enable_interrupts(PSR_I);
-/* $OpenBSD: undefined.c,v 1.10 2017/04/30 16:45:45 mpi Exp $ */
+/* $OpenBSD: undefined.c,v 1.11 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: undefined.c,v 1.22 2003/11/29 22:21:29 bjh21 Exp $ */
/*
#include <machine/cpu.h>
#include <machine/frame.h>
#include <arm/undefined.h>
+#include <arm/vfp.h>
#include <machine/trap.h>
#endif
union sigval sv;
+ /* Before enabling interrupts, save FPU state */
+ vfp_save();
+
/* Enable interrupts if they were enabled before the exception. */
if (!(frame->tf_spsr & PSR_I))
enable_interrupts(PSR_I);
* instruction trap.
*/
+ coprocessor = 0;
if ((fault_instruction & (1 << 27)) != 0)
coprocessor = (fault_instruction >> 8) & 0x0f;
- else
- coprocessor = 0;
+ else { /* check for special instructions */
+ if (((fault_instruction & 0xfe000000) == 0xf2000000) ||
+ ((fault_instruction & 0xff100000) == 0xf4000000))
+ coprocessor = 10; /* vfp / simd */
+ }
if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
/*
--- /dev/null
+/* $OpenBSD: vfp.c,v 1.1 2018/01/26 16:22:19 kettenis Exp $ */
+
+/*
+ * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <arm/include/cpufunc.h>
+#include <arm/include/vfp.h>
+#include <arm/include/undefined.h>
+
+static inline void
+set_vfp_fpexc(uint32_t val)
+{
+ __asm __volatile("vmsr fpexc, %0" :: "r" (val));
+}
+
+static inline uint32_t
+get_vfp_fpexc(void)
+{
+ uint32_t val;
+ __asm __volatile("vmrs %0, fpexc" : "=r" (val));
+ return val;
+}
+
+int vfp_fault(unsigned int, unsigned int, trapframe_t *, int);
+void vfp_load(struct proc *p);
+void vfp_store(struct fpreg *vfpsave);
+
+void
+vfp_init(void)
+{
+ uint32_t val;
+
+ install_coproc_handler(10, vfp_fault);
+ install_coproc_handler(11, vfp_fault);
+
+ __asm volatile("mrc p15, 0, %0, c1, c0, 2" : "=r" (val));
+ val |= COPROC10 | COPROC11;
+ __asm volatile("mcr p15, 0, %0, c1, c0, 2" :: "r" (val));
+ __asm volatile("isb");
+}
+
+void
+vfp_store(struct fpreg *vfpsave)
+{
+ uint32_t scratch;
+
+ if (get_vfp_fpexc() & VFPEXC_EN) {
+ __asm __volatile(
+ "vstmia %1!, {d0-d15}\n" /* d0-d15 */
+ "vstmia %1!, {d16-d31}\n" /* d16-d31 */
+ "vmrs %0, fpscr\n"
+ "str %0, [%1]\n" /* save vfpscr */
+ : "=&r" (scratch) : "r" (vfpsave));
+ }
+
+ /* disable FPU */
+ set_vfp_fpexc(0);
+}
+
+void
+vfp_save(void)
+{
+ struct cpu_info *ci = curcpu();
+ struct pcb *pcb = curpcb;
+ struct proc *p = curproc;
+ uint32_t cr_8;
+
+ if (ci->ci_fpuproc == 0)
+ return;
+
+ cr_8 = get_vfp_fpexc();
+
+ if ((cr_8 & VFPEXC_EN) == 0)
+ return; /* not enabled, nothing to do */
+
+ if (cr_8 & VFPEXC_EX)
+ panic("vfp exceptional data fault, time to write more code");
+
+ if (pcb->pcb_fpcpu == NULL || ci->ci_fpuproc == NULL ||
+ !(pcb->pcb_fpcpu == ci && ci->ci_fpuproc == p)) {
+ /* disable fpu before panic, otherwise recurse */
+ set_vfp_fpexc(0);
+
+ panic("FPU unit enabled when curproc and curcpu dont agree %p %p %p %p", pcb->pcb_fpcpu, ci, ci->ci_fpuproc, p);
+ }
+
+ vfp_store(&p->p_addr->u_pcb.pcb_fpstate);
+
+ /*
+ * NOTE: fpu state is saved but remains 'valid', as long as
+ * curpcb()->pcb_fpucpu == ci && ci->ci_fpuproc == curproc()
+ * is true FPU state is valid and can just be enabled without reload.
+ */
+}
+
+void
+vfp_enable(void)
+{
+ struct cpu_info *ci = curcpu();
+
+ if (curproc->p_addr->u_pcb.pcb_fpcpu == ci &&
+ ci->ci_fpuproc == curproc) {
+ disable_interrupts(PSR_I|PSR_F);
+
+ /* FPU state is still valid, just enable and go */
+ set_vfp_fpexc(VFPEXC_EN);
+ }
+}
+
+void
+vfp_load(struct proc *p)
+{
+ struct cpu_info *ci = curcpu();
+ struct pcb *pcb = &p->p_addr->u_pcb;
+ uint32_t scratch = 0;
+ int psw;
+
+ /* do not allow a partially synced state here */
+ psw = disable_interrupts(PSR_I|PSR_F);
+
+ /*
+ * p->p_pcb->pcb_fpucpu _may_ not be NULL here, but the FPU state
+ * was synced on kernel entry, so we can steal the FPU state
+ * instead of signalling and waiting for it to save
+ */
+
+ /* enable to be able to load ctx */
+ set_vfp_fpexc(VFPEXC_EN);
+
+ __asm __volatile(
+ "vldmia %1!, {d0-d15}\n" /* d0-d15 */
+ "vldmia %1!, {d16-d31}\n" /* d16-d31 */
+ "ldr %0, [%1]\n" /* set old vfpscr */
+ "vmsr fpscr, %0\n"
+ : "=&r" (scratch) : "r" (&pcb->pcb_fpstate));
+
+ ci->ci_fpuproc = p;
+ pcb->pcb_fpcpu = ci;
+
+ /* disable until return to userland */
+ set_vfp_fpexc(0);
+
+ restore_interrupts(psw);
+}
+
+int
+vfp_fault(unsigned int pc, unsigned int insn, trapframe_t *tf, int fault_code)
+{
+ struct proc *p = curproc;
+ struct pcb *pcb = &p->p_addr->u_pcb;
+
+ if (get_vfp_fpexc() & VFPEXC_EN) {
+ /*
+ * We probably ran into an unsupported instruction,
+ * like NEON on a non-NEON system. Let the process know.
+ */
+ return 1;
+ }
+
+ /* we should be able to ignore old state of pcb_fpcpu ci_fpuproc */
+ if ((pcb->pcb_flags & PCB_FPU) == 0) {
+ pcb->pcb_flags |= PCB_FPU;
+ memset(&pcb->pcb_fpstate, 0, sizeof(pcb->pcb_fpstate));
+ }
+ vfp_load(p);
+
+ return 0;
+}
+
+void
+vfp_discard(void)
+{
+ struct cpu_info *ci = curcpu();
+
+ if (curpcb->pcb_fpcpu == ci && ci->ci_fpuproc == curproc) {
+ ci->ci_fpuproc = NULL;
+ curpcb->pcb_fpcpu = NULL;
+ }
+}
-/* $OpenBSD: vm_machdep.c,v 1.21 2017/08/17 20:50:51 tom Exp $ */
+/* $OpenBSD: vm_machdep.c,v 1.22 2018/01/26 16:22:19 kettenis Exp $ */
/* $NetBSD: vm_machdep.c,v 1.31 2004/01/04 11:33:29 jdolecek Exp $ */
/*
#include <machine/reg.h>
#include <machine/vmparam.h>
+#include <arm/vfp.h>
+
extern pv_addr_t systempage;
int process_read_regs (struct proc *p, struct reg *regs);
void
cpu_exit(struct proc *p)
{
+ vfp_discard();
pmap_deactivate(p);
sched_exit(p);
}
-# $OpenBSD: files.arm,v 1.46 2017/04/30 13:04:49 mpi Exp $
+# $OpenBSD: files.arm,v 1.47 2018/01/26 16:22:20 kettenis Exp $
# $NetBSD: files.arm,v 1.76 2003/11/05 12:53:15 scw Exp $
# generic networking files
file arch/arm/armv7/armv7_a4x_io.S cpu_armv7
file arch/arm/armv7/armv7_mutex.c cpu_armv7
file arch/arm/armv7/bus_space_asm_armv7.S cpu_armv7
+file arch/arm/arm/vfp.c cpu_armv7
pseudo-device openprom
file arch/arm/arm/openprom.c openprom needs-flag
-/* $OpenBSD: cpu.h,v 1.49 2018/01/15 14:11:16 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.50 2018/01/26 16:22:20 kettenis Exp $ */
/* $NetBSD: cpu.h,v 1.34 2003/06/23 11:01:08 martin Exp $ */
/*
struct schedstate_percpu ci_schedstate; /* scheduler state */
struct proc *ci_curproc;
+ struct proc *ci_fpuproc;
u_int32_t ci_cpuid;
u_int32_t ci_randseed;
-/* $OpenBSD: fp.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
+/* $OpenBSD: fp.h,v 1.2 2018/01/26 16:22:20 kettenis Exp $ */
/* $NetBSD: fp.h,v 1.1 2001/01/10 19:02:06 bjh21 Exp $ */
/*
typedef struct fp_extended_precision fp_reg_t;
-/*
- * Information about the FPE-SP state that is stored in the pcb
- *
- * This needs to move and be hidden from userland.
- */
-
-struct fpe_sp_state {
- unsigned int fp_flags;
- unsigned int fp_sr;
- unsigned int fp_cr;
- fp_reg_t fp_registers[16];
-};
-
/*
* Type for a saved FP context, if we want to translate the context to a
* user-readable form
-/* $OpenBSD: pcb.h,v 1.7 2016/09/24 21:02:31 patrick Exp $ */
+/* $OpenBSD: pcb.h,v 1.8 2018/01/26 16:22:20 kettenis Exp $ */
/* $NetBSD: pcb.h,v 1.10 2003/10/13 21:46:39 scw Exp $ */
/*
#define _ARM_PCB_H_
#include <machine/frame.h>
-#include <machine/fp.h>
#include <arm/pte.h>
+#include <arm/reg.h>
struct trapframe;
*/
struct pcb {
u_int pcb_flags;
-#define PCB_OWNFPU 0x00000001
+#define PCB_FPU 0x00000001 /* Process had FPU initialized */
struct trapframe *pcb_tf;
caddr_t pcb_onfault; /* On fault handler */
union {
struct pcb_arm32 un_32;
} pcb_un;
- struct fpe_sp_state pcb_fpstate; /* Floating Point state */
+ struct fpreg pcb_fpstate; /* Floating Point state */
+ struct cpu_info *pcb_fpcpu;
void *pcb_tcb;
};
--- /dev/null
+/*
+ * Copyright (c) 2012 Mark Tinguely
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * $FreeBSD$
+ */
+
+
+#ifndef _MACHINE__VFP_H_
+#define _MACHINE__VFP_H_
+
+#ifdef _KERNEL
+/* Only kernel defines exist here */
+
+/* fpsid, fpscr, fpexc are defined in the newer gas */
+#define VFPSID cr0
+#define VFPSCR cr1
+#define VMVFR1 cr6
+#define VMVFR0 cr7
+#define VFPEXC cr8
+#define VFPINST cr9 /* vfp 1 and 2 except instruction */
+#define VFPINST2 cr10 /* vfp 2? */
+
+/* VFPSID */
+#define VFPSID_IMPLEMENTOR_OFF 24
+#define VFPSID_IMPLEMENTOR_MASK (0xff000000)
+#define VFPSID_HARDSOFT_IMP (0x00800000)
+#define VFPSID_SINGLE_PREC 20 /* version 1 and 2 */
+#define VFPSID_SUBVERSION_OFF 16
+#define VFPSID_SUBVERSION2_MASK (0x000f0000) /* version 1 and 2 */
+#define VFPSID_SUBVERSION3_MASK (0x007f0000) /* version 3 */
+#define VFP_ARCH3 (0x00030000)
+#define VFPSID_PARTNUMBER_OFF 8
+#define VFPSID_PARTNUMBER_MASK (0x0000ff00)
+#define VFPSID_VARIANT_OFF 4
+#define VFPSID_VARIANT_MASK (0x000000f0)
+#define VFPSID_REVISION_MASK 0x0f
+
+/* VFPSCR */
+#define VFPSCR_CC_N (0x80000000) /* comparison less than */
+#define VFPSCR_CC_Z (0x40000000) /* comparison equal */
+#define VFPSCR_CC_C (0x20000000) /* comparison = > unordered */
+#define VFPSCR_CC_V (0x10000000) /* comparison unordered */
+#define VFPSCR_QC (0x08000000) /* saturation cululative */
+#define VFPSCR_DN (0x02000000) /* default NaN enable */
+#define VFPSCR_FZ (0x01000000) /* flush to zero enabled */
+
+#define VFPSCR_RMODE_OFF 22 /* rounding mode offset */
+#define VFPSCR_RMODE_MASK (0x00c00000) /* rounding mode mask */
+#define VFPSCR_RMODE_RN (0x00000000) /* round nearest */
+#define VFPSCR_RMODE_RPI (0x00400000) /* round to plus infinity */
+#define VFPSCR_RMODE_RNI (0x00800000) /* round to neg infinity */
+#define VFPSCR_RMODE_RM (0x00c00000) /* round to zero */
+
+#define VFPSCR_STRIDE_OFF 20 /* vector stride -1 */
+#define VFPSCR_STRIDE_MASK (0x00300000)
+#define VFPSCR_LEN_OFF 16 /* vector length -1 */
+#define VFPSCR_LEN_MASK (0x00070000)
+#define VFPSCR_IDE (0x00008000) /* input subnormal exc enable */
+#define VFPSCR_IXE (0x00001000) /* inexact exception enable */
+#define VFPSCR_UFE (0x00000800) /* underflow exception enable */
+#define VFPSCR_OFE (0x00000400) /* overflow exception enable */
+#define VFPSCR_DNZ (0x00000200) /* div by zero exception en */
+#define VFPSCR_IOE (0x00000100) /* invalid op exec enable */
+#define VFPSCR_IDC (0x00000080) /* input subnormal cumul */
+#define VFPSCR_IXC (0x00000010) /* Inexact cumulative flag */
+#define VFPSCR_UFC (0x00000008) /* underflow cumulative flag */
+#define VFPSCR_OFC (0x00000004) /* overflow cumulative flag */
+#define VFPSCR_DZC (0x00000002) /* division by zero flag */
+#define VFPSCR_IOC (0x00000001) /* invalid operation cumul */
+
+/* VFPEXC */
+#define VFPEXC_EX (0x80000000) /* exception v1 v2 */
+#define VFPEXC_EN (0x40000000) /* vfp enable */
+
+/* version 3 registers */
+/* VMVFR0 */
+#define VMVFR0_RM_OFF 28
+#define VMVFR0_RM_MASK (0xf0000000) /* VFP rounding modes */
+
+#define VMVFR0_SV_OFF 24
+#define VMVFR0_SV_MASK (0x0f000000) /* VFP short vector supp */
+#define VMVFR0_SR_OFF 20
+#define VMVFR0_SR (0x00f00000) /* VFP hw sqrt supp */
+#define VMVFR0_D_OFF 16
+#define VMVFR0_D_MASK (0x000f0000) /* VFP divide supp */
+#define VMVFR0_TE_OFF 12
+#define VMVFR0_TE_MASK (0x0000f000) /* VFP trap exception supp */
+#define VMVFR0_DP_OFF 8
+#define VMVFR0_DP_MASK (0x00000f00) /* VFP double prec support */
+#define VMVFR0_SP_OFF 4
+#define VMVFR0_SP_MASK (0x000000f0) /* VFP single prec support */
+#define VMVFR0_RB_MASK (0x0000000f) /* VFP 64 bit media support */
+
+/* VMVFR1 */
+#define VMVFR1_SP_OFF 16
+#define VMVFR1_SP_MASK (0x000f0000) /* Neon single prec support */
+#define VMVFR1_I_OFF 12
+#define VMVFR1_I_MASK (0x0000f000) /* Neon integer support */
+#define VMVFR1_LS_OFF 8
+#define VMVFR1_LS_MASK (0x00000f00) /* Neon ld/st instr support */
+#define VMVFR1_DN_OFF 4
+#define VMVFR1_DN_MASK (0x000000f0) /* Neon prop NaN support */
+#define VMVFR1_FZ_MASK (0x0000000f) /* Neon denormal arith supp */
+
+#define COPROC10 (0x3 << 20)
+#define COPROC11 (0x3 << 22)
+
+void vfp_init(void);
+void vfp_discard(void);
+void vfp_save(void);
+void vfp_enable(void);
+
+#endif /* _KERNEL */
+#endif /* _MACHINE__VFP_H_ */