Add kernel support for the VFP FPU/SIMD unit. Based on a diff by drahn@.
authorkettenis <kettenis@openbsd.org>
Fri, 26 Jan 2018 16:22:19 +0000 (16:22 +0000)
committerkettenis <kettenis@openbsd.org>
Fri, 26 Jan 2018 16:22:19 +0000 (16:22 +0000)
This allows us to use floating-pointer and vector instructions in userland
code.  The current implementation assumes all 32 VFP registers are present.
This should be the case on all armv7 hardware currently supported by
OpenBSD.

ok patrick@

13 files changed:
sys/arch/arm/arm/cpu.c
sys/arch/arm/arm/exception.S
sys/arch/arm/arm/fault.c
sys/arch/arm/arm/irq_dispatch.S
sys/arch/arm/arm/syscall.c
sys/arch/arm/arm/undefined.c
sys/arch/arm/arm/vfp.c [new file with mode: 0644]
sys/arch/arm/arm/vm_machdep.c
sys/arch/arm/conf/files.arm
sys/arch/arm/include/cpu.h
sys/arch/arm/include/fp.h
sys/arch/arm/include/pcb.h
sys/arch/arm/include/vfp.h [new file with mode: 0644]

index 5b6a9ce..6a23a68 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $     */
 
 
@@ -62,6 +62,7 @@
 
 #include <arm/cpuconf.h>
 #include <arm/undefined.h>
+#include <arm/vfp.h>
 
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/ofw_clock.h>
@@ -116,6 +117,8 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
 
                identify_arm_cpu(dev, ci);
 
+               vfp_init();
+
                if (OF_getproplen(faa->fa_node, "clocks") > 0) {
                        cpu_node = faa->fa_node;
                        cpu_cpuspeed = cpu_clockspeed;
index f1bceac..3cf4e2c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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
 
 /*
@@ -194,6 +202,7 @@ Laddress_exception_msg:
 
 exception_exit:
        DO_AST
+       RESTOREVFP
        PULLFRAMEFROMSVCANDEXIT
 
 /*
index 96c0e1b..8ece22e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $ */
 
 /*
@@ -99,6 +99,7 @@
 #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() */
@@ -188,6 +189,9 @@ data_abort_handler(trapframe_t *tf)
        /* 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);
@@ -581,6 +585,9 @@ prefetch_abort_handler(trapframe_t *tf)
        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.
index 63ce564..015c7bb 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $     */
 
 /*
@@ -90,6 +90,9 @@
 .Lcpu_info_primary:
        .word   _C_LABEL(cpu_info_primary)
 
+#define STOREVFP                                               \
+       bl      _C_LABEL(vfp_save)
+
 AST_LOCALS
 
 ASENTRY_NP(irq_entry)
@@ -97,6 +100,8 @@ 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
index 7ffa07e..adc0c07 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $ */
 
 /*-
@@ -89,6 +89,7 @@
 #include <machine/frame.h>
 #include <machine/pcb.h>
 #include <arm/swi.h>
+#include <arm/vfp.h>
 
 #define MAXARGS 8
 
@@ -103,6 +104,9 @@ swi_handler(trapframe_t *frame)
 
        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);
index afe94ef..2120de0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $     */
 
 /*
@@ -62,6 +62,7 @@
 #include <machine/cpu.h>
 #include <machine/frame.h>
 #include <arm/undefined.h>
+#include <arm/vfp.h>
 #include <machine/trap.h>
 
 
@@ -150,6 +151,9 @@ undefinedinstruction(trapframe_t *frame)
 #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);
@@ -194,10 +198,14 @@ undefinedinstruction(trapframe_t *frame)
         * 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) {
                /*
diff --git a/sys/arch/arm/arm/vfp.c b/sys/arch/arm/arm/vfp.c
new file mode 100644 (file)
index 0000000..ec5b4a2
--- /dev/null
@@ -0,0 +1,197 @@
+/*     $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;
+       }
+}
index d755b8c..87e0032 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $ */
 
 /*
@@ -62,6 +62,8 @@
 #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);
@@ -132,6 +134,7 @@ cpu_fork(struct proc *p1, struct proc *p2, void *stack, void *tcb,
 void
 cpu_exit(struct proc *p)
 {
+       vfp_discard();
        pmap_deactivate(p);
        sched_exit(p);
 }
index 9dae5a1..b694cfe 100644 (file)
@@ -1,4 +1,4 @@
-#      $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
@@ -73,6 +73,7 @@ file  arch/arm/armv7/armv7_a4x_space.c        cpu_armv7
 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
index 2d783aa..9fd273e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $  */
 
 /*
@@ -185,6 +185,7 @@ struct cpu_info {
        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;
 
index 5d9096e..d503ea1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $     */
 
 /*
@@ -59,19 +59,6 @@ typedef struct fp_extended_precision {
 
 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
index 1f63d2b..fc43b1c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $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 $     */
 
 /*
@@ -38,9 +38,9 @@
 #define        _ARM_PCB_H_
 
 #include <machine/frame.h>
-#include <machine/fp.h>
 
 #include <arm/pte.h>
+#include <arm/reg.h>
 
 struct trapframe;
 
@@ -77,13 +77,14 @@ struct pcb_arm32 {
  */
 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;
 };
 
diff --git a/sys/arch/arm/include/vfp.h b/sys/arch/arm/include/vfp.h
new file mode 100644 (file)
index 0000000..511be72
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * 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_ */