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-09 18:40:07.000000000 +0900 @@ -0,0 +1,163 @@ +/* $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 *, 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 *, 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 *, 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, d) (*__sh_fpu_save_lwp)(l, d) +#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, d) sh3_fpu_save_lwp(l, d) +#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, d) sh4_fpu_save_lwp(l, d) +#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 +#include 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-08 22:44:44.000000000 +0900 @@ -100,7 +100,6 @@ int r_gbr; }; - /* * Old struct reg that is missing r_gbr. Compat ptrace(2) requests * are renamed to PT___GETREGS40 and PT___SETREGS40. @@ -129,4 +128,10 @@ int r_r0; }; +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 #include +#include #include #include #include @@ -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-09 18:39:43.000000000 +0900 @@ -0,0 +1,63 @@ +/* $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 +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include + +#include + +#if defined(SH3) && defined(SH4) +void (*__sh_fpu_enable)(void); +void (*__sh_fpu_save_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 . + */ +#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_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_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-09 18:39:36.000000000 +0900 @@ -0,0 +1,68 @@ +/* $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 +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include + +#include +#include + +/* + * SH3 FPU + */ + +void +sh3_fpu_enable(void) +{ + + /* Nothing to do. */ +} + +/*ARGSUSED*/ +void +sh3_fpu_save_lwp(struct lwp *l, int discard) +{ + + panic("sh3_fpu_save_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-09 19:54:33.000000000 +0900 @@ -0,0 +1,320 @@ +/* $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 +__KERNEL_RCSID(0, "$NetBSD$"); + +#include +#include +#include +#include + +#include + +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; + + printf("%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; + + printf("%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; + + printf("%s\n", __func__); + + 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); + + pcb->pcb_fpcpu = NULL; + ci->ci_fpulwp = 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; + struct trapframe *tf = l->l_md.md_regs; + int s; + + printf("%s\n", __func__); + + s = _cpu_intr_suspend(); + + if ((l->l_md.md_flags & MDL_USEDFPU) == 0) { + printf("%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(); + } + KASSERT(ci->ci_fpulwp == NULL); + + sh4_fpu_load_regs(&pcb->pcb_fpu); + + ci->ci_fpulwp = l; + pcb->pcb_fpcpu = ci; +out: + tf->tf_ssr &= ~PSL_FDBIT; + _cpu_intr_resume(s); +} + +void +sh4_fpu_save_lwp(struct lwp *l, int discard) +{ + struct pcb *pcb = &l->l_addr->u_pcb; + struct cpu_info * const ci = curcpu(); + + printf("%s\n", __func__); + + /* + * If it's already in the PCB, there's nothing to do. + */ + if (pcb->pcb_fpcpu == NULL) + return; + + /* + * If we simply need to discard the information, then don't + * to save anything. + */ + if (discard) { + printf("%s: discard\n", __func__); + KASSERT(l == pcb->pcb_fpcpu->ci_fpulwp); + pcb->pcb_fpcpu->ci_fpulwp = NULL; + pcb->pcb_fpcpu = NULL; + + /* Ensure we restart with a clean slate. */ + l->l_md.md_flags &= ~MDL_USEDFPU; + return; + } + + /* + * If the state is in the current CPU, + * just flush the current CPU's state. + */ + if (ci->ci_fpulwp == l) { + printf("%s: do sh4_fpu_save_cpu\n", __func__); + sh4_fpu_save_cpu(); + return; + } +} + +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; + + printf("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; +} 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 #include +#include #include #include @@ -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-09 19:23:49.000000000 +0900 @@ -101,6 +101,7 @@ #include #include #include +#include #include #include #include @@ -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) { + printf("%s:FPU\n", __func__); + + sh_fpu_save_lwp(l, false); + 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,13 @@ 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) { + printf("%s:FPU\n", __func__); + + sh_fpu_save_lwp(l, true); + memcpy(&pcb->pcb_fpu, &mcp->__fpregs, sizeof(pcb->pcb_fpu)); + l->l_md.md_flags |= MDL_USEDFPU; } -#endif mutex_enter(p->p_lock); if (flags & _UC_SETSTACK) @@ -513,11 +526,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_IS_SH4) + 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-09 18:39:26.000000000 +0900 @@ -102,6 +102,7 @@ #include #include +#include #include #include #include @@ -293,18 +294,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) { + sh4_fpu_save_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)