diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/conf/files.sh3 src/sys/arch/sh3/conf/files.sh3
--- src.orig/sys/arch/sh3/conf/files.sh3	2008-11-22 15:00:26.000000000 +0900
+++ src/sys/arch/sh3/conf/files.sh3	2009-07-08 23:14:57.000000000 +0900
@@ -29,6 +29,9 @@
 file	arch/sh3/sh3/devreg.c			sh3 & sh4
 file	arch/sh3/sh3/exception.c
 file	arch/sh3/sh3/exception_vector.S
+file	arch/sh3/sh3/fpu.c
+file	arch/sh3/sh3/fpu_sh3.c			sh3
+file	arch/sh3/sh3/fpu_sh4.c			sh4
 file	arch/sh3/sh3/interrupt.c
 file	arch/sh3/sh3/kgdb_machdep.c		kgdb
 file	arch/sh3/sh3/kobj_machdep.c		modular
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/cpu.h src/sys/arch/sh3/include/cpu.h
--- src.orig/sys/arch/sh3/include/cpu.h	2008-03-23 13:30:39.000000000 +0900
+++ src/sys/arch/sh3/include/cpu.h	2009-07-08 22:41:06.000000000 +0900
@@ -60,6 +60,7 @@
 	int	ci_mtx_oldspl;
 	int	ci_want_resched;
 	int	ci_idepth;
