svn commit: r339514 - in head/sys/powerpc: booke include powerpc

Justin Hibbits jhibbits at FreeBSD.org
Sun Oct 21 00:43:29 UTC 2018


Author: jhibbits
Date: Sun Oct 21 00:43:27 2018
New Revision: 339514
URL: https://svnweb.freebsd.org/changeset/base/339514

Log:
  powerpcspe: Implement SPE exception handling
  
  The Signal Processing Engine (SPE) found in Freescale e500 cores (and
  others) offloads IEEE-754 compliance (NaN, Inf handling, overflow,
  underflow) to software, most likely as a means of simplifying the APU
  silicon.  Some software, like AbiWord, needs full IEEE-754 compliance,
  including NaN handling.  Implement the necessary bits to enable it.
  
  Differential Revision: https://reviews.freebsd.org/D17446

Modified:
  head/sys/powerpc/booke/booke_machdep.c
  head/sys/powerpc/booke/spe.c
  head/sys/powerpc/booke/trap_subr.S
  head/sys/powerpc/include/spr.h
  head/sys/powerpc/include/trap.h
  head/sys/powerpc/powerpc/exec_machdep.c
  head/sys/powerpc/powerpc/swtch32.S

Modified: head/sys/powerpc/booke/booke_machdep.c
==============================================================================
--- head/sys/powerpc/booke/booke_machdep.c	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/booke/booke_machdep.c	Sun Oct 21 00:43:27 2018	(r339514)
@@ -189,6 +189,10 @@ extern void *int_debug;
 extern void *int_debug_ed;
 extern void *int_vec;
 extern void *int_vecast;
+#ifdef __SPE__
+extern void *int_spe_fpdata;
+extern void *int_spe_fpround;
+#endif
 #ifdef HWPMC_HOOKS
 extern void *int_performance_counter;
 #endif
@@ -258,6 +262,10 @@ ivor_setup(void)
 	case FSL_E500v1:
 	case FSL_E500v2:
 		SET_TRAP(SPR_IVOR32, int_vec);
+#ifdef __SPE__
+		SET_TRAP(SPR_IVOR33, int_spe_fpdata);
+		SET_TRAP(SPR_IVOR34, int_spe_fpround);
+#endif
 		break;
 	}
 

Modified: head/sys/powerpc/booke/spe.c
==============================================================================
--- head/sys/powerpc/booke/spe.c	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/booke/spe.c	Sun Oct 21 00:43:27 2018	(r339514)
@@ -40,9 +40,19 @@ __FBSDID("$FreeBSD$");
 #include <sys/limits.h>
 
 #include <machine/altivec.h>
+#include <machine/fpu.h>
+#include <machine/ieeefp.h>
 #include <machine/pcb.h>
 #include <machine/psl.h>
 
