summaryrefslogtreecommitdiff
path: root/sys/arch/alpha
diff options
context:
space:
mode:
authorPeter Valchev <pvalchev@cvs.openbsd.org>2002-04-28 20:55:15 +0000
committerPeter Valchev <pvalchev@cvs.openbsd.org>2002-04-28 20:55:15 +0000
commitac8277407eec4f1f45a73b8462b4a807928dd1f0 (patch)
treee97e090b84d170144eb0ed99eeba0d7e1ab1ed5d /sys/arch/alpha
parent4433d79654bae3b6a03df679b3ace77f4b639331 (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.h25
-rw-r--r--sys/arch/alpha/alpha/fp_complete.c698
-rw-r--r--sys/arch/alpha/alpha/locore.s61
-rw-r--r--sys/arch/alpha/alpha/machdep.c146
-rw-r--r--sys/arch/alpha/alpha/process_machdep.c8
-rw-r--r--sys/arch/alpha/alpha/sys_machdep.c124
-rw-r--r--sys/arch/alpha/alpha/trap.c89
-rw-r--r--sys/arch/alpha/alpha/vm_machdep.c36
-rw-r--r--sys/arch/alpha/conf/RAMDISK4
-rw-r--r--sys/arch/alpha/conf/RAMDISKB4
-rw-r--r--sys/arch/alpha/conf/RAMDISKBIG4
-rw-r--r--sys/arch/alpha/conf/files.alpha3
-rw-r--r--sys/arch/alpha/include/cpu.h54
-rw-r--r--sys/arch/alpha/include/fpu.h121
-rw-r--r--sys/arch/alpha/include/ieeefp.h39
-rw-r--r--sys/arch/alpha/include/pcb.h3
-rw-r--r--sys/arch/alpha/include/proc.h23
-rw-r--r--sys/arch/alpha/include/sysarch.h69
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_ */