+	struct lwp *ci_fpulwp;		/* current owner of FPU */
 };
 
 extern struct cpu_info cpu_info_store;
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/fpu.h src/sys/arch/sh3/include/fpu.h
--- src.orig/sys/arch/sh3/include/fpu.h	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/arch/sh3/include/fpu.h	2009-07-10 20:31:05.000000000 +0900
@@ -0,0 +1,169 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#ifndef _SH3_FPU_H_
+#define _SH3_FPU_H_
+
+#if defined(_KERNEL)
+
+struct lwp;
+struct ksiginfo;
+struct trapframe;
+
+void sh_fpu_init(void);
+
+#ifdef SH3
+void sh3_fpu_enable(void);
+void sh3_fpu_save_lwp(struct lwp *);
+void sh3_fpu_exit_lwp(struct lwp *, int);
+int sh3_fpu_exception(struct lwp *, struct trapframe *, struct ksiginfo *);
+#endif
+
+#ifdef SH4
+void sh4_fpu_enable(void);
+void sh4_fpu_save_lwp(struct lwp *);
+void sh4_fpu_exit_lwp(struct lwp *, int);
+int sh4_fpu_exception(struct lwp *, struct trapframe *, struct ksiginfo *);
+#endif
+
+#if defined(SH3) && defined(SH4)
+extern void (*__sh_fpu_enable)(void);
+extern void (*__sh_fpu_save_lwp)(struct lwp *);
+extern void (*__sh_fpu_exit_lwp)(struct lwp *, int);
+extern int (*__sh_fpu_exception)(struct lwp *, struct trapframe *,
+    struct ksiginfo *);
+
+#define	sh_fpu_enable()		(*__sh_fpu_enable)()
+#define	sh_fpu_save_lwp(l)	(*__sh_fpu_save_lwp)(l)
+#define	sh_fpu_exit_lwp(l, c)	(*__sh_fpu_exit_lwp)(l, c)
+#define	sh_fpu_exception(l,t,s)	(*__sh_fpu_exception)(l,t,s)
+#define	CPU_HAS_FPU		(CPU_IS_SH4)
+
+#elif defined(SH3)
+
+#define	sh_fpu_enable()		sh3_fpu_enable()
+#define	sh_fpu_save_lwp(l)	sh3_fpu_save_lwp(l)
+#define	sh_fpu_exit_lwp(l, c)	sh3_fpu_exit_lwp(l, c)
+#define	sh_fpu_exception(l,t,s)	sh3_fpu_exception(l,t,s)
+#define	CPU_HAS_FPU		(0)	/* XXX: SH3E */
+
+#elif defined(SH4)
+
+#define	sh_fpu_enable()		sh4_fpu_enable()
+#define	sh_fpu_save_lwp(l)	sh4_fpu_save_lwp(l)
+#define	sh_fpu_exit_lwp(l, c)	sh4_fpu_exit_lwp(l, c)
+#define	sh_fpu_exception(l,t,s)	sh4_fpu_exception(l,t,s)
+#define	CPU_HAS_FPU		(1)
+
+#endif	/* SH3 && SH4 */
+
+#endif	/* _KERNEL */
+
+#if !defined(__ASSEMBLER__)
+/* FPU control register access */
+static __inline int __unused
+get_fpscr(void)
+{
+	int r;
+
+	asm volatile ("sts fpscr, %0" : "=r"(r));
+
+	return r;
+}
+
+static __inline void __unused
+set_fpscr(int r)
+{
+
+	asm volatile ("lds %0, fpscr" :: "r"(r));
+}
+
+static __inline int __unused
+get_fpul(void)
+{
+	int r;
+
+	asm volatile ("sts fpul, %0" : "=r"(r));
+
+	return r;
+}
+
+static __inline void __unused
+set_fpul(int r)
+{
+
+	asm volatile ("lds %0, fpul" :: "r"(r));
+}
+#endif	/* !__ASSEMBLER__ */
+
+/*
+ * FPU register definition
+ */
+#define	FPREGS_PER_BANK	0x10
+#define	FP_BANK_BIT	0x10
+
+/* fpscr bit */
+#define	FPSCR_RM	(0x03 << 0)	/* Round mode */
+#define	 RM_NEAREST	(0x00 << 0)	/* nearest (SH4 only) */
+#define	 RM_ZERO	(0x01 << 0)	/* round to zero */
+#define	FPSCR_FLAG	(0x1f << 2)	/* FPU exception flag: VZOUI */
+#define	FPSCR_ENABLE	(0x1f << 7)	/* FPU exception enable: VZOUI */
+#define	FPSCR_CAUSE	(0x3f << 12)	/* FPU exception cause: EVZOUI */
+#define	FPSCR_DN	(0x01 << 18)	/* Denormal mode: 0=denormal (SH4 only), 1=0 */
+#define	FPSCR_PR	(0x01 << 19)	/* precision (SH4 only): 0=float, 1=double */
+#define	FPSCR_SZ	(0x01 << 20)	/* fmov size (SH4 only): 0=32, 1=64 */
+#define	FPSCR_FR	(0x01 << 21)	/* register bank (SH4 only) */
+#define	FPSCR_MASK	(0x003fffff)
+
+/* FPU exception flag/enable/cause bit */
+#define	FP_I_BIT	(1 << 0)	/* inexact result (SH4 only) */
+#define	FP_U_BIT	(1 << 1)	/* underflow (SH4 only) */
+#define	FP_O_BIT	(1 << 2)	/* overflow (SH4 only) */
+#define	FP_Z_BIT	(1 << 3)	/* divide by zero */
+#define	FP_V_BIT	(1 << 4)	/* invalid operation */
+#define	FP_E_BIT	(1 << 5)	/* FPU error (SH4 only) */
+#define	FP_ALL_BIT	(FP_I_BIT|FP_U_BIT|FP_O_BIT|FP_Z_BIT|FP_V_BIT)
+
+/* FPU exception flag/enable/cause shift bits */
+#define	FP_FLAG_SHIFT	2
+#define	FP_ENABLE_SHIFT	7
+#define	FP_CAUSE_SHIFT	12
+
+#define	FP_FLAG_MASK	FP_ALL_BIT
+#define	FP_ENABLE_MASK	FP_ALL_BIT
+#define	FP_CAUSE_MASK	(FP_ALL_BIT|FP_E_BIT)
+
+#define	FP_FLAG(r)	(((r) >> FP_FLAG_SHIFT) & FP_FLAG_MASK)
+#define	FP_ENABLE(r)	(((r) >> FP_ENABLE_SHIFT) & FP_ENABLE_MASK)
+#define	FP_CAUSE(r)	(((r) >> FP_CAUSE_SHIFT) & FP_CAUSE_MASK)
+
+/* fpscr initial value */
+#define	SH3_FPSCR_INIT	(RM_ZERO|FPSCR_DN)
+#define	SH4_FPSCR_INIT	(RM_NEAREST)
+
+#endif /* !_SH3_FPU_H_ */
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/mcontext.h src/sys/arch/sh3/include/mcontext.h
--- src.orig/sys/arch/sh3/include/mcontext.h	2008-06-05 23:46:01.000000000 +0900
+++ src/sys/arch/sh3/include/mcontext.h	2009-07-08 22:41:43.000000000 +0900
@@ -65,9 +65,43 @@
 /* Convenience synonym */
 #define	_REG_SP		_REG_R15
 