+#include <powerpc/fpu/fpu_arith.h>
+#include <powerpc/fpu/fpu_emu.h>
+#include <powerpc/fpu/fpu_extern.h>
+
+void spe_handle_fpdata(struct trapframe *);
+void spe_handle_fpround(struct trapframe *);
+static int spe_emu_instr(uint32_t, struct fpemu *, struct fpn **, uint32_t *);
+
 static void
 save_vec_int(struct thread *td)
 {
@@ -75,7 +85,7 @@ save_vec_int(struct thread *td)
 
 	__asm ( "evxor 0,0,0\n"
 		"evaddumiaaw 0,0\n"
-		"evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.vr[17][0]));
+		"evstdd 0,0(%0)" :: "b"(&pcb->pcb_vec.spare[0]));
 	pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
 
 	/*
@@ -113,6 +123,7 @@ enable_vec(struct thread *td)
 	if (!(pcb->pcb_flags & PCB_VEC)) {
 		memset(&pcb->pcb_vec, 0, sizeof pcb->pcb_vec);
 		pcb->pcb_flags |= PCB_VEC;
+		pcb->pcb_vec.vscr = mfspr(SPR_SPEFSCR);
 	}
 
 	/*
@@ -121,12 +132,11 @@ enable_vec(struct thread *td)
 	 */
 	msr = mfmsr();
 	mtmsr(msr | PSL_VEC);
-	isync();
 
 	/* Restore SPEFSCR and ACC.  Use %r0 as the scratch for ACC. */
 	mtspr(SPR_SPEFSCR, pcb->pcb_vec.vscr);
 	__asm __volatile("evldd 0, 0(%0); evmra 0,0\n"
-	    :: "b"(&pcb->pcb_vec.vr[17][0]));
+	    :: "b"(&pcb->pcb_vec.spare[0]));
 
 	/* 
 	 * The lower half of each register will be restored on trap return.  Use
@@ -180,4 +190,445 @@ save_vec_nodrop(struct thread *td)
 	}
 
 	save_vec_int(td);
+}
+
+
+#define	SPE_INST_MASK	0x31f
+#define	EADD	0x200
+#define	ESUB	0x201
+#define	EABS	0x204
+#define	ENABS	0x205
+#define	ENEG	0x206
+#define	EMUL	0x208
+#define	EDIV	0x209
+#define	ECMPGT	0x20c
+#define	ECMPLT	0x20d
+#define	ECMPEQ	0x20e
+#define	ECFUI	0x210
+#define	ECFSI	0x211
+#define	ECTUI	0x214
+#define	ECTSI	0x215
+#define	ECTUF	0x216
+#define	ECTSF	0x217
+#define	ECTUIZ	0x218
+#define	ECTSIZ	0x21a
+
+#define	SPE		0x4
+#define	SPFP		0x6
+#define	DPFP		0x7
+
+#define	SPE_OPC		4
+#define	OPC_SHIFT	26
+
+#define	EVFSADD		0x280
+#define	EVFSSUB		0x281
+#define	EVFSABS		0x284
+#define	EVFSNABS	0x285
+#define	EVFSNEG		0x286
+#define	EVFSMUL		0x288
+#define	EVFSDIV		0x289
+#define	EVFSCMPGT	0x28c
+#define	EVFSCMPLT	0x28d
+#define	EVFSCMPEQ	0x28e
+#define	EVFSCFUI	0x290
+#define	EVFSCFSI	0x291
+#define	EVFSCTUI	0x294
+#define	EVFSCTSI	0x295
+#define	EVFSCTUF	0x296
+#define	EVFSCTSF	0x297
+#define	EVFSCTUIZ	0x298
+#define	EVFSCTSIZ	0x29a
+
+#define	EFSADD		0x2c0
+#define	EFSSUB		0x2c1
+#define	EFSABS		0x2c4
+#define	EFSNABS		0x2c5
+#define	EFSNEG		0x2c6
+#define	EFSMUL		0x2c8
+#define	EFSDIV		0x2c9
+#define	EFSCMPGT	0x2cc
+#define	EFSCMPLT	0x2cd
+#define	EFSCMPEQ	0x2ce
+#define	EFSCFD		0x2cf
+#define	EFSCFUI		0x2d0
+#define	EFSCFSI		0x2d1
+#define	EFSCTUI		0x2d4
+#define	EFSCTSI		0x2d5
+#define	EFSCTUF		0x2d6
+#define	EFSCTSF		0x2d7
+#define	EFSCTUIZ	0x2d8
+#define	EFSCTSIZ	0x2da
+
+#define	EFDADD		0x2e0
+#define	EFDSUB		0x2e1
+#define	EFDABS		0x2e4
+#define	EFDNABS		0x2e5
+#define	EFDNEG		0x2e6
+#define	EFDMUL		0x2e8
+#define	EFDDIV		0x2e9
+#define	EFDCMPGT	0x2ec
+#define	EFDCMPLT	0x2ed
+#define	EFDCMPEQ	0x2ee
+#define	EFDCFS		0x2ef
+#define	EFDCFUI		0x2f0
+#define	EFDCFSI		0x2f1
+#define	EFDCTUI		0x2f4
+#define	EFDCTSI		0x2f5
+#define	EFDCTUF		0x2f6
+#define	EFDCTSF		0x2f7
+#define	EFDCTUIZ	0x2f8
+#define	EFDCTSIZ	0x2fa
+
+enum {
+	NONE,
+	SINGLE,
+	DOUBLE,
+	VECTOR,
+};
+
+static uint32_t fpscr_to_spefscr(uint32_t fpscr)
+{
+	uint32_t spefscr;
+
+	spefscr = 0;
+
+	if (fpscr & FPSCR_VX)
+		spefscr |= SPEFSCR_FINV;
+	if (fpscr & FPSCR_OX)
+		spefscr |= SPEFSCR_FOVF;
+	if (fpscr & FPSCR_UX)
+		spefscr |= SPEFSCR_FUNF;
+	if (fpscr & FPSCR_ZX)
+		spefscr |= SPEFSCR_FDBZ;
+	if (fpscr & FPSCR_XX)
+		spefscr |= SPEFSCR_FX;
+
+	return (spefscr);
+}
+
+/* Sign is 0 for unsigned, 1 for signed. */
+static int
+spe_to_int(struct fpemu *fpemu, struct fpn *fpn, uint32_t *val, int sign)
+{
+	uint32_t res[2];
+
+	res[0] = fpu_ftox(fpemu, fpn, res);
+	if (res[0] != UINT_MAX && res[0] != 0)
+		fpemu->fe_cx |= FPSCR_OX;
+	else if (sign == 0 && res[0] != 0)
+		fpemu->fe_cx |= FPSCR_UX;
+	else
+		*val = res[1];
+
+	return (0);
+}
+
+/* Masked instruction */
+/*
+ * For compare instructions, returns 1 if success, 0 if not.  For all others,
+ * returns -1, or -2 if no result needs recorded.
+ */
+static int
+spe_emu_instr(uint32_t instr, struct fpemu *fpemu,
+    struct fpn **result, uint32_t *iresult)
+{
+	switch (instr & SPE_INST_MASK) {
+	case EABS:
+	case ENABS:
+	case ENEG:
+		/* Taken care of elsewhere. */
+		break;
+	case ECTUIZ:
+		fpemu->fe_cx &= ~FPSCR_RN;
+		fpemu->fe_cx |= FP_RZ;
+	case ECTUI:
+		spe_to_int(fpemu, &fpemu->fe_f2, iresult, 0);
+		return (-1);
+	case ECTSIZ:
+		fpemu->fe_cx &= ~FPSCR_RN;
+		fpemu->fe_cx |= FP_RZ;
+	case ECTSI:
+		spe_to_int(fpemu, &fpemu->fe_f2, iresult, 1);
+		return (-1);
+	case EADD:
+		*result = fpu_add(fpemu);
+		break;
+	case ESUB:
+		*result = fpu_sub(fpemu);
+		break;
+	case EMUL:
+		*result = fpu_mul(fpemu);
+		break;
+	case EDIV:
+		*result = fpu_div(fpemu);
+		break;
+	case ECMPGT:
+		fpu_compare(fpemu, 0);
+		if (fpemu->fe_cx & FPSCR_FG)
+			return (1);
+		return (0);
+	case ECMPLT:
+		fpu_compare(fpemu, 0);
+		if (fpemu->fe_cx & FPSCR_FL)
+			return (1);
+		return (0);
+	case ECMPEQ:
+		fpu_compare(fpemu, 0);
+		if (fpemu->fe_cx & FPSCR_FE)
+			return (1);
+		return (0);
+	default:
+		printf("Unknown instruction %x\n", instr);
+	}
+
+	return (-1);
+}
+
+static int
+spe_explode(struct fpemu *fe, struct fpn *fp, uint32_t type,
+    uint32_t hi, uint32_t lo)
+{
+	uint32_t s;
+
+	fp->fp_sign = hi >> 31;
+	fp->fp_sticky = 0;
+	switch (type) {
+	case SINGLE:
+		s = fpu_stof(fp, hi);
+		break;
+
+	case DOUBLE:
+		s = fpu_dtof(fp, hi, lo);
+		break;
+	}
+
+	if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) {
+		/*
+		 * Input is a signalling NaN.  All operations that return
+		 * an input NaN operand put it through a ``NaN conversion'',
+		 * which basically just means ``turn on the quiet bit''.
+		 * We do this here so that all NaNs internally look quiet
+		 * (we can tell signalling ones by their class).
+		 */
+		fp->fp_mant[0] |= FP_QUIETBIT;
+		fe->fe_cx = FPSCR_VXSNAN;	/* assert invalid operand */
+		s = FPC_SNAN;
+	}
+	fp->fp_class = s;
+
+	return (0);
+}
+
+void
+spe_handle_fpdata(struct trapframe *frame)
+{
+	struct fpemu fpemu;
+	struct fpn *result;
+	uint32_t instr, instr_sec_op;
+	uint32_t cr_shift, ra, rb, rd, src;
+	uint32_t high, low, res; /* For vector operations. */
+	uint32_t spefscr = 0;
+	uint32_t ftod_res[2];
+	int width; /* Single, Double, Vector, Integer */
+	int err;
+
+	err = fueword32((void *)frame->srr0, &instr);
+	
+	if (err != 0)
+		return;
+		/* Fault. */;
+
+	if ((instr >> OPC_SHIFT) != SPE_OPC)
+		return;
+
+	/*
+	 * 'cr' field is the upper 3 bits of rd.  Magically, since a) rd is 5
+	 * bits, b) each 'cr' field is 4 bits, and c) Only the 'GT' bit is
+	 * modified for most compare operations, the full value of rd can be
+	 * used as a shift value.
+	 */
+	rd = (instr >> 21) & 0x1f;
+	ra = (instr >> 16) & 0x1f;
+	rb = (instr >> 11) & 0x1f;
+	src = (instr >> 5) & 0x7;
+	cr_shift = 28 - (rd & 0x1f);
+
+	instr_sec_op = (instr & 0x7ff);
+
+	memset(&fpemu, 0, sizeof(fpemu));
+
+	width = NONE;
+	switch (src) {
+	case SPE:
+		save_vec_nodrop(curthread);
+		switch (instr_sec_op) {
+		case EVFSABS:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] & ~(1U << 31);
+			frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
+			break;
+		case EVFSNABS:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] | (1U << 31);
+			frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
+			break;
+		case EVFSNEG:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] ^ (1U << 31);
+			frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
+			break;
+		default:
+			/* High word */
+			spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
+			    curthread->td_pcb->pcb_vec.vr[ra][0], 0);
+			spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
+			    curthread->td_pcb->pcb_vec.vr[rb][0], 0);
+			high = spe_emu_instr(instr_sec_op, &fpemu, &result,
+			    &curthread->td_pcb->pcb_vec.vr[rd][0]);
+
+			spefscr = fpscr_to_spefscr(fpemu.fe_cx) << 16;
+			/* Clear the fpemu to start over on the lower bits. */
+			memset(&fpemu, 0, sizeof(fpemu));
+
+			/* Now low word */
+			spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
+			    frame->fixreg[ra], 0);
+			spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
+			    frame->fixreg[rb], 0);
+			spefscr |= fpscr_to_spefscr(fpemu.fe_cx);
+			low = spe_emu_instr(instr_sec_op, &fpemu, &result,
+			    &frame->fixreg[rd]);
+			if (instr_sec_op == EVFSCMPEQ ||
+			    instr_sec_op == EVFSCMPGT ||
+			    instr_sec_op == EVFSCMPLT) {
+				res = (high << 3) | (low << 2) |
+				    ((high | low) << 1) | (high & low);
+				width = NONE;
+			} else
+				width = VECTOR;
+			break;
+		}
+		enable_vec(curthread);
+		goto end;
+
+	case SPFP:
+		switch (instr_sec_op) {
+		case EFSABS:
+			frame->fixreg[rd] = frame->fixreg[ra] & ~(1U << 31);
+			break;
+		case EFSNABS:
+			frame->fixreg[rd] = frame->fixreg[ra] | (1U << 31);
+			break;
+		case EFSNEG:
+			frame->fixreg[rd] = frame->fixreg[ra] ^ (1U << 31);
+			break;
+		case EFSCFD:
+			spe_explode(&fpemu, &fpemu.fe_f3, DOUBLE,
+			    curthread->td_pcb->pcb_vec.vr[rb][0],
+			    frame->fixreg[rb]);
+			result = &fpemu.fe_f3;
+			width = SINGLE;
+			break;
+		default:
+			spe_explode(&fpemu, &fpemu.fe_f1, SINGLE,
+			    frame->fixreg[ra], 0);
+			spe_explode(&fpemu, &fpemu.fe_f2, SINGLE,
+			    frame->fixreg[rb], 0);
+			width = SINGLE;
+		}
+		break;
+	case DPFP:
+		save_vec_nodrop(curthread);
+		switch (instr_sec_op) {
+		case EFDABS:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] & ~(1U << 31);
+			break;
+		case EFDNABS:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] | (1U << 31);
+			break;
+		case EFDNEG:
+			curthread->td_pcb->pcb_vec.vr[rd][0] = 
+				curthread->td_pcb->pcb_vec.vr[ra][0] ^ (1U << 31);
+			break;
+		case EFDCFS:
+			spe_explode(&fpemu, &fpemu.fe_f3, SINGLE,
+			    frame->fixreg[rb], 0);
+			result = &fpemu.fe_f3;
+			width = DOUBLE;
+			break;
+		default:
+			spe_explode(&fpemu, &fpemu.fe_f1, DOUBLE,
+			    curthread->td_pcb->pcb_vec.vr[ra][0],
+			    frame->fixreg[ra]);
+			spe_explode(&fpemu, &fpemu.fe_f2, DOUBLE,
+			    curthread->td_pcb->pcb_vec.vr[rb][0],
+			    frame->fixreg[rb]);
+			width = DOUBLE;
+		}
+		break;
+	}
+	switch (instr_sec_op) {
+	case EFDCFS:
+	case EFSCFD:
+		/* Already handled. */
+		break;
+	default:
+		res = spe_emu_instr(instr_sec_op, &fpemu, &result,
+		    &frame->fixreg[rd]);
+		if (res != -1)
+			res <<= 2;
+		break;
+	}
+
+	switch (instr_sec_op & SPE_INST_MASK) {
+	case ECMPEQ:
+	case ECMPGT:
+	case ECMPLT:
+		frame->cr &= ~(0xf << cr_shift);
+		frame->cr |= (res << cr_shift);
+		break;
+	case ECTUI:
+	case ECTUIZ:
+	case ECTSI:
+	case ECTSIZ:
+		break;
+	default:
+		switch (width) {
+		case NONE:
+		case VECTOR:
+			break;
+		case SINGLE:
+			frame->fixreg[rd] = fpu_ftos(&fpemu, result);
+			break;
+		case DOUBLE:
+			curthread->td_pcb->pcb_vec.vr[rd][0] =
+			    fpu_ftod(&fpemu, result, ftod_res);
+			frame->fixreg[rd] = ftod_res[1];
+			enable_vec(curthread);
+			break;
+		default:
+			panic("Unknown storage width %d", width);
+			break;
+		}
+	}
+
+end:
+	spefscr |= (mfspr(SPR_SPEFSCR) & ~SPEFSCR_FINVS);
+	mtspr(SPR_SPEFSCR, spefscr);
+	frame->srr0 += 4;
+
+	return;
+}
+
+void
+spe_handle_fpround(struct trapframe *frame)
+{
+
+	/*
+	 * Punt fpround exceptions for now.  This leaves the truncated result in
+	 * the register.  We'll deal with overflow/underflow later.
+	 */
+	return;
 }

