diff options
author | Peter Valchev <pvalchev@cvs.openbsd.org> | 2002-04-28 20:55:15 +0000 |
---|---|---|
committer | Peter Valchev <pvalchev@cvs.openbsd.org> | 2002-04-28 20:55:15 +0000 |
commit | ac8277407eec4f1f45a73b8462b4a807928dd1f0 (patch) | |
tree | e97e090b84d170144eb0ed99eeba0d7e1ab1ed5d /sys/arch/alpha | |
parent | 4433d79654bae3b6a03df679b3ace77f4b639331 (diff) |
IEEE 754 floating point completion code, and implementation of the
FP_C (Floating Point Control Quadword).
From ross@NetBSD. Added a way to disable it with option NO_IEEE,
which appears on the ramdisks to save space. This affects only
programs compiled with -mieee, and what it essentially does is
enabling infinities and NaNs, instead of generating SIGFPE on
division by zero, overflow, etc.
ok art, deraadt
Diffstat (limited to 'sys/arch/alpha')
-rw-r--r-- | sys/arch/alpha/alpha/db_instruction.h | 25 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/fp_complete.c | 698 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/locore.s | 61 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/machdep.c | 146 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/process_machdep.c | 8 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/sys_machdep.c | 124 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/trap.c | 89 | ||||
-rw-r--r-- | sys/arch/alpha/alpha/vm_machdep.c | 36 | ||||
-rw-r--r-- | sys/arch/alpha/conf/RAMDISK | 4 | ||||
-rw-r--r-- | sys/arch/alpha/conf/RAMDISKB | 4 | ||||
-rw-r--r-- | sys/arch/alpha/conf/RAMDISKBIG | 4 | ||||
-rw-r--r-- | sys/arch/alpha/conf/files.alpha | 3 | ||||
-rw-r--r-- | sys/arch/alpha/include/cpu.h | 54 | ||||
-rw-r--r-- | sys/arch/alpha/include/fpu.h | 121 | ||||
-rw-r--r-- | sys/arch/alpha/include/ieeefp.h | 39 | ||||
-rw-r--r-- | sys/arch/alpha/include/pcb.h | 3 | ||||
-rw-r--r-- | sys/arch/alpha/include/proc.h | 23 | ||||
-rw-r--r-- | sys/arch/alpha/include/sysarch.h | 69 |
18 files changed, 1410 insertions, 101 deletions
diff --git a/sys/arch/alpha/alpha/db_instruction.h b/sys/arch/alpha/alpha/db_instruction.h index 10994cff35c..6eb6a4faf7f 100644 --- a/sys/arch/alpha/alpha/db_instruction.h +++ b/sys/arch/alpha/alpha/db_instruction.h @@ -1,5 +1,5 @@ -/* $OpenBSD: db_instruction.h,v 1.3 2001/08/12 12:03:02 heko Exp $ */ -/* $NetBSD: db_instruction.h,v 1.6 2000/03/20 02:54:45 thorpej Exp $ */ +/* $OpenBSD: db_instruction.h,v 1.4 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: db_instruction.h,v 1.7 2001/04/26 03:10:44 ross Exp $ */ /* * Copyright (c) 1999 Christopher G. Demetriou. All rights reserved. @@ -185,6 +185,16 @@ typedef union { opcode : 6; } float_format; + struct { + unsigned fc : 5, + opclass : 4, + src : 2, + rnd : 2, + trp : 3, + fb : 5, + fa : 5, + opcode : 6; + } float_detail; /* * PAL instructions just define the major opcode @@ -223,6 +233,7 @@ typedef union { #define op_bit 0x12 /* see BIT sub-table */ #define op_mul 0x13 /* see MUL sub-table */ /* reserved */ +#define op_fix_float 0x14 /* if ALPHA_AMASK_FIX */ #define op_vax_float 0x15 /* see FLOAT sub-table */ #define op_ieee_float 0x16 /* see FLOAT sub-table */ #define op_any_float 0x17 /* see FLOAT sub-table */ @@ -412,6 +423,12 @@ typedef union { * Load and store operations use opcodes op_ldf..op_stt */ + /* src encoding from function, 9..10 */ +#define op_src_sf 0 +#define op_src_xd 1 +#define op_src_tg 2 +#define op_src_qq 3 + /* any FLOAT, "function" opcodes (bits 5..11) */ #define op_cvtlq 0x010 @@ -428,7 +445,7 @@ typedef union { #define op_fcmovgt 0x02f #define op_cvtql 0x030 #define op_cvtql_v 0x130 -#define op_cvtql_sv 0x330 +#define op_cvtql_sv 0x530 /* ieee FLOAT, "function" opcodes (bits 5..11) */ @@ -521,6 +538,7 @@ typedef union { #define op_mult_ud 0x1e2 #define op_divt_ud 0x1e3 #define op_cvtts_ud 0x1ec +#define op_cvtst 0x2ac #define op_adds_suc 0x500 #define op_subs_suc 0x501 #define op_muls_suc 0x502 @@ -563,6 +581,7 @@ typedef union { #define op_mult_sud 0x5e2 #define op_divt_sud 0x5e3 #define op_cvtts_sud 0x5ec +#define op_cvtst_u 0x6ac #define op_adds_suic 0x700 #define op_subs_suic 0x701 #define op_muls_suic 0x702 diff --git a/sys/arch/alpha/alpha/fp_complete.c b/sys/arch/alpha/alpha/fp_complete.c new file mode 100644 index 00000000000..80f295050e5 --- /dev/null +++ b/sys/arch/alpha/alpha/fp_complete.c @@ -0,0 +1,698 @@ +/* $OpenBSD: fp_complete.c,v 1.1 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: fp_complete.c,v 1.5 2002/01/18 22:15:56 ross Exp $ */ + +/*- + * Copyright (c) 2001 Ross Harvey + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 NO_IEEE + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> + +#include <machine/cpu.h> +#include <machine/fpu.h> +#include <machine/reg.h> +#include <machine/cpu.h> +#include <alpha/alpha/db_instruction.h> + +#include <lib/libkern/softfloat.h> + +#define TSWINSIZE 4 /* size of trap shadow window in u_int32_t units */ + +/* Set Name Opcodes AARM C.* Symbols */ + +#define CPUREG_CLASS (0xfUL << 0x10) /* INT[ALSM] */ +#define FPUREG_CLASS (0xfUL << 0x14) /* ITFP, FLT[ILV] */ +#define CHECKFUNCTIONCODE (1UL << 0x18) /* MISC */ +#define TRAPSHADOWBOUNDARY (1UL << 0x00 | /* PAL */\ + 1UL << 0x19 | /* \PAL\ */\ + 1UL << 0x1a | /* JSR */\ + 1UL << 0x1b | /* \PAL\ */\ + 1UL << 0x1d | /* \PAL\ */\ + 1UL << 0x1e | /* \PAL\ */\ + 1UL << 0x1f | /* \PAL\ */\ + 0xffffUL << 0x30 | /* branch ops */\ + CHECKFUNCTIONCODE) + +#define MAKE_FLOATXX(width, expwidth, sign, exp, msb, rest_of_frac) \ + (u_int ## width ## _t)(sign) << ((width) - 1) |\ + (u_int ## width ## _t)(exp) << ((width) - 1 - (expwidth)) |\ + (u_int ## width ## _t)(msb) << ((width) - 1 - (expwidth) - 1) |\ + (u_int ## width ## _t)(rest_of_frac) + +#define FLOAT32QNAN MAKE_FLOATXX(32, 8, 0, 0xff, 1, 0) +#define FLOAT64QNAN MAKE_FLOATXX(64, 11, 0, 0x7ff, 1, 0) + +#define IS_SUBNORMAL(v) ((v)->exp == 0 && (v)->frac != 0) + +#define PREFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_DMZ \ + && IS_SUBNORMAL(v)) \ + (v)->frac = 0; else + +#define POSTFILTER_SUBNORMAL(p,v) if ((p)->p_md.md_flags & IEEE_MAP_UMZ \ + && IS_SUBNORMAL(v)) \ + (v)->frac = 0; else + + /* Alpha returns 2.0 for true, all zeroes for false. */ + +#define CMP_RESULT(flag) ((flag) ? 4UL << 60 : 0L) + + /* Move bits from sw fp_c to hw fpcr. */ + +#define CRBLIT(sw, hw, m, offs) (((sw) & ~(m)) | ((hw) >> (offs) & (m))) + +/* + * Temporary trap shadow instrumentation. The [un]resolved counters + * could be kept permanently, as they provide information on whether + * user code has met AARM trap shadow generation requirements. + */ + +struct alpha_shadow { + u_int64_t resolved; /* cases trigger pc found */ + u_int64_t unresolved; /* cases it wasn't, code problems? */ + u_int64_t scans; /* trap shadow scans */ + u_int64_t len; /* number of instructions examined */ + u_int64_t uop; /* bit mask of unexpected opcodes */ + u_int64_t sqrts; /* ev6+ square root single count */ + u_int64_t sqrtt; /* ev6+ square root double count */ + u_int32_t ufunc; /* bit mask of unexpected functions */ + u_int32_t max; /* max trap shadow scan */ + u_int32_t nilswop; /* unexpected op codes */ + u_int32_t nilswfunc; /* unexpected function codes */ + u_int32_t nilanyop; /* this "cannot happen" */ + u_int32_t vax; /* sigs from vax fp opcodes */ +} alpha_shadow, alpha_shadow_zero; + +static float64 float64_unk(float64, float64); +static float64 compare_un(float64, float64); +static float64 compare_eq(float64, float64); +static float64 compare_lt(float64, float64); +static float64 compare_le(float64, float64); +static void cvt_qs_ts_st_gf_qf(u_int32_t, struct proc *); +static void cvt_gd(u_int32_t, struct proc *); +static void cvt_qt_dg_qg(u_int32_t, struct proc *); +static void cvt_tq_gq(u_int32_t, struct proc *); + +static float32 (*swfp_s[])(float32, float32) = { + float32_add, float32_sub, float32_mul, float32_div, +}; + +static float64 (*swfp_t[])(float64, float64) = { + float64_add, float64_sub, float64_mul, float64_div, + compare_un, compare_eq, compare_lt, compare_le, + float64_unk, float64_unk, float64_unk, float64_unk +}; + +static void (*swfp_cvt[])(u_int32_t, struct proc *) = { + cvt_qs_ts_st_gf_qf, cvt_gd, cvt_qt_dg_qg, cvt_tq_gq +}; + +static void +this_cannot_happen(int what_cannot_happen, int64_t bits) +{ + static int total; + alpha_instruction inst; + static u_int64_t reported; + + inst.bits = bits; + ++alpha_shadow.nilswfunc; + if (bits != -1) + alpha_shadow.uop |= 1UL << inst.generic_format.opcode; + if (1UL << what_cannot_happen & reported) + return; + reported |= 1UL << what_cannot_happen; + if (total >= 1000) + return; /* right now, this return "cannot happen" */ + ++total; + if (bits) + printf("FP instruction %x\n", (unsigned int)bits); + printf("FP event %d/%lx/%lx\n", what_cannot_happen, reported, + alpha_shadow.uop); +} + +static __inline void +sts(unsigned int rn, s_float *v, struct proc *p) +{ + alpha_sts(rn, v); + PREFILTER_SUBNORMAL(p, v); +} + +static __inline void +stt(unsigned int rn, t_float *v, struct proc *p) +{ + alpha_stt(rn, v); + PREFILTER_SUBNORMAL(p, v); +} + +static __inline void +lds(unsigned int rn, s_float *v, struct proc *p) +{ + POSTFILTER_SUBNORMAL(p, v); + alpha_lds(rn, v); +} + +static __inline void +ldt(unsigned int rn, t_float *v, struct proc *p) +{ + POSTFILTER_SUBNORMAL(p, v); + alpha_ldt(rn, v); +} + +static float64 +compare_lt(float64 a, float64 b) +{ + return CMP_RESULT(float64_lt(a, b)); +} + +static float64 +compare_le(float64 a, float64 b) +{ + return CMP_RESULT(float64_le(a, b)); +} + +static float64 +compare_un(float64 a, float64 b) +{ + if (float64_is_nan(a) | float64_is_nan(b)) { + if (float64_is_signaling_nan(a) | float64_is_signaling_nan(b)) + float_set_invalid(); + return CMP_RESULT(1); + } + return CMP_RESULT(0); +} + +static float64 +compare_eq(float64 a, float64 b) +{ + return CMP_RESULT(float64_eq(a, b)); +} +/* + * A note regarding the VAX FP ops. + * + * The AARM gives us complete leeway to set or not set status flags on VAX + * ops, but we do any subnorm, NaN and dirty zero fixups anyway, and we set + * flags by IEEE rules. Many ops are common to d/f/g and s/t source types. + * For the purely vax ones, it's hard to imagine ever running them. + * (Generated VAX fp ops with completion flags? Hmm.) We are careful never + * to panic, assert, or print unlimited output based on a path through the + * decoder, so weird cases don't become security issues. + */ +static void +cvt_qs_ts_st_gf_qf(u_int32_t inst_bits, struct proc *p) +{ + t_float tfb, tfc; + s_float sfb, sfc; + alpha_instruction inst; + + inst.bits = inst_bits; + /* + * cvtst and cvtts have the same opcode, function, and source. The + * distinction for cvtst is hidden in the illegal modifier combinations. + * We decode even the non-/s modifier, so that the fix-up-always mode + * works on ev6 and later. The rounding bits are unused and fixed for + * cvtst, so we check those too. + */ + switch(inst.float_format.function) { + case op_cvtst: + case op_cvtst_u: + sts(inst.float_detail.fb, &sfb, p); + tfc.i = float32_to_float64(sfb.i); + ldt(inst.float_detail.fc, &tfc, p); + return; + } + if(inst.float_detail.src == 2) { + stt(inst.float_detail.fb, &tfb, p); + sfc.i = float64_to_float32(tfb.i); + lds(inst.float_detail.fc, &sfc, p); + return; + } + /* 0: S/F */ + /* 1: /D */ + /* 3: Q/Q */ + this_cannot_happen(5, inst.generic_format.opcode); + tfc.i = FLOAT64QNAN; + ldt(inst.float_detail.fc, &tfc, p); + return; +} + +static void +cvt_gd(u_int32_t inst_bits, struct proc *p) +{ + t_float tfb, tfc; + alpha_instruction inst; + + inst.bits = inst_bits; + stt(inst.float_detail.fb, &tfb, p); + (void) float64_to_float32(tfb.i); + p->p_md.md_flags &= ~OPENBSD_FLAG_TO_FP_C(FP_X_IMP); + tfc.i = float64_add(tfb.i, (float64)0); + ldt(inst.float_detail.fc, &tfc, p); +} + +static void +cvt_qt_dg_qg(u_int32_t inst_bits, struct proc *p) +{ + t_float tfb, tfc; + alpha_instruction inst; + + inst.bits = inst_bits; + switch(inst.float_detail.src) { + case 0: /* S/F */ + this_cannot_happen(3, inst.bits); + /* fall thru */ + case 1: /* D */ + /* VAX dirty 0's and reserved ops => UNPREDICTABLE */ + /* We've done what's important by just not trapping */ + tfc.i = 0; + break; + case 2: /* T/G */ + this_cannot_happen(4, inst.bits); + tfc.i = 0; + break; + case 3: /* Q/Q */ + stt(inst.float_detail.fb, &tfb, p); + tfc.i = int64_to_float64(tfb.i); + break; + } + alpha_ldt(inst.float_detail.fc, &tfc); +} +/* + * XXX: AARM and 754 seem to disagree here, also, beware of softfloat's + * unfortunate habit of always returning the nontrapping result. + * XXX: there are several apparent AARM/AAH disagreements, as well as + * the issue of trap handler pc and trapping results. + */ +static void +cvt_tq_gq(u_int32_t inst_bits, struct proc *p) +{ + t_float tfb, tfc; + alpha_instruction inst; + + inst.bits = inst_bits; + stt(inst.float_detail.fb, &tfb, p); + tfc.i = float64_to_int64(tfb.i); + alpha_ldt(inst.float_detail.fc, &tfc); /* yes, ldt */ +} + +static u_int64_t +fp_c_to_fpcr_1(u_int64_t fpcr, u_int64_t fp_c) +{ + u_int64_t disables; + + /* + * It's hard to arrange for conforming bit fields, because the FP_C + * and the FPCR are both architected, with specified (and relatively + * scrambled) bit numbers. Defining an internal unscrambled FP_C + * wouldn't help much, because every user exception requires the + * architected bit order in the sigcontext. + * + * Programs that fiddle with the fpcr exception bits (instead of fp_c) + * will lose, because those bits can be and usually are subsetted; + * the official home is in the fp_c. Furthermore, the kernel puts + * phony enables (it lies :-) in the fpcr in order to get control when + * it is necessary to initially set a sticky bit. + */ + + fpcr &= FPCR_DYN(3); + + /* + * enable traps = case where flag bit is clear OR program wants a trap + * enables = ~flags | mask + * disables = ~(~flags | mask) + * disables = flags & ~mask. Thank you, Augustus De Morgan (1806-1871) + */ + disables = FP_C_TO_OPENBSD_FLAG(fp_c) & ~FP_C_TO_OPENBSD_MASK(fp_c); + + fpcr |= (disables & (FP_X_IMP | FP_X_UFL)) << (61 - 3); + fpcr |= (disables & (FP_X_OFL | FP_X_DZ | FP_X_INV)) << (49 - 0); + +# if !(FP_X_INV == 1 && FP_X_DZ == 2 && FP_X_OFL == 4 && \ + FP_X_UFL == 8 && FP_X_IMP == 16 && FP_X_IOV == 32 && \ + FP_X_UFL << (61 - 3) == FPCR_UNFD && \ + FP_X_IMP << (61 - 3) == FPCR_INED && \ + FP_X_OFL << (49 - 0) == FPCR_OVFD) +# error "Assertion failed" + /* + * We don't care about the other built-in bit numbers because they + * have been architecturally specified. + */ +# endif + + fpcr |= fp_c & FP_C_MIRRORED << (FPCR_MIR_START - FP_C_MIR_START); + fpcr |= (fp_c & IEEE_MAP_DMZ) << 36; + if (fp_c & FP_C_MIRRORED) + fpcr |= FPCR_SUM; + if (fp_c & IEEE_MAP_UMZ) + fpcr |= FPCR_UNDZ | FPCR_UNFD; + fpcr |= (~fp_c & IEEE_TRAP_ENABLE_DNO) << 41; + return fpcr; +} + +static void +fp_c_to_fpcr(struct proc *p) +{ + alpha_write_fpcr(fp_c_to_fpcr_1(alpha_read_fpcr(), p->p_md.md_flags)); +} + +void +alpha_write_fp_c(struct proc *p, u_int64_t fp_c) +{ + u_int64_t md_flags; + + fp_c &= MDP_FP_C; + md_flags = p->p_md.md_flags; + if ((md_flags & MDP_FP_C) == fp_c) + return; + p->p_md.md_flags = (md_flags & ~MDP_FP_C) | fp_c; + alpha_enable_fp(p, 1); + fp_c_to_fpcr(p); + alpha_pal_wrfen(0); +} + +u_int64_t +alpha_read_fp_c(struct proc *p) +{ + /* + * A possibly-desireable EV6-specific optimization would deviate from + * the Alpha Architecture spec and keep some FP_C bits in the FPCR, + * but in a transparent way. Some of the code for that would need to + * go right here. + */ + return p->p_md.md_flags & MDP_FP_C; +} + +static float64 +float64_unk(float64 a, float64 b) +{ + return 0; +} + +/* + * The real function field encodings for IEEE and VAX FP instructions. + * + * Since there is only one operand type field, the cvtXX instructions + * require a variety of special cases, and these have to be analyzed as + * they don't always fit into the field descriptions in AARM section I. + * + * Lots of staring at bits in the appendix shows what's really going on. + * + * | | + * 15 14 13|12 11 10 09|08 07 06 05 + * --------======------============ + * TRAP : RND : SRC : FUNCTION : + * 0 0 0:. . .:. . . . . . . . . . . . Imprecise + * 0 0 1|. . .:. . . . . . . . . . . ./U underflow enable (if FP output) + * | /V overfloat enable (if int output) + * 0 1 0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST + * 0 1 1|. . .:. . . . . . . . . . . . Unsupported + * 1 0 0:. . .:. . . . . . . . . . . ./S software completion (VAX only) + * 1 0 1|. . .:. . . . . . . . . . . ./SU + * | /SV + * 1 1 0:. . .:. . . . . . . . . . . ."Unsupported", but used for CVTST/S + * 1 1 1|. . .:. . . . . . . . . . . ./SUI (if FP output) (IEEE only) + * | /SVI (if int output) (IEEE only) + * S I UV: In other words: bits 15:13 are S:I:UV, except that _usually_ + * | not all combinations are valid. + * | | + * 15 14 13|12 11 10 09|08 07 06 05 + * --------======------============ + * TRAP : RND : SRC : FUNCTION : + * | 0 0 . . . . . . . . . . . ./C Chopped + * : 0 1 . . . . . . . . . . . ./M Minus Infinity + * | 1 0 . . . . . . . . . . . . Normal + * : 1 1 . . . . . . . . . . . ./D Dynamic (in FPCR: Plus Infinity) + * | | + * 15 14 13|12 11 10 09|08 07 06 05 + * --------======------============ + * TRAP : RND : SRC : FUNCTION : + * 0 0. . . . . . . . . . S/F + * 0 1. . . . . . . . . . -/D + * 1 0. . . . . . . . . . T/G + * 1 1. . . . . . . . . . Q/Q + * | | + * 15 14 13|12 11 10 09|08 07 06 05 + * --------======------============ + * TRAP : RND : SRC : FUNCTION : + * 0 0 0 0 . . . addX + * 0 0 0 1 . . . subX + * 0 0 1 0 . . . mulX + * 0 0 1 1 . . . divX + * 0 1 0 0 . . . cmpXun + * 0 1 0 1 . . . cmpXeq + * 0 1 1 0 . . . cmpXlt + * 0 1 1 1 . . . cmpXle + * 1 0 0 0 . . . reserved + * 1 0 0 1 . . . reserved + * 1 0 1 0 . . . sqrt[fg] (op_fix, not exactly "vax") + * 1 0 1 1 . . . sqrt[st] (op_fix, not exactly "ieee") + * 1 1 0 0 . . . cvtXs/f (cvt[qt]s, cvtst(!), cvt[gq]f) + * 1 1 0 1 . . . cvtXd (vax only) + * 1 1 1 0 . . . cvtXt/g (cvtqt, cvt[dq]g only) + * 1 1 1 1 . . . cvtXq/q (cvttq, cvtgq) + * | | + * 15 14 13|12 11 10 09|08 07 06 05 the twilight zone + * --------======------============ + * TRAP : RND : SRC : FUNCTION : + * /s /i /u x x 1 0 1 1 0 0 . . . cvtts, /siu only 0, 1, 5, 7 + * 0 1 0 1 0 1 0 1 1 0 0 . . . cvtst (src == T (!)) 2ac NOT /S + * 1 1 0 1 0 1 0 1 1 0 0 . . . cvtst/s (src == T (!)) 6ac + * x 0 x x x x 0 1 1 1 1 . . . cvttq/_ (src == T) + */ + +static void +alpha_fp_interpret(alpha_instruction *pc, struct proc *p, u_int64_t bits) +{ + s_float sfa, sfb, sfc; + t_float tfa, tfb, tfc; + alpha_instruction inst; + + inst.bits = bits; + switch(inst.generic_format.opcode) { + default: + /* this "cannot happen" */ + this_cannot_happen(2, inst.bits); + return; + case op_any_float: + if (inst.float_format.function == op_cvtql_sv || + inst.float_format.function == op_cvtql_v) { + alpha_stt(inst.float_detail.fb, &tfb); + sfc.i = (int64_t)tfb.i >= 0L ? INT_MAX : INT_MIN; + alpha_lds(inst.float_detail.fc, &sfc); + float_raise(FP_X_INV); + } else { + ++alpha_shadow.nilanyop; + this_cannot_happen(3, inst.bits); + } + break; + case op_vax_float: + ++alpha_shadow.vax; /* fall thru */ + case op_ieee_float: + case op_fix_float: + switch(inst.float_detail.src) { + case op_src_sf: + sts(inst.float_detail.fb, &sfb, p); + if (inst.float_detail.opclass == 10) + sfc.i = float32_sqrt(sfb.i); + else if (inst.float_detail.opclass & ~3) { + this_cannot_happen(1, inst.bits); + sfc.i = FLOAT32QNAN; + } else { + sts(inst.float_detail.fa, &sfa, p); + sfc.i = (*swfp_s[inst.float_detail.opclass])( + sfa.i, sfb.i); + } + lds(inst.float_detail.fc, &sfc, p); + break; + case op_src_xd: + case op_src_tg: + if (inst.float_detail.opclass >= 12) + (*swfp_cvt[inst.float_detail.opclass - 12])( + inst.bits, p); + else { + stt(inst.float_detail.fb, &tfb, p); + if (inst.float_detail.opclass == 10) + tfc.i = float64_sqrt(tfb.i); + else { + stt(inst.float_detail.fa, &tfa, p); + tfc.i = (*swfp_t[inst.float_detail + .opclass])(tfa.i, tfb.i); + } + ldt(inst.float_detail.fc, &tfc, p); + } + break; + case op_src_qq: + float_raise(FP_X_IMP); + break; + } + } +} + +static int +alpha_fp_complete_at(alpha_instruction *trigger_pc, struct proc *p, + u_int64_t *ucode) +{ + int needsig; + alpha_instruction inst; + u_int64_t rm, fpcr, orig_fpcr; + u_int64_t orig_flags, new_flags, changed_flags, md_flags; + + if (__predict_false(copyin(trigger_pc, &inst, sizeof inst))) { + this_cannot_happen(6, -1); + return SIGSEGV; + } + alpha_enable_fp(p, 1); + /* + * If necessary, lie about the dynamic rounding mode so emulation + * software need go to only one place for it, and so we don't have to + * lock any memory locations or pass a third parameter to every + * SoftFloat entry point. + */ + orig_fpcr = fpcr = alpha_read_fpcr(); + rm = inst.float_detail.rnd; + if (__predict_false(rm != 3 /* dynamic */ && rm != (fpcr >> 58 & 3))) { + fpcr = (fpcr & ~FPCR_DYN(3)) | FPCR_DYN(rm); + alpha_write_fpcr(fpcr); + } + orig_flags = FP_C_TO_OPENBSD_FLAG(p->p_md.md_flags); + + alpha_fp_interpret(trigger_pc, p, inst.bits); + + md_flags = p->p_md.md_flags; + + new_flags = FP_C_TO_OPENBSD_FLAG(md_flags); + changed_flags = orig_flags ^ new_flags; + KASSERT((orig_flags | changed_flags) == new_flags); /* panic on 1->0 */ + alpha_write_fpcr(fp_c_to_fpcr_1(orig_fpcr, md_flags)); + needsig = changed_flags & FP_C_TO_OPENBSD_MASK(md_flags); + alpha_pal_wrfen(0); + if (__predict_false(needsig)) { + *ucode = needsig; + return SIGFPE; + } + return 0; +} + +int +alpha_fp_complete(u_long a0, u_long a1, struct proc *p, u_int64_t *ucode) +{ + int t; + int sig; + u_int64_t op_class; + alpha_instruction inst; + /* "trigger_pc" is Compaq's term for the earliest faulting op */ + alpha_instruction *trigger_pc, *usertrap_pc; + alpha_instruction *pc, *win_begin, tsw[TSWINSIZE]; + + sig = SIGFPE; + pc = (alpha_instruction *)p->p_md.md_tf->tf_regs[FRAME_PC]; + trigger_pc = pc - 1; /* for ALPHA_AMASK_PAT case */ + if (cpu_amask & ALPHA_AMASK_PAT) { + if (a0 & 1 || alpha_fp_sync_complete) { + sig = alpha_fp_complete_at(trigger_pc, p, ucode); + goto done; + } + } + *ucode = a0; + if (!(a0 & 1)) + return sig; +/* + * At this point we are somwhere in the trap shadow of one or more instruc- + * tions that have trapped with software completion specified. We have a mask + * of the registers written by trapping instructions. + * + * Now step backwards through the trap shadow, clearing bits in the + * destination write mask until the trigger instruction is found, and + * interpret this one instruction in SW. If a SIGFPE is not required, back up + * the PC until just after this instruction and restart. This will execute all + * trap shadow instructions between the trigger pc and the trap pc twice. + * + * If a SIGFPE is generated from the OSF1 emulation, back up one more + * instruction to the trigger pc itself. Native binaries don't because it + * is non-portable and completely defeats the intended purpose of IEEE + * traps -- for example, to count the number of exponent wraps for a later + * correction. + */ + trigger_pc = 0; + win_begin = pc; + ++alpha_shadow.scans; + t = alpha_shadow.len; + for (--pc; a1; --pc) { + ++alpha_shadow.len; + if (pc < win_begin) { + win_begin = pc - TSWINSIZE + 1; + if (copyin(win_begin, tsw, sizeof tsw)) { + /* sigh, try to get just one */ + win_begin = pc; + if (copyin(win_begin, tsw, 4)) + return SIGSEGV; + } + } + assert(win_begin <= pc && !((long)pc & 3)); + inst = tsw[pc - win_begin]; + op_class = 1UL << inst.generic_format.opcode; + if (op_class & FPUREG_CLASS) { + a1 &= ~(1UL << (inst.operate_generic_format.rc + 32)); + trigger_pc = pc; + } else if (op_class & CPUREG_CLASS) { + a1 &= ~(1UL << inst.operate_generic_format.rc); + trigger_pc = pc; + } else if (op_class & TRAPSHADOWBOUNDARY) { + if (op_class & CHECKFUNCTIONCODE) { + if (inst.mem_format.displacement == op_trapb || + inst.mem_format.displacement == op_excb) + break; /* code breaks AARM rules */ + } else + break; /* code breaks AARM rules */ + } + /* Some shadow-safe op, probably load, store, or FPTI class */ + } + t = alpha_shadow.len - t; + if (t > alpha_shadow.max) + alpha_shadow.max = t; + if (__predict_true(trigger_pc != 0 && a1 == 0)) { + ++alpha_shadow.resolved; + sig = alpha_fp_complete_at(trigger_pc, p, ucode); + } else { + ++alpha_shadow.unresolved; + return sig; + } +done: + if (sig) { + usertrap_pc = trigger_pc + 1; + p->p_md.md_tf->tf_regs[FRAME_PC] = (unsigned long)usertrap_pc; + return sig; + } + return 0; +} +#endif diff --git a/sys/arch/alpha/alpha/locore.s b/sys/arch/alpha/alpha/locore.s index 8c1d9ddc315..4d38766d884 100644 --- a/sys/arch/alpha/alpha/locore.s +++ b/sys/arch/alpha/alpha/locore.s @@ -1,5 +1,5 @@ -/* $OpenBSD: locore.s,v 1.17 2001/09/30 13:08:45 art Exp $ */ -/* $NetBSD: locore.s,v 1.80 2000/09/04 00:31:59 thorpej Exp $ */ +/* $OpenBSD: locore.s,v 1.18 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: locore.s,v 1.94 2001/04/26 03:10:44 ross Exp $ */ /*- * Copyright (c) 1999, 2000 The NetBSD Foundation, Inc. @@ -1906,6 +1906,63 @@ longjmp_botchmsg: .text END(longjmp) +/* + * void sts(int rn, u_int32_t *rval); + * void stt(int rn, u_int64_t *rval); + * void lds(int rn, u_int32_t *rval); + * void ldt(int rn, u_int64_t *rval); + */ + +#ifndef NO_IEEE +.macro make_freg_util name, op + LEAF(alpha_\name, 2) + and a0, 0x1f, a0 + s8addq a0, pv, pv + addq pv, 1f - alpha_\name, pv + jmp (pv) +1: + rn = 0 + .rept 32 + \op $f0 + rn, 0(a1) + RET + rn = rn + 1 + .endr + END(alpha_\name) +.endm +/* +LEAF(alpha_sts, 2) +LEAF(alpha_stt, 2) +LEAF(alpha_lds, 2) +LEAF(alpha_ldt, 2) + */ + make_freg_util sts, sts + make_freg_util stt, stt + make_freg_util lds, lds + make_freg_util ldt, ldt + +LEAF(alpha_read_fpcr, 0); f30save = 0; rettmp = 8; framesz = 16 + lda sp, -framesz(sp) + stt $f30, f30save(sp) + mf_fpcr $f30 + stt $f30, rettmp(sp) + ldt $f30, f30save(sp) + ldq v0, rettmp(sp) + lda sp, framesz(sp) + RET +END(alpha_read_fpcr) + +LEAF(alpha_write_fpcr, 1); f30save = 0; fpcrtmp = 8; framesz = 16 + lda sp, -framesz(sp) + stq a0, fpcrtmp(sp) + stt $f30, f30save(sp) + ldt $f30, fpcrtmp(sp) + mt_fpcr $f30 + ldt $f30, f30save(sp) + lda sp, framesz(sp) + RET +END(alpha_write_fpcr) +#endif + #if 0 NESTED(transfer_check,0,0,ra,0,0) CALL(U_need_2_run_config) diff --git a/sys/arch/alpha/alpha/machdep.c b/sys/arch/alpha/alpha/machdep.c index 9918d85d027..9b56830e56b 100644 --- a/sys/arch/alpha/alpha/machdep.c +++ b/sys/arch/alpha/alpha/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.70 2002/04/25 00:53:58 miod Exp $ */ +/* $OpenBSD: machdep.c,v 1.71 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: machdep.c,v 1.210 2000/06/01 17:12:38 thorpej Exp $ */ /*- @@ -90,6 +90,9 @@ #include <sys/core.h> #include <sys/kcore.h> #include <machine/kcore.h> +#ifndef NO_IEEE +#include <machine/fpu.h> +#endif #ifdef SYSVMSG #include <sys/msg.h> #endif @@ -113,6 +116,9 @@ #include <machine/rpb.h> #include <machine/prom.h> #include <machine/cpuconf.h> +#ifndef NO_IEEE +#include <machine/ieeefp.h> +#endif #include <dev/pci/pcivar.h> @@ -201,6 +207,9 @@ struct platform platform; int alpha_unaligned_print = 1; /* warn about unaligned accesses */ int alpha_unaligned_fix = 1; /* fix up unaligned accesses */ int alpha_unaligned_sigbus = 1; /* SIGBUS on fixed-up accesses */ +#ifndef NO_IEEE +int alpha_fp_sync_complete = 0; /* fp fixup if sync even without /s */ +#endif /* * XXX This should be dynamically sized, but we have the chicken-egg problem! @@ -1597,19 +1606,18 @@ sendsig(catcher, sig, mask, code, type, val) ksc.sc_regs[R_SP] = alpha_pal_rdusp(); /* save the floating-point state, if necessary, then copy it. */ - if (p == fpcurproc) { - alpha_pal_wrfen(1); - savefpstate(&p->p_addr->u_pcb.pcb_fp); - alpha_pal_wrfen(0); - fpcurproc = NULL; - } + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); ksc.sc_ownedfp = p->p_md.md_flags & MDP_FPUSED; - bcopy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)ksc.sc_fpregs, + memcpy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); - ksc.sc_fp_control = 0; /* XXX ? */ - bzero(ksc.sc_reserved, sizeof ksc.sc_reserved); /* XXX */ - bzero(ksc.sc_xxx, sizeof ksc.sc_xxx); /* XXX */ - +#ifndef NO_IEEE + ksc.sc_fp_control = alpha_read_fp_c(p); +#else + ksc.sc_fp_control = 0; +#endif + memset(ksc.sc_reserved, 0, sizeof ksc.sc_reserved); /* XXX */ + memset(ksc.sc_xxx, 0, sizeof ksc.sc_xxx); /* XXX */ #ifdef COMPAT_OSF1 /* @@ -1713,11 +1721,14 @@ sys_sigreturn(p, v, retval) alpha_pal_wrusp(ksc.sc_regs[R_SP]); /* XXX ksc.sc_ownedfp ? */ - if (p == fpcurproc) - fpcurproc = NULL; - bcopy((struct fpreg *)ksc.sc_fpregs, &p->p_addr->u_pcb.pcb_fp, + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); + memcpy(&p->p_addr->u_pcb.pcb_fp, (struct fpreg *)ksc.sc_fpregs, sizeof(struct fpreg)); - /* XXX ksc.sc_fp_control ? */ +#ifndef NO_IEEE + p->p_addr->u_pcb.pcb_fp.fpr_cr = ksc.sc_fpcr; + p->p_md.md_flags = ksc.sc_fp_control & MDP_FP_C; +#endif #ifdef DEBUG if (sigdebug & SDB_FOLLOW) @@ -1772,10 +1783,17 @@ cpu_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p) case CPU_BOOTED_KERNEL: return (sysctl_rdstring(oldp, oldlenp, newp, bootinfo.booted_kernel)); - + case CPU_CHIPSET: return (alpha_sysctl_chipset(name + 1, namelen - 1, oldp, oldlenp)); + +#ifndef NO_IEEE + case CPU_FP_SYNC_COMPLETE: + return (sysctl_int(oldp, oldlenp, newp, newlen, + &alpha_fp_sync_complete)); +#endif + default: return (EOPNOTSUPP); } @@ -1812,8 +1830,6 @@ setregs(p, pack, stack, retval) bzero(tfp->tf_regs, FRAME_SIZE * sizeof tfp->tf_regs[0]); #endif bzero(&p->p_addr->u_pcb.pcb_fp, sizeof p->p_addr->u_pcb.pcb_fp); -#define FP_RN 2 /* XXX */ - p->p_addr->u_pcb.pcb_fp.fpr_cr = (long)FP_RN << 58; alpha_pal_wrusp(stack); tfp->tf_regs[FRAME_PS] = ALPHA_PSL_USERSET; tfp->tf_regs[FRAME_PC] = pack->ep_entry & ~3; @@ -1823,10 +1839,96 @@ setregs(p, pack, stack, retval) tfp->tf_regs[FRAME_T12] = tfp->tf_regs[FRAME_PC]; /* a.k.a. PV */ p->p_md.md_flags &= ~MDP_FPUSED; - if (fpcurproc == p) - fpcurproc = NULL; +#ifndef NO_IEEE + if (__predict_true((p->p_md.md_flags & IEEE_INHERIT) == 0)) { + p->p_md.md_flags &= ~MDP_FP_C; + p->p_addr->u_pcb.pcb_fp.fpr_cr = FPCR_DYN(FP_RN); + } +#endif + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); +} + +/* + * Release the FPU. + */ +void +fpusave_cpu(struct cpu_info *ci, int save) +{ + struct proc *p; +#if defined(MULTIPROCESSOR) + int s; +#endif + + KDASSERT(ci == curcpu()); + +#if defined(MULTIPROCESSOR) + atomic_setbits_ulong(&ci->ci_flags, CPUF_FPUSAVE); +#endif - retval[0] = retval[1] = 0; + p = ci->ci_fpcurproc; + if (p == NULL) + goto out; + + if (save) { + alpha_pal_wrfen(1); + savefpstate(&p->p_addr->u_pcb.pcb_fp); + } + + alpha_pal_wrfen(0); + + p->p_addr->u_pcb.pcb_fpcpu = NULL; + ci->ci_fpcurproc = NULL; + +out: +#if defined(MULTIPROCESSOR) + atomic_clearbits_ulong(&ci->ci_flags, CPUF_FPUSAVE); +#endif + return; +} + +/* + * Synchronize FP state for this process. + */ +void +fpusave_proc(struct proc *p, int save) +{ + struct cpu_info *ci = curcpu(); + struct cpu_info *oci; +#if defined(MULTIPROCESSOR) + u_long ipi = save ? ALPHA_IPI_SYNCH_FPU : ALPHA_IPI_DISCARD_FPU; + int s, spincount; +#endif + + KDASSERT(p->p_addr != NULL); + KDASSERT(p->p_flag & P_INMEM); + + oci = p->p_addr->u_pcb.pcb_fpcpu; + if (oci == NULL) { + return; + } + +#if defined(MULTIPROCESSOR) + if (oci == ci) { + KASSERT(ci->ci_fpcurproc == p); + fpusave_cpu(ci, save); + return; + } + + KASSERT(oci->ci_fpcurproc == p); + alpha_send_ipi(oci->ci_cpuid, ipi); + + spincount = 0; + while (p->p_addr->u_pcb.pcb_fpcpu != NULL) { + spincount++; + delay(1000); /* XXX */ + if (spincount > 10000) + panic("fpsave ipi didn't"); + } +#else + KASSERT(ci->ci_fpcurproc == p); + fpusave_cpu(ci, save); +#endif /* MULTIPROCESSOR */ } int diff --git a/sys/arch/alpha/alpha/process_machdep.c b/sys/arch/alpha/alpha/process_machdep.c index ed6817e9bcd..a99c685acfb 100644 --- a/sys/arch/alpha/alpha/process_machdep.c +++ b/sys/arch/alpha/alpha/process_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: process_machdep.c,v 1.8 2002/03/14 06:04:11 mickey Exp $ */ +/* $OpenBSD: process_machdep.c,v 1.9 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: process_machdep.c,v 1.7 1996/07/11 20:14:21 cgd Exp $ */ /*- @@ -154,8 +154,8 @@ process_write_fpregs(p, regs) struct fpreg *regs; { - if (p == fpcurproc) - fpcurproc = NULL; + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); bcopy(regs, process_fpframe(p), sizeof(struct fpreg)); return (0); @@ -333,6 +333,8 @@ process_sstep(struct proc *p, int sstep) count = 1; } + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); p->p_md.md_sstep[0].addr = addr[0]; error = ptrace_set_bpt(p, &p->p_md.md_sstep[0]); if (error) diff --git a/sys/arch/alpha/alpha/sys_machdep.c b/sys/arch/alpha/alpha/sys_machdep.c index 5a2bc9f6f28..587cd20986e 100644 --- a/sys/arch/alpha/alpha/sys_machdep.c +++ b/sys/arch/alpha/alpha/sys_machdep.c @@ -1,5 +1,41 @@ -/* $OpenBSD: sys_machdep.c,v 1.5 1997/01/24 19:56:44 niklas Exp $ */ -/* $NetBSD: sys_machdep.c,v 1.5 1996/11/13 22:20:57 cgd Exp $ */ +/* $OpenBSD: sys_machdep.c,v 1.6 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: sys_machdep.c,v 1.14 2002/01/14 00:53:16 thorpej Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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. + */ /* * Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University. @@ -30,22 +66,92 @@ #include <sys/param.h> #include <sys/systm.h> +#ifndef NO_IEEE +#include <sys/device.h> +#include <sys/proc.h> +#endif #include <sys/mount.h> #include <sys/syscallargs.h> +#ifndef NO_IEEE +#include <machine/fpu.h> +#include <machine/sysarch.h> + +#include <dev/pci/pcivar.h> + int -sys_sysarch(p, v, retval) - struct proc *p; - void *v; - register_t *retval; +sys_sysarch(struct proc *p, void *v, register_t *retval) { -#if 0 struct sys_sysarch_args /* { syscallarg(int) op; - syscallarg(char *) parms; + syscallarg(void *) parms; } */ *uap = v; -#endif + int error = 0; + + switch(SCARG(uap, op)) { + case ALPHA_FPGETMASK: + *retval = FP_C_TO_OPENBSD_MASK(p->p_md.md_flags); + break; + case ALPHA_FPGETSTICKY: + *retval = FP_C_TO_OPENBSD_FLAG(p->p_md.md_flags); + break; + case ALPHA_FPSETMASK: + case ALPHA_FPSETSTICKY: + { + fp_except m; + u_int64_t md_flags; + struct alpha_fp_except_args args; + + error = copyin(SCARG(uap, parms), &args, sizeof args); + if (error) + return error; + m = args.mask; + md_flags = p->p_md.md_flags; + switch (SCARG(uap, op)) { + case ALPHA_FPSETMASK: + *retval = FP_C_TO_OPENBSD_MASK(md_flags); + md_flags = SET_FP_C_MASK(md_flags, m); + break; + case ALPHA_FPSETSTICKY: + *retval = FP_C_TO_OPENBSD_FLAG(md_flags); + md_flags = SET_FP_C_FLAG(md_flags, m); + break; + } + alpha_write_fp_c(p, md_flags); + break; + } + case ALPHA_GET_FP_C: + { + struct alpha_fp_c_args args; + + args.fp_c = alpha_read_fp_c(p); + error = copyout(&args, SCARG(uap, parms), sizeof args); + break; + } + case ALPHA_SET_FP_C: + { + struct alpha_fp_c_args args; + + error = copyin(SCARG(uap, parms), &args, sizeof args); + if (error) + return (error); + if ((args.fp_c >> 63) != 0) + args.fp_c |= IEEE_INHERIT; + alpha_write_fp_c(p, args.fp_c); + break; + } + default: + error = EINVAL; + break; + } + + return (error); +} +#else +int sys_sysarch(struct proc *p, void *v, register_t *retval) +{ return (ENOSYS); } +#endif diff --git a/sys/arch/alpha/alpha/trap.c b/sys/arch/alpha/alpha/trap.c index d6722a9c831..d6d06f2521e 100644 --- a/sys/arch/alpha/alpha/trap.c +++ b/sys/arch/alpha/alpha/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.32 2002/03/16 03:21:28 art Exp $ */ +/* $OpenBSD: trap.c,v 1.33 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: trap.c,v 1.52 2000/05/24 16:48:33 thorpej Exp $ */ /*- @@ -102,6 +102,9 @@ #include <sys/user.h> #include <sys/syscall.h> #include <sys/buf.h> +#ifndef NO_IEEE +#include <sys/device.h> +#endif #ifdef KTRACE #include <sys/ktrace.h> #endif @@ -114,7 +117,7 @@ #ifdef DDB #include <machine/db_machdep.h> #endif -#include <alpha/alpha/db_instruction.h> /* for handle_opdec() */ +#include <alpha/alpha/db_instruction.h> #ifdef COMPAT_OSF1 #include <compat/osf1/osf1_syscall.h> @@ -135,6 +138,11 @@ int unaligned_fixup(unsigned long, unsigned long, unsigned long, struct proc *); int handle_opdec(struct proc *p, u_int64_t *ucodep); +#ifndef NO_IEEE +struct device fpevent_use; +struct device fpevent_reuse; +#endif + static void printtrap(const unsigned long, const unsigned long, const unsigned long, const unsigned long, struct trapframe *, int, int); @@ -331,21 +339,19 @@ trap(a0, a1, a2, entry, framep) goto dopanic; case ALPHA_KENTRY_ARITH: - /* - * If user-land, just give a SIGFPE. Should do - * software completion and IEEE handling, if the - * user has requested that. + /* + * Resolve trap shadows, interpret FP ops requiring infinities, + * NaNs, or denorms, and maintain FPCR corrections. */ if (user) { -#ifdef COMPAT_OSF1 - extern struct emul emul_osf1; - - /* just punt on OSF/1. XXX THIS IS EVIL */ - if (p->p_emul == &emul_osf1) +#ifndef NO_IEEE + i = alpha_fp_complete(a0, a1, p, &ucode); + if (i == 0) goto out; -#endif +#else i = SIGFPE; - ucode = a0; /* exception summary */ + ucode = a0; +#endif break; } @@ -401,6 +407,10 @@ trap(a0, a1, a2, entry, framep) break; case ALPHA_IF_CODE_FEN: +#ifndef NO_IEEE + alpha_enable_fp(p, 0); + alpha_pal_wrfen(0); +#else /* * on exit from the kernel, if proc == fpcurproc, * FP is enabled. @@ -410,7 +420,7 @@ trap(a0, a1, a2, entry, framep) p); goto dopanic; } - + alpha_pal_wrfen(1); if (fpcurproc) savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); @@ -419,6 +429,7 @@ trap(a0, a1, a2, entry, framep) alpha_pal_wrfen(0); p->p_md.md_flags |= MDP_FPUSED; +#endif goto out; default: @@ -751,6 +762,45 @@ child_return(arg) #endif } +#ifndef NO_IEEE +/* + * Set the float-point enable for the current process, and return + * the FPU context to the named process. If check == 0, it is an + * error for the named process to already be fpcurproc. + */ +void +alpha_enable_fp(struct proc *p, int check) +{ + struct cpu_info *ci = curcpu(); + + if (check && ci->ci_fpcurproc == p) { + alpha_pal_wrfen(1); + return; + } + if (ci->ci_fpcurproc == p) + panic("trap: fp disabled for fpcurproc == %p", p); + + if (ci->ci_fpcurproc != NULL) + fpusave_cpu(ci, 1); + + KDASSERT(ci->ci_fpcurproc == NULL); + +#if defined(MULTIPROCESSOR) + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); +#else + KDASSERT(p->p_addr->u_pcb.pcb_fpcpu == NULL); +#endif + + p->p_addr->u_pcb.pcb_fpcpu = ci; + ci->ci_fpcurproc = p; + + p->p_md.md_flags |= MDP_FPUSED; + alpha_pal_wrfen(1); + restorefpstate(&p->p_addr->u_pcb.pcb_fp); +} +#endif + /* * Process an asynchronous software trap. * This is relatively easy. @@ -804,12 +854,8 @@ const static int reg_to_framereg[32] = { (&(p)->p_addr->u_pcb.pcb_fp.fpr_regs[(reg)]) #define dump_fp_regs() \ - if (p == fpcurproc) { \ - alpha_pal_wrfen(1); \ - savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); \ - alpha_pal_wrfen(0); \ - fpcurproc = NULL; \ - } + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) \ + fpusave_proc(p, 1); #define unaligned_load(storage, ptrf, mod) \ if (copyin((caddr_t)va, &(storage), sizeof (storage)) != 0) \ @@ -957,9 +1003,6 @@ Gfloat_reg_cvt(input) } #endif /* FIX_UNALIGNED_VAX_FP */ -extern int alpha_unaligned_print, alpha_unaligned_fix; -extern int alpha_unaligned_sigbus; - struct unaligned_fixup_data { const char *type; /* opcode name */ int fixable; /* fixable, 0 if fixup not supported */ diff --git a/sys/arch/alpha/alpha/vm_machdep.c b/sys/arch/alpha/alpha/vm_machdep.c index 05d78106c69..afab58a822f 100644 --- a/sys/arch/alpha/alpha/vm_machdep.c +++ b/sys/arch/alpha/alpha/vm_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vm_machdep.c,v 1.27 2001/12/08 02:24:05 art Exp $ */ +/* $OpenBSD: vm_machdep.c,v 1.28 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: vm_machdep.c,v 1.55 2000/03/29 03:49:48 simonb Exp $ */ /* @@ -68,12 +68,9 @@ cpu_coredump(p, vp, cred, chdr) cpustate.md_tf = *p->p_md.md_tf; cpustate.md_tf.tf_regs[FRAME_SP] = alpha_pal_rdusp(); /* XXX */ if (p->p_md.md_flags & MDP_FPUSED) { - if (p == fpcurproc) { - alpha_pal_wrfen(1); - savefpstate(&cpustate.md_fpstate); - alpha_pal_wrfen(0); - } else - cpustate.md_fpstate = p->p_addr->u_pcb.pcb_fp; + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); + cpustate.md_fpstate = p->p_addr->u_pcb.pcb_fp; } else bzero(&cpustate.md_fpstate, sizeof(cpustate.md_fpstate)); @@ -108,8 +105,8 @@ cpu_exit(p) struct proc *p; { - if (p == fpcurproc) - fpcurproc = NULL; + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 0); /* * Deactivate the exiting address space before the vmspace @@ -150,7 +147,12 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) struct user *up = p2->p_addr; p2->p_md.md_tf = p1->p_md.md_tf; + +#ifndef NO_IEEE + p2->p_md.md_flags = p1->p_md.md_flags & (MDP_FPUSED | MDP_FP_C); +#else p2->p_md.md_flags = p1->p_md.md_flags & MDP_FPUSED; +#endif /* * Cache the physical address of the pcb, so we can @@ -162,11 +164,8 @@ cpu_fork(p1, p2, stack, stacksize, func, arg) * Copy floating point state from the FP chip to the PCB * if this process has state stored there. */ - if (p1 == fpcurproc) { - alpha_pal_wrfen(1); - savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); - alpha_pal_wrfen(0); - } + if (p1->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p1, 1); /* * Copy pcb and stack from proc p1 to p2. @@ -265,13 +264,8 @@ cpu_swapout(p) struct proc *p; { - if (p != fpcurproc) - return; - - alpha_pal_wrfen(1); - savefpstate(&fpcurproc->p_addr->u_pcb.pcb_fp); - alpha_pal_wrfen(0); - fpcurproc = NULL; + if (p->p_addr->u_pcb.pcb_fpcpu != NULL) + fpusave_proc(p, 1); } /* diff --git a/sys/arch/alpha/conf/RAMDISK b/sys/arch/alpha/conf/RAMDISK index 7c681de4f26..231d1c8a513 100644 --- a/sys/arch/alpha/conf/RAMDISK +++ b/sys/arch/alpha/conf/RAMDISK @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISK,v 1.55 2002/03/30 20:21:25 deraadt Exp $ +# $OpenBSD: RAMDISK,v 1.56 2002/04/28 20:55:14 pvalchev Exp $ # $NetBSD: RAMDISK,v 1.9 1996/12/03 17:25:33 cgd Exp $ machine alpha # architecture, used by config; REQUIRED @@ -21,6 +21,8 @@ option DEC_550 # Miata: Digital Personal Workstation option RAMDISK_HOOKS option MINIROOTSIZE=5744 # 4 Megabytes! +option NO_IEEE # Disable IEEE math + # Standard system options maxusers 8 # estimated number of users diff --git a/sys/arch/alpha/conf/RAMDISKB b/sys/arch/alpha/conf/RAMDISKB index 7a7759e2b9a..d32a646f415 100644 --- a/sys/arch/alpha/conf/RAMDISKB +++ b/sys/arch/alpha/conf/RAMDISKB @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISKB,v 1.18 2002/03/30 20:21:25 deraadt Exp $ +# $OpenBSD: RAMDISKB,v 1.19 2002/04/28 20:55:14 pvalchev Exp $ # $NetBSD: RAMDISK,v 1.9 1996/12/03 17:25:33 cgd Exp $ machine alpha # architecture, used by config; REQUIRED @@ -21,6 +21,8 @@ option API_UP1000 # EV6: Alpha Processor UP1000 option RAMDISK_HOOKS option MINIROOTSIZE=5744 # 4 Megabytes! +option NO_IEEE # Disable IEEE math + # Standard system options maxusers 8 # estimated number of users diff --git a/sys/arch/alpha/conf/RAMDISKBIG b/sys/arch/alpha/conf/RAMDISKBIG index 364066a2c33..fc4d1cba8c2 100644 --- a/sys/arch/alpha/conf/RAMDISKBIG +++ b/sys/arch/alpha/conf/RAMDISKBIG @@ -1,4 +1,4 @@ -# $OpenBSD: RAMDISKBIG,v 1.24 2002/04/02 17:14:48 deraadt Exp $ +# $OpenBSD: RAMDISKBIG,v 1.25 2002/04/28 20:55:14 pvalchev Exp $ # $NetBSD: GENERIC,v 1.31 1996/12/03 17:25:29 cgd Exp $ # # Generic Alpha kernel. Enough to get booted, etc., but not much more. @@ -21,6 +21,8 @@ option API_UP1000 # EV6: Alpha Processor UP1000 option RAMDISK_HOOKS option MINIROOTSIZE=5744 # 4 Megabytes! +option NO_IEEE # Disable IEEE math + # Standard system options maxusers 8 # estimated number of users diff --git a/sys/arch/alpha/conf/files.alpha b/sys/arch/alpha/conf/files.alpha index e643643f3d4..5249e2ecadd 100644 --- a/sys/arch/alpha/conf/files.alpha +++ b/sys/arch/alpha/conf/files.alpha @@ -1,4 +1,4 @@ -# $OpenBSD: files.alpha,v 1.56 2002/03/23 14:14:25 deraadt Exp $ +# $OpenBSD: files.alpha,v 1.57 2002/04/28 20:55:14 pvalchev Exp $ # $NetBSD: files.alpha,v 1.32 1996/11/25 04:03:21 cgd Exp $ # # alpha-specific configuration info @@ -288,6 +288,7 @@ file arch/alpha/alpha/process_machdep.c file arch/alpha/alpha/prom.c file arch/alpha/alpha/sys_machdep.c file arch/alpha/alpha/trap.c +file arch/alpha/alpha/fp_complete.c file arch/alpha/alpha/vm_machdep.c file arch/alpha/alpha/disksubr.c file arch/alpha/dev/bus_dma.c diff --git a/sys/arch/alpha/include/cpu.h b/sys/arch/alpha/include/cpu.h index b599120df2e..4a4ff665401 100644 --- a/sys/arch/alpha/include/cpu.h +++ b/sys/arch/alpha/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.15 2001/11/06 18:41:09 art Exp $ */ +/* $OpenBSD: cpu.h,v 1.16 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: cpu.h,v 1.45 2000/08/21 02:03:12 thorpej Exp $ */ /*- @@ -83,6 +83,22 @@ #ifndef _ALPHA_CPU_H_ #define _ALPHA_CPU_H_ +#ifndef NO_IEEE +typedef union alpha_s_float { + u_int32_t i; + u_int32_t frac: 23, + exp: 8, + sign: 1; +} s_float; + +typedef union alpha_t_float { + u_int64_t i; + u_int64_t frac: 52, + exp: 11, + sign: 1; +} t_float; +#endif + /* * Exported definitions unique to Alpha cpu support. */ @@ -100,7 +116,11 @@ struct reg; struct rpb; struct trapframe; +extern u_long cpu_implver; /* from IMPLVER instruction */ +extern u_long cpu_amask; /* from AMASK instruction */ extern int bootdev_debug; +extern int alpha_fp_sync_complete; +extern int alpha_unaligned_print, alpha_unaligned_fix, alpha_unaligned_sigbus; void XentArith(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */ void XentIF(u_int64_t, u_int64_t, u_int64_t); /* MAGIC */ @@ -195,6 +215,11 @@ struct cpu_info { #define CPUF_PRIMARY 0x01 /* CPU is primary CPU */ #define CPUF_PRESENT 0x02 /* CPU is present */ #define CPUF_RUNNING 0x04 /* CPU is running */ +#define CPUF_PAUSED 0x08 /* CPU is paused */ +#define CPUF_FPUSAVE 0x10 /* CPU is currently in fpusave_cpu() */ + +void fpusave_cpu(struct cpu_info *, int); +void fpusave_proc(struct proc *, int); #if defined(MULTIPROCESSOR) extern __volatile u_long cpus_running; @@ -218,9 +243,6 @@ extern struct cpu_info cpu_info_store; #define fpcurproc curcpu()->ci_fpcurproc #define curpcb curcpu()->ci_curpcb -extern u_long cpu_implver; /* from IMPLVER instruction */ -extern u_long cpu_amask; /* from AMASK instruction */ - /* * definitions of cpu-dependent requirements * referenced in generic code @@ -309,8 +331,9 @@ do { \ #define CPU_UNALIGNED_FIX 4 /* int: fix unaligned accesses */ #define CPU_UNALIGNED_SIGBUS 5 /* int: SIGBUS unaligned accesses */ #define CPU_BOOTED_KERNEL 6 /* string: booted kernel name */ -#define CPU_CHIPSET 7 /* chipset information */ -#define CPU_MAXID 8 /* 6 valid machdep IDs */ +#define CPU_FP_SYNC_COMPLETE 7 /* int: always fixup sync fp traps */ +#define CPU_MAXID 8 /* 7 valid machdep IDs */ +#define CPU_CHIPSET 9 /* chipset information */ #define CPU_CHIPSET_MEM 1 /* PCI memory address */ #define CPU_CHIPSET_BWX 2 /* PCI supports BWX */ @@ -328,6 +351,7 @@ do { \ { "unaligned_sigbus", CTLTYPE_INT }, \ { "booted_kernel", CTLTYPE_STRING }, \ { "chipset", CTLTYPE_NODE }, \ + { "fp_sync_complete", CTLTYPE_INT }, \ } #ifdef _KERNEL @@ -338,5 +362,23 @@ struct reg; struct rpb; struct trapframe; +/* IEEE and VAX FP completion */ + +#ifndef NO_IEEE +void alpha_sts(int, s_float *); /* MAGIC */ +void alpha_stt(int, t_float *); /* MAGIC */ +void alpha_lds(int, s_float *); /* MAGIC */ +void alpha_ldt(int, t_float *); /* MAGIC */ + +uint64_t alpha_read_fpcr(void); /* MAGIC */ +void alpha_write_fpcr(u_int64_t); /* MAGIC */ + +u_int64_t alpha_read_fp_c(struct proc *); +void alpha_write_fp_c(struct proc *, u_int64_t); + +void alpha_enable_fp(struct proc *, int); +int alpha_fp_complete(u_long, u_long, struct proc *, u_int64_t *); +#endif + #endif /* _KERNEL */ #endif /* _ALPHA_CPU_H_ */ diff --git a/sys/arch/alpha/include/fpu.h b/sys/arch/alpha/include/fpu.h new file mode 100644 index 00000000000..1aa71c1e765 --- /dev/null +++ b/sys/arch/alpha/include/fpu.h @@ -0,0 +1,121 @@ +/* $OpenBSD: fpu.h,v 1.1 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: fpu.h,v 1.4 2001/04/26 03:10:46 ross Exp $ */ + +/*- + * Copyright (c) 2001 Ross Harvey + * All rights reserved. + * + * This software was written for NetBSD. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 _ALPHA_FPU_H_ +#define _ALPHA_FPU_H_ + +#define _FP_C_DEF(n) (1UL << (n)) + +/* + * Most of these next definitions were moved from <ieeefp.h>. Apparently the + * names happen to match those exported by Compaq and Linux from their fpu.h + * files. + */ + +#define FPCR_SUM _FP_C_DEF(63) +#define FPCR_INED _FP_C_DEF(62) +#define FPCR_UNFD _FP_C_DEF(61) +#define FPCR_UNDZ _FP_C_DEF(60) +#define FPCR_DYN(rm) ((unsigned long)(rm) << 58) +#define FPCR_IOV _FP_C_DEF(57) +#define FPCR_INE _FP_C_DEF(56) +#define FPCR_UNF _FP_C_DEF(55) +#define FPCR_OVF _FP_C_DEF(54) +#define FPCR_DZE _FP_C_DEF(53) +#define FPCR_INV _FP_C_DEF(52) +#define FPCR_OVFD _FP_C_DEF(51) +#define FPCR_DZED _FP_C_DEF(50) +#define FPCR_INVD _FP_C_DEF(49) +#define FPCR_DNZ _FP_C_DEF(48) +#define FPCR_DNOD _FP_C_DEF(47) + +#define FPCR_MIRRORED (FPCR_INE | FPCR_UNF | FPCR_OVF | FPCR_DZE | FPCR_INV) +#define FPCR_MIR_START 52 + +/* + * The AARM specifies the bit positions of the software word used for + * user mode interface to the control and status of the kernel completion + * routines. Although it largely just redefines the FPCR, it shuffles + * the bit order. The names of the bits are defined in the AARM, and + * the definition prefix can easily be determined from public domain + * programs written to either the Compaq or Linux interfaces, which + * appear to be identical. + */ + +#define IEEE_STATUS_DNO _FP_C_DEF(22) +#define IEEE_STATUS_INE _FP_C_DEF(21) +#define IEEE_STATUS_UNF _FP_C_DEF(20) +#define IEEE_STATUS_OVF _FP_C_DEF(19) +#define IEEE_STATUS_DZE _FP_C_DEF(18) +#define IEEE_STATUS_INV _FP_C_DEF(17) + +#define IEEE_TRAP_ENABLE_DNO _FP_C_DEF(6) +#define IEEE_TRAP_ENABLE_INE _FP_C_DEF(5) +#define IEEE_TRAP_ENABLE_UNF _FP_C_DEF(4) +#define IEEE_TRAP_ENABLE_OVF _FP_C_DEF(3) +#define IEEE_TRAP_ENABLE_DZE _FP_C_DEF(2) +#define IEEE_TRAP_ENABLE_INV _FP_C_DEF(1) + +#define IEEE_INHERIT _FP_C_DEF(14) +#define IEEE_MAP_UMZ _FP_C_DEF(13) +#define IEEE_MAP_DMZ _FP_C_DEF(12) + +#define FP_C_MIRRORED (IEEE_STATUS_INE | IEEE_STATUS_UNF | IEEE_STATUS_OVF\ + | IEEE_STATUS_DZE | IEEE_STATUS_INV) +#define FP_C_MIR_START 17 + +#ifdef _KERNEL + +#define FLD_MASK(len) ((1UL << (len)) - 1) +#define FLD_CLEAR(obj, origin, len) \ + ((obj) & ~(FLD_MASK(len) << (origin))) +#define FLD_INSERT(obj, origin, len, value) \ + (FLD_CLEAR(obj, origin, len) | (value) << origin) + +#define FP_C_TO_OPENBSD_MASK(fp_c) ((fp_c) >> 1 & 0x3f) +#define FP_C_TO_OPENBSD_FLAG(fp_c) ((fp_c) >> 17 & 0x3f) +#define OPENBSD_MASK_TO_FP_C(m) (((m) & 0x3f) << 1) +#define OPENBSD_FLAG_TO_FP_C(s) (((s) & 0x3f) << 17) +#define CLEAR_FP_C_MASK(fp_c) ((fp_c) & ~(0x3f << 1)) +#define CLEAR_FP_C_FLAG(fp_c) ((fp_c) & ~(0x3f << 17)) +#define SET_FP_C_MASK(fp_c, m) (CLEAR_FP_C_MASK(fp_c) | OPENBSD_MASK_TO_FP_C(m)) +#define SET_FP_C_FLAG(fp_c, m) (CLEAR_FP_C_FLAG(fp_c) | OPENBSD_FLAG_TO_FP_C(m)) + +#endif + +#endif diff --git a/sys/arch/alpha/include/ieeefp.h b/sys/arch/alpha/include/ieeefp.h index 4ebb20b0aa5..4cb8539a2c1 100644 --- a/sys/arch/alpha/include/ieeefp.h +++ b/sys/arch/alpha/include/ieeefp.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ieeefp.h,v 1.3 1996/10/30 22:39:08 niklas Exp $ */ +/* $OpenBSD: ieeefp.h,v 1.4 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: ieeefp.h,v 1.1 1995/04/29 01:09:17 cgd Exp $ */ /* @@ -10,18 +10,45 @@ #define _ALPHA_IEEEFP_H_ typedef int fp_except; + +#ifdef _KERNEL + +#include <sys/param.h> +#include <sys/proc.h> +#include <machine/fpu.h> +#include <machine/cpu.h> + +/* FP_X_IOV is intentionally omitted from the architecture flags mask */ + +#define FP_AA_FLAGS (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP) + +#define float_raise(f) \ + do curproc->p_md.md_flags |= OPENBSD_FLAG_TO_FP_C(f); \ + while(0) + +#define float_set_inexact() float_raise(FP_X_IMP) +#define float_set_invalid() float_raise(FP_X_INV) +#define fpgetround() (alpha_read_fpcr() >> 58 & 3) + +#endif + #define FP_X_INV 0x01 /* invalid operation exception */ #define FP_X_DZ 0x02 /* divide-by-zero exception */ #define FP_X_OFL 0x04 /* overflow exception */ #define FP_X_UFL 0x08 /* underflow exception */ #define FP_X_IMP 0x10 /* imprecise (loss of precision; "inexact") */ -#define FP_X_IOV 0x20 /* integer overflow XXX? */ +#define FP_X_IOV 0x20 /* integer overflow */ +/* + * fp_rnd bits match the fpcr, below, as well as bits 12:11 + * in fp operate instructions + */ typedef enum { - FP_RZ=0, /* round to zero (truncate) */ - FP_RM=1, /* round toward negative infinity */ - FP_RN=2, /* round to nearest representable number */ - FP_RP=3 /* round toward positive infinity */ + FP_RZ = 0, /* round to zero (truncate) */ + FP_RM = 1, /* round toward negative infinity */ + FP_RN = 2, /* round to nearest representable number */ + FP_RP = 3, /* round toward positive infinity */ + _FP_DYNAMIC=FP_RP } fp_rnd; #endif /* _ALPHA_IEEEFP_H_ */ diff --git a/sys/arch/alpha/include/pcb.h b/sys/arch/alpha/include/pcb.h index f7eb89491af..b91bdf22438 100644 --- a/sys/arch/alpha/include/pcb.h +++ b/sys/arch/alpha/include/pcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcb.h,v 1.5 2002/03/14 01:26:27 millert Exp $ */ +/* $OpenBSD: pcb.h,v 1.6 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: pcb.h,v 1.5 1996/11/13 22:21:00 cgd Exp $ */ /* @@ -52,6 +52,7 @@ struct pcb { struct fpreg pcb_fp; /* FP registers [SW] */ unsigned long pcb_onfault; /* for copy faults [SW] */ unsigned long pcb_accessaddr; /* for [fs]uswintr [SW] */ + struct cpu_info *__volatile pcb_fpcpu; /* CPU with our FP state[SW] */ }; /* diff --git a/sys/arch/alpha/include/proc.h b/sys/arch/alpha/include/proc.h index fd698f6f9e1..dab1d4c78c0 100644 --- a/sys/arch/alpha/include/proc.h +++ b/sys/arch/alpha/include/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.7 2002/03/14 01:26:27 millert Exp $ */ +/* $OpenBSD: proc.h,v 1.8 2002/04/28 20:55:14 pvalchev Exp $ */ /* $NetBSD: proc.h,v 1.2 1995/03/24 15:01:36 cgd Exp $ */ /* @@ -45,7 +45,28 @@ struct mdproc { struct mdbpt md_sstep[2]; /* two breakpoints for sstep */ }; +/* + * md_flags usage + * -------------- + * MDP_FPUSED + * A largely unused bit indicating the presence of FPU history. + * Cleared on exec. Set but not used by the fpu context switcher + * itself. + * + * MDP_FP_C + * The architected FP Control word. It should forever begin at bit 1, + * as the bits are AARM specified and this way it doesn't need to be + * shifted. + * + * Until C99 there was never an IEEE 754 API, making most of the + * standard useless. Because of overlapping AARM, OSF/1, NetBSD, and + * C99 API's, the use of the MDP_FP_C bits is defined variously in + * ieeefp.h and fpu.h. + */ #define MDP_FPUSED 0x0001 /* Process used the FPU */ +#ifndef NO_IEEE +#define MDP_FP_C 0x7ffffe /* Extended FP_C Quadword bits */ +#endif #define MDP_STEP1 0x0002 /* Single step normal */ #define MDP_STEP2 0x0003 /* Single step branch */ diff --git a/sys/arch/alpha/include/sysarch.h b/sys/arch/alpha/include/sysarch.h new file mode 100644 index 00000000000..a439c52c7e2 --- /dev/null +++ b/sys/arch/alpha/include/sysarch.h @@ -0,0 +1,69 @@ +/* $OpenBSD: sysarch.h,v 1.3 2002/04/28 20:55:14 pvalchev Exp $ */ +/* $NetBSD: sysarch.h,v 1.8 2001/04/26 03:10:46 ross Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Jason R. Thorpe. + * + * 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. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 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 _ALPHA_SYSARCH_H_ +#define _ALPHA_SYSARCH_H_ + +#include <machine/bus.h> +#include <machine/ieeefp.h> + +/* + * Architecture specific syscalls (ALPHA) + */ + +#define ALPHA_FPGETMASK 0 +#define ALPHA_FPSETMASK 1 +#define ALPHA_FPSETSTICKY 2 +#define ALPHA_FPGETSTICKY 6 +#define ALPHA_GET_FP_C 7 +#define ALPHA_SET_FP_C 8 + +struct alpha_fp_except_args { + fp_except mask; +}; + +struct alpha_fp_c_args { + uint64_t fp_c; +}; + +#ifdef _KERNEL +int sysarch(int, void *); +#endif /* _KERNEL */ + +#endif /* !_ALPHA_SYSARCH_H_ */ |