+#define	_REG_FPSCR	0
+#define	_REG_FPUL	1
+#define	_REG_FR0	2
+#define	_REG_FR1	3
+#define	_REG_FR2	4
+#define	_REG_FR3	5
+#define	_REG_FR4	6
+#define	_REG_FR5	7
+#define	_REG_FR6	8
+#define	_REG_FR7	9
+#define	_REG_FR8	10
+#define	_REG_FR9	11
+#define	_REG_FR10	12
+#define	_REG_FR11	13
+#define	_REG_FR12	14
+#define	_REG_FR13	15
+#define	_REG_FR14	16
+#define	_REG_FR15	17
+#define	_REG_FR16	18
+#define	_REG_FR17	19
+#define	_REG_FR18	20
+#define	_REG_FR19	21
+#define	_REG_FR20	22
+#define	_REG_FR21	23
+#define	_REG_FR22	24
+#define	_REG_FR23	25
+#define	_REG_FR24	26
+#define	_REG_FR25	27
+#define	_REG_FR26	28
+#define	_REG_FR27	29
+#define	_REG_FR28	30
+#define	_REG_FR29	31
+#define	_REG_FR30	32
+#define	_REG_FR31	33
+
 /*
  * FPU state description.
- * XXX: kernel doesn't support FPU yet, so this is just a placeholder.
  */
 typedef struct {
 	int		__fpr_fpscr;
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/pcb.h src/sys/arch/sh3/include/pcb.h
--- src.orig/sys/arch/sh3/include/pcb.h	2008-04-29 11:39:26.000000000 +0900
+++ src/sys/arch/sh3/include/pcb.h	2009-07-09 16:10:33.000000000 +0900
@@ -33,12 +33,16 @@
 #define	_SH3_PCB_H_
 
 #include <sh3/frame.h>
+#include <sh3/mcontext.h>
 
 struct pcb {
 	struct switchframe pcb_sf;	/* kernel context for resume */
 	void *	pcb_onfault;		/* for copyin/out fault */
 	int	pcb_faultbail;		/* bail out before call uvm_fault. */
+	struct cpu_info * volatile pcb_fpcpu;	/* CPU with our FP state */
+	__fpregset_t pcb_fpu;		/* floating point registers */
 };
 
 extern struct pcb *curpcb;
+
 #endif /* !_SH3_PCB_H_ */
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/proc.h src/sys/arch/sh3/include/proc.h
--- src.orig/sys/arch/sh3/include/proc.h	2008-02-16 07:22:38.000000000 +0900
+++ src/sys/arch/sh3/include/proc.h	2009-07-08 22:42:30.000000000 +0900
@@ -57,7 +57,7 @@
 };
 
 /* md_flags */
-#define	MDP_USEDFPU	0x0001	/* has used the FPU */
+#define	MDL_USEDFPU	0x0001	/* has used the FPU */
 
 struct lwp;
 
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/psl.h src/sys/arch/sh3/include/psl.h
--- src.orig/sys/arch/sh3/include/psl.h	2008-01-05 11:05:53.000000000 +0900
+++ src/sys/arch/sh3/include/psl.h	2009-07-08 22:43:10.000000000 +0900
@@ -45,16 +45,17 @@
 #define	PSL_IMASK	0x000000f0	/* Interrupt Mask bit */
 #define	PSL_QBIT	0x00000100	/* Q bit */
 #define	PSL_MBIT	0x00000200	/* M bit */
+#define	PSL_FDBIT	0x00008000	/* FD bit (SH4 only) */
 #define	PSL_BL		0x10000000	/* Exception Block bit */
 #define	PSL_RB		0x20000000	/* Register Bank bit */
 #define	PSL_MD		0x40000000	/* Processor Mode bit */
                                         /* 1 = kernel, 0 = user */
 
 #define	PSL_MBO		0x00000000	/* must be one bits */
-#define	PSL_MBZ		0x8ffffc0c	/* must be zero bits */
+#define	PSL_MBZ		0x8fff7c0c	/* must be zero bits */
 
 #define	PSL_USERSET	0
-#define	PSL_USERSTATIC	(PSL_BL|PSL_RB|PSL_MD|PSL_IMASK|PSL_MBO|PSL_MBZ)
+#define	PSL_USERSTATIC	(PSL_BL|PSL_RB|PSL_MD|PSL_FDBIT|PSL_IMASK|PSL_MBO|PSL_MBZ)
 
 #define	KERNELMODE(sr)		((sr) & PSL_MD)
 
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/ptrace.h src/sys/arch/sh3/include/ptrace.h
--- src.orig/sys/arch/sh3/include/ptrace.h	2008-10-30 11:36:05.000000000 +0900
+++ src/sys/arch/sh3/include/ptrace.h	2009-07-08 22:44:09.000000000 +0900
@@ -43,14 +43,17 @@
 
 #define	PT_GETREGS	(PT_FIRSTMACH + 3)
 #define	PT_SETREGS	(PT_FIRSTMACH + 4)
+#define	PT_GETFPREGS	(PT_FIRSTMACH + 5)
+#define	PT_SETFPREGS	(PT_FIRSTMACH + 6)
 
 #define PT_MACHDEP_STRINGS \
 	"(unused)", \
 	"PT___GETREGS40", \
 	"PT___SETREGS40", \
 	"PT_GETREGS", \