Modified: head/sys/powerpc/booke/trap_subr.S
==============================================================================
--- head/sys/powerpc/booke/trap_subr.S	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/booke/trap_subr.S	Sun Oct 21 00:43:27 2018	(r339514)
@@ -638,6 +638,28 @@ INTERRUPT(int_vecast)
 	b	trap_common
 
 
+#ifdef __SPE__
+/*****************************************************************************
+ * Floating point Assist interrupt
+ ****************************************************************************/
+INTERRUPT(int_spe_fpdata)
+	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
+	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPD)
+	addi	%r3, %r1, CALLSIZE
+	bl	spe_handle_fpdata
+	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
+	rfi
+
+INTERRUPT(int_spe_fpround)
+	STANDARD_PROLOG(SPR_SPRG1, PC_TEMPSAVE, SPR_SRR0, SPR_SRR1)
+	FRAME_SETUP(SPR_SPRG1, PC_TEMPSAVE, EXC_SPFPR)
+	addi	%r3, %r1, CALLSIZE
+	bl	spe_handle_fpround
+	FRAME_LEAVE(SPR_SRR0, SPR_SRR1)
+	rfi
+#endif
+
+
 #ifdef HWPMC_HOOKS
 /*****************************************************************************
  * PMC Interrupt

Modified: head/sys/powerpc/include/spr.h
==============================================================================
--- head/sys/powerpc/include/spr.h	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/include/spr.h	Sun Oct 21 00:43:27 2018	(r339514)
@@ -245,6 +245,33 @@
 
 #define	SPR_PTCR		0x1d0	/* Partition Table Control Register */
 #define	SPR_SPEFSCR		0x200	/* ..8 Signal Processing Engine FSCR. */