-	"PT_SETREGS",
-
+	"PT_SETREGS", \
+	"PT_GETFPREGS", \
+	"PT_SETFPREGS",
 
 #ifdef _KERNEL
 #ifdef _KERNEL_OPT
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/include/reg.h src/sys/arch/sh3/include/reg.h
--- src.orig/sys/arch/sh3/include/reg.h	2008-10-30 11:36:05.000000000 +0900
+++ src/sys/arch/sh3/include/reg.h	2009-07-09 20:52:23.000000000 +0900
@@ -129,4 +129,17 @@
 	int r_r0;
 };
 
+
+/*
+ * Registers accessible to ptrace(2) syscall for debugger
+ * The machine-dependent code for PT_FP{SET,GET}REGS needs to
+ * use whichever order, defined above, is correct, so that it
+ * is all invisible to the user.
+ */
+struct fpreg {
+	int fpr_fpscr;
+	int fpr_fpul;
+	int fpr_fr[32];
+};
+
 #endif /* !_SH3_REG_H_ */
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/exception.c src/sys/arch/sh3/sh3/exception.c
--- src.orig/sys/arch/sh3/sh3/exception.c	2008-12-20 01:06:35.000000000 +0900
+++ src/sys/arch/sh3/sh3/exception.c	2009-07-09 17:09:14.000000000 +0900
@@ -101,6 +101,7 @@
 #include <uvm/uvm_extern.h>
 
 #include <sh3/cpu.h>
+#include <sh3/fpu.h>
 #include <sh3/mmu.h>
 #include <sh3/exception.h>
 #include <sh3/userret.h>
@@ -219,6 +220,17 @@
 		ksi.ksi_addr = (void *)tf->tf_spc;
 		goto trapsignal;
 
+	case EXPEVT_FPU_DISABLE | EXP_USER: /* FALLTHROUGH */
+	case EXPEVT_FPU_SLOT_DISABLE | EXP_USER:
+		sh_fpu_enable();
+		break;
+
+	case EXPEVT_FPU | EXP_USER:
+		KSI_INIT_TRAP(&ksi);
+		if (sh_fpu_exception(l, tf, &ksi))
+			goto do_panic;
+		goto trapsignal;
+
 	default:
 		goto do_panic;
 	}
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/fpu.c src/sys/arch/sh3/sh3/fpu.c
--- src.orig/sys/arch/sh3/sh3/fpu.c	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/arch/sh3/sh3/fpu.c	2009-07-10 20:31:25.000000000 +0900
@@ -0,0 +1,66 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+
+#include <sh3/fpu.h>
+
+#if defined(SH3) && defined(SH4)
+void (*__sh_fpu_enable)(void);
+void (*__sh_fpu_save_lwp)(struct lwp *);
+void (*__sh_fpu_exit_lwp)(struct lwp *, int);
+int (*__sh_fpu_exception)(struct lwp *, struct trapframe *, struct ksiginfo *);
+#endif /* SH3 && SH4 */
+
+void
+sh_fpu_init(void)
+{
+
+	/*
+	 * Assign function hooks but only if both SH3 and SH4 are defined.
+	 * They are called directly otherwise.  See <sh3/fpu.h>.
+	 */
+#if defined(SH3) && defined(SH4)
+	if (CPU_IS_SH3) {
+		__sh_fpu_enable = sh3_fpu_enable;
+		__sh_fpu_save_lwp = sh3_fpu_save_lwp;
+		__sh_fpu_exit_lwp = sh3_fpu_exit_lwp;
+		__sh_fpu_exception = sh3_fpu_exception;
+	} else if (CPU_IS_SH4) {
+		__sh_fpu_enable = sh4_fpu_enable;
+		__sh_fpu_save_lwp = sh4_fpu_save_lwp;
+		__sh_fpu_exit_lwp = sh4_fpu_exit_lwp;
+		__sh_fpu_exception = sh4_fpu_exception;
+	} else
+		panic("sh_fpu_init: unknown CPU type");
+#endif /* SH3 && SH4 */
+}
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/fpu_sh3.c src/sys/arch/sh3/sh3/fpu_sh3.c
--- src.orig/sys/arch/sh3/sh3/fpu_sh3.c	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/arch/sh3/sh3/fpu_sh3.c	2009-07-10 20:32:04.000000000 +0900
@@ -0,0 +1,76 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/siginfo.h>
+
+#include <sh3/frame.h>
+#include <sh3/fpu.h>
+
+/*
+ * SH3 FPU
+ */
+
+void
+sh3_fpu_enable(void)
+{
+
+	/* Nothing to do. */
+}
+
+/*ARGSUSED*/
+void
+sh3_fpu_save_lwp(struct lwp *l)
+{
+
+	panic("sh3_fpu_save_lwp: not supported");
+}
+
+/*ARGSUSED*/
+void
+sh3_fpu_exit_lwp(struct lwp *l, int clean)
+{
+
+	panic("sh3_fpu_exit_lwp: not supported");
+}
+
+/*ARGSUSED*/
+int
+sh3_fpu_exception(struct lwp *l, struct trapframe *tf, struct ksiginfo *ksi)
+{
+
+	ksi->ksi_signo = SIGFPE;
+	ksi->ksi_code = FPE_FLTINV;
+	ksi->ksi_addr = (void *)tf->tf_spc;
+
+	return 0;	/* trapsignal */
+}
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/fpu_sh4.c src/sys/arch/sh3/sh3/fpu_sh4.c
--- src.orig/sys/arch/sh3/sh3/fpu_sh4.c	1970-01-01 09:00:00.000000000 +0900
+++ src/sys/arch/sh3/sh3/fpu_sh4.c	2009-07-10 20:52:10.000000000 +0900
@@ -0,0 +1,319 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2009 The NetBSD Foundation, Inc.
+ * 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 REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/user.h>
+
+#include <sh3/fpu.h>
+
+#if defined(FPUDEBUG)
+#define	DPRINTF(s)	printf s
+#else
+#define	DPRINTF(s)
+#endif
+
+static inline int
+get_sr(void)
+{
+	int r;
+
+	__asm volatile ("stc sr, %0" : "=r"(r));
+
+	return r;
+}
+
+static inline void
+set_sr(int r)
+{
+
+	__asm volatile ("ldc %0, sr" :: "r"(r));
+}
+
+static void
+sh4_fpu_save_regs(__fpregset_t *fp)
+{
+	int sr;
+	int fpscr;
+
+	DPRINTF(("%s\n", __func__));
+
+	sr = get_sr();
+	set_sr(sr & ~PSL_FDBIT);
+
+	fpscr = get_fpscr();
+
+	/* save FPU register */
+	set_fpscr((fpscr | FPSCR_FR) & ~FPSCR_SZ);
+	__asm volatile (
+		"mov	%0, r4\n\t"
+		"fmov.s	fr15, @-r4\n\t"
+		"fmov.s	fr14, @-r4\n\t"
+		"fmov.s	fr13, @-r4\n\t"
+		"fmov.s	fr12, @-r4\n\t"
+		"fmov.s	fr11, @-r4\n\t"
+		"fmov.s	fr10, @-r4\n\t"
+		"fmov.s	fr9, @-r4\n\t"
+		"fmov.s	fr8, @-r4\n\t"
+		"fmov.s	fr7, @-r4\n\t"
+		"fmov.s	fr6, @-r4\n\t"
+		"fmov.s	fr5, @-r4\n\t"
+		"fmov.s	fr4, @-r4\n\t"
+		"fmov.s	fr3, @-r4\n\t"
+		"fmov.s	fr2, @-r4\n\t"
+		"fmov.s	fr1, @-r4\n\t"
+		"fmov.s	fr0, @-r4\n\t"
+		"frchg\n\t"
+		"fmov.s	fr15, @-r4\n\t"
+		"fmov.s	fr14, @-r4\n\t"
+		"fmov.s	fr13, @-r4\n\t"
+		"fmov.s	fr12, @-r4\n\t"
+		"fmov.s	fr11, @-r4\n\t"
+		"fmov.s	fr10, @-r4\n\t"
+		"fmov.s	fr9, @-r4\n\t"
+		"fmov.s	fr8, @-r4\n\t"
+		"fmov.s	fr7, @-r4\n\t"
+		"fmov.s	fr6, @-r4\n\t"
+		"fmov.s	fr5, @-r4\n\t"
+		"fmov.s	fr4, @-r4\n\t"
+		"fmov.s	fr3, @-r4\n\t"
+		"fmov.s	fr2, @-r4\n\t"
+		"fmov.s	fr1, @-r4\n\t"
+		"fmov.s	fr0, @-r4"
+	    :: "r"(&fp->__fpr_regs[32]));
+
+	/* save FPU control register */
+	fp->__fpr_fpul = get_fpul();
+	fp->__fpr_fpscr = fpscr;
+
+	set_fpscr(fpscr);
+
+	set_sr(sr);
+}
+
+static void
+sh4_fpu_load_regs(__fpregset_t *fp)
+{
+	int sr;
+	int fpscr;
+
+	DPRINTF(("%s\n", __func__));
+
+	sr = get_sr();
+	set_sr(sr & ~PSL_FDBIT);
+
+	fpscr = get_fpscr();
+
+	/* load FPU registers */
+	set_fpscr(fpscr & ~(FPSCR_FR|FPSCR_SZ));
+	__asm volatile (
+		"mov	%0, r4\n\t"
+		"fmov.s	@r4+, fr0\n\t"
+		"fmov.s	@r4+, fr1\n\t"
+		"fmov.s	@r4+, fr2\n\t"
+		"fmov.s	@r4+, fr3\n\t"
+		"fmov.s	@r4+, fr4\n\t"
+		"fmov.s	@r4+, fr5\n\t"
+		"fmov.s	@r4+, fr6\n\t"
+		"fmov.s	@r4+, fr7\n\t"
+		"fmov.s	@r4+, fr8\n\t"
+		"fmov.s	@r4+, fr9\n\t"
+		"fmov.s	@r4+, fr10\n\t"
+		"fmov.s	@r4+, fr11\n\t"
+		"fmov.s	@r4+, fr12\n\t"
+		"fmov.s	@r4+, fr13\n\t"
+		"fmov.s	@r4+, fr14\n\t"
+		"fmov.s	@r4+, fr15\n\t"
+		"frchg\n\t"
+		"fmov.s	@r4+, fr0\n\t"
+		"fmov.s	@r4+, fr1\n\t"
+		"fmov.s	@r4+, fr2\n\t"
+		"fmov.s	@r4+, fr3\n\t"
+		"fmov.s	@r4+, fr4\n\t"
+		"fmov.s	@r4+, fr5\n\t"
+		"fmov.s	@r4+, fr6\n\t"
+		"fmov.s	@r4+, fr7\n\t"
+		"fmov.s	@r4+, fr8\n\t"
+		"fmov.s	@r4+, fr9\n\t"
+		"fmov.s	@r4+, fr10\n\t"
+		"fmov.s	@r4+, fr11\n\t"
+		"fmov.s	@r4+, fr12\n\t"
+		"fmov.s	@r4+, fr13\n\t"
+		"fmov.s	@r4+, fr14\n\t"
+		"fmov.s	@r4+, fr15\n\t"
+	    :: "r"(&fp->__fpr_regs[0]));
+
+	/* load FPU control register */
+	set_fpul(fp->__fpr_fpul);
+	set_fpscr(fp->__fpr_fpscr);
+
+	set_sr(sr);
+}
+
+/*
+ * Save current CPU's FPU state.
+ */
+static void
+sh4_fpu_save_cpu(void)
+{
+	struct cpu_info *ci = curcpu();
+	struct lwp *l;
+	struct pcb *pcb;
+	int s;
+
+	DPRINTF(("%s: lwp=%p\n", __func__, ci->ci_fpulwp));
+
+	s = _cpu_intr_suspend();
+
+	l = ci->ci_fpulwp;
+	if (l == NULL)
+		goto out;
+
+	pcb = &l->l_addr->u_pcb;
+	sh4_fpu_save_regs(&pcb->pcb_fpu);
+
+	ci->ci_fpulwp->l_md.md_regs->tf_ssr |= PSL_FDBIT;
+	ci->ci_fpulwp = NULL;
+	pcb->pcb_fpcpu = NULL;
+out:
+	_cpu_intr_resume(s);
+}
+
+void
+sh4_fpu_enable(void)
+{
+	struct cpu_info *ci = curcpu();
+	struct lwp *l = curlwp;
+	struct pcb *pcb = &l->l_addr->u_pcb;
+	int s;
+
+	DPRINTF(("%s: lwp=%p\n", __func__, l));
+
+	s = _cpu_intr_suspend();
+
+	if ((l->l_md.md_flags & MDL_USEDFPU) == 0) {
+		DPRINTF(("%s: !MDL_USEDFPU\n", __func__));
+		memset(&pcb->pcb_fpu, 0, sizeof(pcb->pcb_fpu));
+		pcb->pcb_fpu.__fpr_fpscr = SH4_FPSCR_INIT;
+		l->l_md.md_flags |= MDL_USEDFPU;
+	}
+
+	/*
+	 * If we own the CPU but FP is disabled, simply enable it and return.
+	 */
+	if (ci->ci_fpulwp == l)
+		goto out;
+
+	if (ci->ci_fpulwp != NULL)
+		sh4_fpu_save_cpu();
+	sh4_fpu_load_regs(&pcb->pcb_fpu);
+
+	ci->ci_fpulwp = l;
+	pcb->pcb_fpcpu = ci;
+out:
+	l->l_md.md_regs->tf_ssr &= ~PSL_FDBIT;
+	_cpu_intr_resume(s);
+}
+
+void
+sh4_fpu_save_lwp(struct lwp *l)
+{
+	struct cpu_info * const ci = curcpu();
+
+	DPRINTF(("%s: lwp=%p\n", __func__, l));
+
+	/*
+	 * If the state is in the current CPU,
+	 * just flush the current CPU's state.
+	 */
+	if (ci->ci_fpulwp == l) {
+		DPRINTF(("%s: do sh4_fpu_save_cpu\n", __func__));
+		sh4_fpu_save_cpu();
+	}
+}
+
+void
+sh4_fpu_exit_lwp(struct lwp *l, int clean)
+{
+	struct pcb *pcb = &l->l_addr->u_pcb;
+
+	DPRINTF(("%s: lwp=%p, clean=%d\n", __func__, l, clean));
+
+	KASSERT(l == pcb->pcb_fpcpu->ci_fpulwp);
+	pcb->pcb_fpcpu->ci_fpulwp->l_md.md_regs->tf_ssr |= PSL_FDBIT;
+	pcb->pcb_fpcpu->ci_fpulwp = NULL;
+	pcb->pcb_fpcpu = NULL;
+
+	if (clean) {
+		DPRINTF(("%s: do clean\n", __func__));
+		/* Ensure we restart with a clean slate. */
+		l->l_md.md_flags &= ~MDL_USEDFPU;
+	}
+}
+
+int
+sh4_fpu_exception(struct lwp *l, struct trapframe *tf, struct ksiginfo *ksi)
+{
+	static const int cause2sigcode[6] = {
+		FPE_FLTRES,	/* FP_I_BIT */
+		FPE_FLTUND,	/* FP_U_BIT */
+		FPE_FLTOVF,	/* FP_O_BIT */
+		FPE_FLTDIV,	/* FP_Z_BIT */
+		FPE_FLTINV,	/* FP_V_BIT */
+		FPE_FLTRES	/* FP_E_BIT */
+	};
+	int fpscr;
+	int cause;
+	int i;
+
+	fpscr = get_fpscr();
+
+	cause = FP_CAUSE(fpscr);
+	cause &= FP_ENABLE(fpscr) | FP_E_BIT;
+
+	DPRINTF(("fpscr = 0x%x, cause = 0x%x\n", fpscr, cause));
+
+	ksi->ksi_signo = SIGFPE;
+	ksi->ksi_addr = (void *)tf->tf_spc;
+
+	for (i = 0; i < __arraycount(cause2sigcode); i++) {
+		if (cause & (1 << i)) {
+			ksi->ksi_code = cause2sigcode[i];
+			break;
+		}
+	}
+	if (i == __arraycount(cause2sigcode)) {
+		ksi->ksi_code = FPE_FLTINV;
+	}
+
+	return 0;	/* trapsignal */
+}
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/process_machdep.c src/sys/arch/sh3/sh3/process_machdep.c
--- src.orig/sys/arch/sh3/sh3/process_machdep.c	2008-10-30 11:36:05.000000000 +0900
+++ src/sys/arch/sh3/sh3/process_machdep.c	2009-07-08 23:10:21.000000000 +0900
@@ -88,6 +88,7 @@
 #include <sys/vnode.h>
 #include <sys/ptrace.h>
 