+#define	  SPEFSCR_SOVH		  0x80000000
+#define	  SPEFSCR_OVH		  0x40000000
+#define	  SPEFSCR_FGH		  0x20000000
+#define	  SPEFSCR_FXH		  0x10000000
+#define	  SPEFSCR_FINVH		  0x08000000
+#define	  SPEFSCR_FDBZH		  0x04000000
+#define	  SPEFSCR_FUNFH		  0x02000000
+#define	  SPEFSCR_FOVFH		  0x01000000
+#define	  SPEFSCR_FINXS		  0x00200000
+#define	  SPEFSCR_FINVS		  0x00100000
+#define	  SPEFSCR_FDBZS		  0x00080000
+#define	  SPEFSCR_FUNFS		  0x00040000
+#define	  SPEFSCR_FOVFS		  0x00020000
+#define	  SPEFSCR_SOV		  0x00008000
+#define	  SPEFSCR_OV		  0x00004000
+#define	  SPEFSCR_FG		  0x00002000
+#define	  SPEFSCR_FX		  0x00001000
+#define	  SPEFSCR_FINV		  0x00000800
+#define	  SPEFSCR_FDBZ		  0x00000400
+#define	  SPEFSCR_FUNF		  0x00000200
+#define	  SPEFSCR_FOVF		  0x00000100
+#define	  SPEFSCR_FINXE		  0x00000040
+#define	  SPEFSCR_FINVE		  0x00000020
+#define	  SPEFSCR_FDBZE		  0x00000010
+#define	  SPEFSCR_FUNFE		  0x00000008
+#define	  SPEFSCR_FOVFE		  0x00000004
+#define	  SPEFSCR_FRMC_M	  0x00000003
 #define	SPR_IBAT0U		0x210	/* .6. Instruction BAT Reg 0 Upper */
 #define	SPR_IBAT0L		0x211	/* .6. Instruction BAT Reg 0 Lower */
 #define	SPR_IBAT1U		0x212	/* .6. Instruction BAT Reg 1 Upper */