+#include <sh3/fpu.h>
 #include <machine/psl.h>
 #include <machine/reg.h>
 
@@ -142,6 +143,27 @@
 	return (0);
 }
 
+int
+process_read_fpregs(struct lwp *l, struct fpreg *fpregs)
+{
+	__fpregset_t *fp;
+	int i;
+
+	if (CPU_HAS_FPU) {
+		fp = &l->l_md.md_pcb->pcb_fpu;
+
+		fpregs->fpr_fpscr = fp->__fpr_fpscr;
+		fpregs->fpr_fpul = fp->__fpr_fpul;
+		for (i = 0; i < __arraycount(fpregs->fpr_fr); i++) {
+			fpregs->fpr_fr[i] = fp->__fpr_regs[i];
+		}
+	} else {
+		memset(fpregs, 0, sizeof(struct fpreg));
+	}
+
+	return (0);
+}
+
 #endif /* PTRACE || COREDUMP */
 
 
@@ -186,6 +208,24 @@
 	return (0);
 }
 
+int
+process_write_fpregs(struct lwp *l, const struct fpreg *fpregs)
+{
+	__fpregset_t *fp;
+	int i;
+
+	if (CPU_HAS_FPU) {
+		fp = &l->l_md.md_pcb->pcb_fpu;
+
+		fp->__fpr_fpscr = fpregs->fpr_fpscr;
+		fp->__fpr_fpul = fpregs->fpr_fpul;
+		for (i = 0; i < __arraycount(fp->__fpr_regs); i++) {
+			fp->__fpr_regs[i] = fpregs->fpr_fr[i];
+		}
+	}
+
+	return (0);
+}
 
 #ifdef __HAVE_PTRACE_MACHDEP
 
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/sh3_machdep.c src/sys/arch/sh3/sh3/sh3_machdep.c
--- src.orig/sys/arch/sh3/sh3/sh3_machdep.c	2009-03-21 18:58:59.000000000 +0900
+++ src/sys/arch/sh3/sh3/sh3_machdep.c	2009-07-10 20:30:20.000000000 +0900
@@ -101,6 +101,7 @@
 #include <sh3/cache.h>
 #include <sh3/clock.h>
 #include <sh3/exception.h>
+#include <sh3/fpu.h>
 #include <sh3/locore.h>
 #include <sh3/mmu.h>
 #include <sh3/intr.h>
@@ -160,6 +161,9 @@
 	/* MMU access ops. */
 	sh_mmu_init();
 
+	/* FPU access ops. */
+	sh_fpu_init();
+
 	/* Hardclock, RTC initialize. */
 	machine_clock_init();
 
@@ -414,6 +418,7 @@
 cpu_getmcontext(struct lwp *l, mcontext_t *mcp, unsigned int *flags)
 {
 	const struct trapframe *tf = l->l_md.md_regs;
+	const struct pcb *pcb = &l->l_addr->u_pcb;
 	__greg_t *gr = mcp->__gregs;
 	__greg_t ras_pc;
 
@@ -447,14 +452,21 @@
 
 	*flags |= _UC_CPU;
 
-	/* FPU context is currently not handled by the kernel. */
-	memset(&mcp->__fpregs, 0, sizeof (mcp->__fpregs));
+	if ((l->l_md.md_flags & MDL_USEDFPU) != 0) {
+		if (pcb->pcb_fpcpu) {
+			sh_fpu_save_lwp(l);
+		}
+		memcpy(&mcp->__fpregs, &pcb->pcb_fpu, sizeof(mcp->__fpregs));
+		*flags |= _UC_FPU;
+	} else
+		memset(&mcp->__fpregs, 0, sizeof(mcp->__fpregs));
 }
 
 int
 cpu_setmcontext(struct lwp *l, const mcontext_t *mcp, unsigned int flags)
 {
 	struct trapframe *tf = l->l_md.md_regs;
+	struct pcb *pcb = &l->l_addr->u_pcb;
 	const __greg_t *gr = mcp->__gregs;
 	struct proc *p = l->l_proc;
 
@@ -488,12 +500,12 @@
 		tf->tf_r15    = gr[_REG_R15];
 	}
 