Modified: head/sys/powerpc/include/trap.h
==============================================================================
--- head/sys/powerpc/include/trap.h	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/include/trap.h	Sun Oct 21 00:43:27 2018	(r339514)
@@ -100,6 +100,8 @@
 #define	EXC_APU		0x1300		/* Auxiliary Processing Unit */
 #define	EXC_DEBUG	0x2f10		/* Debug trap */
 #define	EXC_VECAST_E	0x2f20		/* Altivec Assist (Book-E) */
+#define	EXC_SPFPD	0x2f30		/* SPE Floating-point Data */
+#define	EXC_SPFPR	0x2f40		/* SPE Floating-point Round */
 
 #define	EXC_LAST	0x2f00		/* Last possible exception vector */
 

Modified: head/sys/powerpc/powerpc/exec_machdep.c
==============================================================================
--- head/sys/powerpc/powerpc/exec_machdep.c	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/powerpc/exec_machdep.c	Sun Oct 21 00:43:27 2018	(r339514)
@@ -971,6 +971,10 @@ cpu_copy_thread(struct thread *td, struct thread *td0)
 	pcb2->pcb_context[0] = pcb2->pcb_lr;
 	#endif
 	pcb2->pcb_cpu.aim.usr_vsid = 0;
+#ifdef __SPE__
+	pcb2->pcb_vec.vscr = SPEFSCR_FINVE | SPEFSCR_FDBZE |
+	    SPEFSCR_FUNFE | SPEFSCR_FOVFE;
+#endif
 
 	/* Setup to release spin count in fork_exit(). */
 	td->td_md.md_spinlock_count = 1;
@@ -1016,6 +1020,10 @@ cpu_set_upcall(struct thread *td, void (*entry)(void *
 	}
 
 	td->td_pcb->pcb_flags = 0;
+#ifdef __SPE__
+	td->td_pcb->pcb_vec.vscr = SPEFSCR_FINVE | SPEFSCR_FDBZE |
+	    SPEFSCR_FUNFE | SPEFSCR_FOVFE;
+#endif
 
 	td->td_retval[0] = (register_t)entry;
 	td->td_retval[1] = 0;

Modified: head/sys/powerpc/powerpc/swtch32.S
==============================================================================
--- head/sys/powerpc/powerpc/swtch32.S	Sun Oct 21 00:35:54 2018	(r339513)
+++ head/sys/powerpc/powerpc/swtch32.S	Sun Oct 21 00:43:27 2018	(r339514)
@@ -212,4 +212,8 @@ ENTRY(fork_trampoline)
 					   trapframe to simulate FRAME_SETUP
 					   does when allocating space for
 					   a frame pointer/saved LR */
+#ifdef __SPE__
+	li	%r3,SPEFSCR_FINVE|SPEFSCR_FDBZE|SPEFSCR_FUNFE|SPEFSCR_FOVFE
+	mtspr	SPR_SPEFSCR, %r3
+#endif
 	b	trapexit


More information about the svn-src-all mailing list