-#if 0
-	/* XXX: FPU context is currently not handled by the kernel. */
-	if (flags & _UC_FPU) {
-		/* TODO */;
+	if ((flags & _UC_FPU) != 0) {
+		if (pcb->pcb_fpcpu) {
+			sh_fpu_exit_lwp(l, false);
+		}
+		memcpy(&pcb->pcb_fpu, &mcp->__fpregs, sizeof(pcb->pcb_fpu));
 	}
-#endif
 
 	mutex_enter(p->p_lock);
 	if (flags & _UC_SETSTACK)
@@ -513,11 +525,13 @@
 {
 	struct trapframe *tf;
 
-	l->l_md.md_flags &= ~MDP_USEDFPU;
+	l->l_md.md_flags &= ~MDL_USEDFPU;
 
 	tf = l->l_md.md_regs;
 
 	tf->tf_ssr = PSL_USERSET;
+	if (CPU_HAS_FPU)
+		tf->tf_ssr |= PSL_FDBIT;	/* disable FPU */
 	tf->tf_spc = pack->ep_entry;
 	tf->tf_pr = 0;
 
diff --exclude=CVS --exclude='obj.*' --exclude=compile -uNr src.orig/sys/arch/sh3/sh3/vm_machdep.c src/sys/arch/sh3/sh3/vm_machdep.c
--- src.orig/sys/arch/sh3/sh3/vm_machdep.c	2008-11-22 06:15:53.000000000 +0900
+++ src/sys/arch/sh3/sh3/vm_machdep.c	2009-07-10 20:28:53.000000000 +0900
@@ -102,6 +102,7 @@
 
 #include <sh3/locore.h>
 #include <sh3/cpu.h>
+#include <sh3/fpu.h>
 #include <sh3/reg.h>
 #include <sh3/mmu.h>
 #include <sh3/cache.h>
@@ -175,6 +176,8 @@
 	sh3_setup_uarea(l);
 
 	l->l_md.md_regs->tf_ssr = PSL_USERSET;
+	if (CPU_HAS_FPU)
+		l->l_md.md_regs->tf_ssr |= PSL_FDBIT;	/* disable FPU */
 
 	/* When lwp is switched to, jump to the trampoline */
 	sf = &l->l_md.md_pcb->pcb_sf;
@@ -293,18 +296,23 @@
 
 
 /*
- * Exit hook
+ * cpu_lwp_free is called from exit() to let machine-dependent
+ * code free machine-dependent resources.  Note that this routine
+ * must not block.
  */
 void
 cpu_lwp_free(struct lwp *l, int proc)
 {
 
-	/* Nothing to do */
+	/* If we were using the FPU, forget about it. */
+	if (l->l_addr->u_pcb.pcb_fpcpu) {
+		sh_fpu_exit_lwp(l, true);
+	}
 }
 
-
 /*
- * lwp_free() hook
+ * cpu_lwp_free2 is called when an LWP is being reaped.
+ * This routine may block.
  */
 void
 cpu_lwp_free2(struct lwp *l)
