diff --git a/lib/libc/sparc64/fpu/Makefile.inc b/lib/libc/sparc64/fpu/Makefile.inc index a21672e6aa02..f311177bf193 100644 --- a/lib/libc/sparc64/fpu/Makefile.inc +++ b/lib/libc/sparc64/fpu/Makefile.inc @@ -2,5 +2,7 @@ .PATH: ${.CURDIR}/../libc/sparc64/fpu/ +CFLAGS+= -I${.CURDIR}/sparc64/sys + SRCS+= fpu.c fpu_add.c fpu_compare.c fpu_div.c fpu_explode.c fpu_implode.c \ fpu_mul.c fpu_reg.S fpu_sqrt.c fpu_subr.c diff --git a/lib/libc/sparc64/fpu/fpu.c b/lib/libc/sparc64/fpu/fpu.c index a35238ed2419..1092a67e4015 100644 --- a/lib/libc/sparc64/fpu/fpu.c +++ b/lib/libc/sparc64/fpu/fpu.c @@ -87,7 +87,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include "../sys/__sparc_utrap_private.h" +#include "__sparc_utrap_private.h" #include "fpu_emu.h" #include "fpu_extern.h" @@ -119,89 +119,52 @@ int __fpe_debug = 0; #endif /* FPU_DEBUG */ static int __fpu_execute(struct utrapframe *, struct fpemu *, u_int32_t, u_long); -static void utrap_write(char *); -static void utrap_kill_self(int); - -/* - * System call wrappers usable in an utrap environment. - */ -static void -utrap_write(char *str) -{ - int berrno; - - berrno = errno; - __sys_write(STDERR_FILENO, str, strlen(str)); - errno = berrno; -} - -static void -utrap_kill_self(sig) -{ - int berrno; - - berrno = errno; - __sys_kill(__sys_getpid(), sig); - errno = berrno; -} - -void -__fpu_panic(char *msg) -{ - - utrap_write(msg); - utrap_write("\n"); - utrap_kill_self(SIGKILL); -} /* * Need to use an fpstate on the stack; we could switch, so we cannot safely * modify the pcb one, it might get overwritten. */ -void +int __fpu_exception(struct utrapframe *uf) { struct fpemu fe; u_long fsr, tstate; u_int insn; - int rv; + int sig; fsr = uf->uf_fsr; switch (FSR_GET_FTT(fsr)) { case FSR_FTT_NONE: - utrap_write("lost FPU trap type\n"); - return; + __utrap_write("lost FPU trap type\n"); + return (0); case FSR_FTT_IEEE: - goto fatal; + return (SIGFPE); case FSR_FTT_SEQERR: - utrap_write("FPU sequence error\n"); - goto fatal; + __utrap_write("FPU sequence error\n"); + return (SIGFPE); case FSR_FTT_HWERR: - utrap_write("FPU hardware error\n"); - goto fatal; + __utrap_write("FPU hardware error\n"); + return (SIGFPE); case FSR_FTT_UNFIN: case FSR_FTT_UNIMP: break; default: - utrap_write("unknown FPU error\n"); - goto fatal; + __utrap_write("unknown FPU error\n"); + return (SIGFPE); } fe.fe_fsr = fsr & ~FSR_FTT_MASK; insn = *(u_int32_t *)uf->uf_pc; if (IF_OP(insn) != IOP_MISC || (IF_F3_OP3(insn) != INS2_FPop1 && IF_F3_OP3(insn) != INS2_FPop2)) - __fpu_panic("bogus FP fault"); + __utrap_panic("bogus FP fault"); tstate = uf->uf_state; - rv = __fpu_execute(uf, &fe, insn, tstate); - if (rv != 0) - utrap_kill_self(rv); + sig = __fpu_execute(uf, &fe, insn, tstate); + if (sig != 0) + return (sig); __asm __volatile("ldx %0, %%fsr" : : "m" (fe.fe_fsr)); - return; -fatal: - utrap_kill_self(SIGFPE); - return; + return (0); } #ifdef FPU_DEBUG @@ -223,29 +186,6 @@ __fpu_dumpfpn(struct fpn *fp) } #endif -static u_long -fetch_reg(struct utrapframe *uf, int reg) -{ - u_long offs; - struct frame *frm; - - if (reg == IREG_G0) - return (0); - else if (reg < IREG_O0) /* global */ - return (uf->uf_global[reg]); - else if (reg < IREG_L0) /* out */ - return (uf->uf_out[reg - IREG_O0]); - else { /* local, in */ - /* - * The in registers are immediately after the locals in - * the frame. - */ - frm = (struct frame *)(uf->uf_out[6] + SPOFF); - return (frm->fr_local[reg - IREG_L0]); - } - __fpu_panic("fetch_reg: bogus register"); -} - static void __fpu_mov(struct fpemu *fe, int type, int rd, int rs1, int rs2) { @@ -361,32 +301,32 @@ __fpu_execute(struct utrapframe *uf, struct fpemu *fe, u_int32_t insn, u_long ts (tstate & TSTATE_XCC_MASK) >> (TSTATE_XCC_SHIFT)); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_Z)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg == 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LEZ)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg <= 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_LZ)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg < 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_NZ)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg != 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GZ)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg > 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); case FOP(INS2_FPop2, INSFP2_FMOV_RC(IRCOND_GEZ)): - reg = fetch_reg(uf, IF_F4_RS1(insn)); + reg = __emul_fetch_reg(uf, IF_F4_RS1(insn)); if (reg >= 0) __fpu_mov(fe, type, rd, __fpu_getreg(rs2), rs2); return (0); diff --git a/lib/libc/sparc64/fpu/fpu_add.c b/lib/libc/sparc64/fpu/fpu_add.c index e321e4158cfc..405b9b83bed5 100644 --- a/lib/libc/sparc64/fpu/fpu_add.c +++ b/lib/libc/sparc64/fpu/fpu_add.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include "fpu_arith.h" #include "fpu_emu.h" #include "fpu_extern.h" +#include "__sparc_utrap_private.h" struct fpn * __fpu_add(fe) @@ -198,7 +199,7 @@ __fpu_add(fe) */ #ifdef DIAGNOSTIC if (x->fp_exp != y->fp_exp || r->fp_sticky) - __fpu_panic("fpu_add"); + __utrap_panic("fpu_add"); #endif r->fp_sign = y->fp_sign; FPU_SUBS(r3, 0, r3); diff --git a/lib/libc/sparc64/fpu/fpu_explode.c b/lib/libc/sparc64/fpu/fpu_explode.c index baa2da265ba7..6967f5ce010d 100644 --- a/lib/libc/sparc64/fpu/fpu_explode.c +++ b/lib/libc/sparc64/fpu/fpu_explode.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include "fpu_arith.h" #include "fpu_emu.h" #include "fpu_extern.h" +#include "__sparc_utrap_private.h" /* * N.B.: in all of the following, we assume the FP format is @@ -278,7 +279,7 @@ __fpu_explode(fe, fp, type, reg) break; default: - __fpu_panic("fpu_explode"); + __utrap_panic("fpu_explode"); } if (s == FPC_QNAN && (fp->fp_mant[0] & FP_QUIETBIT) == 0) { diff --git a/lib/libc/sparc64/fpu/fpu_extern.h b/lib/libc/sparc64/fpu/fpu_extern.h index fca0f065c04c..f22c46300a55 100644 --- a/lib/libc/sparc64/fpu/fpu_extern.h +++ b/lib/libc/sparc64/fpu/fpu_extern.h @@ -40,16 +40,13 @@ #ifndef _SPARC64_FPU_FPU_EXTERN_H_ #define _SPARC64_FPU_FPU_EXTERN_H_ -struct proc; -struct fpstate; struct utrapframe; union instr; struct fpemu; struct fpn; /* fpu.c */ -void __fpu_exception(struct utrapframe *tf); -void __fpu_panic(char *msg); +int __fpu_exception(struct utrapframe *tf); /* fpu_add.c */ struct fpn *__fpu_add(struct fpemu *); diff --git a/lib/libc/sparc64/fpu/fpu_implode.c b/lib/libc/sparc64/fpu/fpu_implode.c index 27a826a1ea0d..e1937a472029 100644 --- a/lib/libc/sparc64/fpu/fpu_implode.c +++ b/lib/libc/sparc64/fpu/fpu_implode.c @@ -62,6 +62,7 @@ __FBSDID("$FreeBSD$"); #include "fpu_arith.h" #include "fpu_emu.h" #include "fpu_extern.h" +#include "__sparc_utrap_private.h" static int round(struct fpemu *, struct fpn *); static int toinf(struct fpemu *, int); @@ -354,7 +355,7 @@ __fpu_ftos(fe, fp) (void) __fpu_shr(fp, FP_NMANT - FP_NG - 1 - SNG_FRACBITS); #ifdef DIAGNOSTIC if ((fp->fp_mant[3] & SNG_EXP(1 << FP_NG)) == 0) - __fpu_panic("fpu_ftos"); + __utrap_panic("fpu_ftos"); #endif if (round(fe, fp) && fp->fp_mant[3] == SNG_EXP(2)) exp++; @@ -529,7 +530,7 @@ __fpu_implode(fe, fp, type, space) break; default: - __fpu_panic("fpu_implode"); + __utrap_panic("fpu_implode"); } DPRINTF(FPE_REG, ("fpu_implode: %x %x %x %x\n", space[0], space[1], space[2], space[3])); diff --git a/lib/libc/sparc64/fpu/fpu_subr.c b/lib/libc/sparc64/fpu/fpu_subr.c index 97300a3c3915..7e6308ff129e 100644 --- a/lib/libc/sparc64/fpu/fpu_subr.c +++ b/lib/libc/sparc64/fpu/fpu_subr.c @@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); #include "fpu_arith.h" #include "fpu_emu.h" #include "fpu_extern.h" +#include "__sparc_utrap_private.h" /* * Shift the given number right rsh bits. Any bits that `fall off' will get @@ -75,7 +76,7 @@ __fpu_shr(struct fpn *fp, int rsh) #ifdef DIAGNOSTIC if (rsh <= 0 || (fp->fp_class != FPC_NUM && !ISNAN(fp))) - __fpu_panic("fpu_rightshift 1"); + __utrap_panic("fpu_rightshift 1"); #endif m0 = fp->fp_mant[0]; @@ -87,7 +88,7 @@ __fpu_shr(struct fpn *fp, int rsh) if (rsh >= FP_NMANT) { #ifdef DIAGNOSTIC if ((m0 | m1 | m2 | m3) == 0) - __fpu_panic("fpu_rightshift 2"); + __utrap_panic("fpu_rightshift 2"); #endif fp->fp_mant[0] = 0; fp->fp_mant[1] = 0; diff --git a/lib/libc/sparc64/sys/Makefile.inc b/lib/libc/sparc64/sys/Makefile.inc index 7e1d1784dab0..5eb7782eddbc 100644 --- a/lib/libc/sparc64/sys/Makefile.inc +++ b/lib/libc/sparc64/sys/Makefile.inc @@ -1,7 +1,9 @@ # $FreeBSD$ -SRCS+= __sparc_utrap.c __sparc_utrap_fp_disabled.S __sparc_utrap_gen.S \ - __sparc_utrap_install.c __sparc_utrap_setup.c +SRCS+= __sparc_utrap.c __sparc_utrap_emul.c __sparc_utrap_fp_disabled.S \ + __sparc_utrap_gen.S __sparc_utrap_install.c __sparc_utrap_setup.c + +CFLAGS+= -I${.CURDIR}/sparc64/fpu MDASM+= brk.S cerror.S exect.S pipe.S ptrace.S sbrk.S setlogin.S diff --git a/lib/libc/sparc64/sys/__sparc_utrap.c b/lib/libc/sparc64/sys/__sparc_utrap.c index f56c0190f77e..d51d89ac0148 100644 --- a/lib/libc/sparc64/sys/__sparc_utrap.c +++ b/lib/libc/sparc64/sys/__sparc_utrap.c @@ -32,8 +32,11 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include #include +#include #include "__sparc_utrap_private.h" @@ -77,23 +80,55 @@ static const char *utrap_msg[] = { void __sparc_utrap(struct utrapframe *uf) { + int sig; switch (uf->uf_type) { case UT_FP_EXCEPTION_IEEE_754: case UT_FP_EXCEPTION_OTHER: - __fpu_exception(uf); - UF_DONE(uf); - return; + sig = __fpu_exception(uf); + break; case UT_ILLEGAL_INSTRUCTION: + sig = __emul_insn(uf); + break; case UT_MEM_ADDRESS_NOT_ALIGNED: break; - case UT_TRAP_INSTRUCTION_16: - UF_DONE(uf); - return; default: break; } - printf("__sparc_utrap: type=%s pc=%#lx npc=%#lx\n", - utrap_msg[uf->uf_type], uf->uf_pc, uf->uf_npc); - abort(); + if (sig) { + __utrap_write("__sparc_utrap: fatal "); + __utrap_write(utrap_msg[uf->uf_type]); + __utrap_write("\n"); + __utrap_kill_self(sig); + } + UF_DONE(uf); +} + +void +__utrap_write(const char *str) +{ + int berrno; + + berrno = errno; + __sys_write(STDERR_FILENO, str, strlen(str)); + errno = berrno; +} + +void +__utrap_kill_self(sig) +{ + int berrno; + + berrno = errno; + __sys_kill(__sys_getpid(), sig); + errno = berrno; +} + +void +__utrap_panic(const char *msg) +{ + + __utrap_write(msg); + __utrap_write("\n"); + __utrap_kill_self(SIGKILL); } diff --git a/lib/libc/sparc64/sys/__sparc_utrap_emul.c b/lib/libc/sparc64/sys/__sparc_utrap_emul.c new file mode 100644 index 000000000000..77f49bf24a95 --- /dev/null +++ b/lib/libc/sparc64/sys/__sparc_utrap_emul.c @@ -0,0 +1,157 @@ +/*- + * Copyright (c) 2001 by Thomas Moestl . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include "__sparc_utrap_private.h" +#include "fpu_reg.h" + +int +__emul_insn(struct utrapframe *uf) +{ + u_long reg, res; + u_long *addr; + u_int insn; + int sig; + int rd; + int i; + + sig = 0; + insn = *(u_int *)uf->uf_pc; + flushw(); + switch (IF_OP(insn)) { + case IOP_MISC: + switch (IF_F3_OP3(insn)) { + case INS2_POPC: + if (IF_F3_RS1(insn) != 0) { + sig = SIGILL; + break; + } + reg = __emul_f3_op2(uf, insn); + for (i = 0; i < 64; i++) + res += (reg >> i) & 1; + __emul_store_reg(uf, IF_F3_RD(insn), res); + break; + default: + sig = SIGILL; + break; + } + break; + case IOP_LDST: + switch (IF_F3_OP3(insn)) { + case INS3_LDQF: + rd = IF_F3_RD(insn); + rd = (rd & ~3) | ((rd & 1) << 5); + addr = (u_long *)__emul_f3_memop_addr(uf, insn); + __fpu_setreg64(rd, addr[0]); + __fpu_setreg64(rd + 2, addr[1]); + break; + case INS3_STQF: + rd = IF_F3_RD(insn); + rd = (rd & ~3) | ((rd & 1) << 5); + addr = (u_long *)__emul_f3_memop_addr(uf, insn); + addr[0] = __fpu_getreg64(rd); + addr[1] = __fpu_getreg64(rd + 2); + break; + default: + sig = SIGILL; + break; + } + break; + default: + sig = SIGILL; + break; + } + return (sig); +} + +u_long +__emul_fetch_reg(struct utrapframe *uf, int reg) +{ + struct frame *frm; + + if (reg == IREG_G0) + return (0); + else if (reg < IREG_O0) /* global */ + return (uf->uf_global[reg]); + else if (reg < IREG_L0) /* out */ + return (uf->uf_out[reg - IREG_O0]); + else { /* local, in */ + /* + * The in registers are immediately after the locals in + * the frame. + */ + frm = (struct frame *)(uf->uf_out[6] + SPOFF); + return (frm->fr_local[reg - IREG_L0]); + } +} + +void +__emul_store_reg(struct utrapframe *uf, int reg, u_long val) +{ + struct frame *frm; + + if (reg == IREG_G0) + return; + if (reg < IREG_O0) /* global */ + uf->uf_global[reg] = val; + else if (reg < IREG_L0) /* out */ + uf->uf_out[reg - IREG_O0] = val; + else { + /* + * The in registers are immediately after the locals in + * the frame. + */ + frm = (struct frame *)(uf->uf_out[6] + SPOFF); + frm->fr_local[reg - IREG_L0] = val; + } +} + +u_long +__emul_f3_op2(struct utrapframe *uf, u_int insn) +{ + + if (IF_F3_I(insn) != 0) + return (IF_SIMM(insn, 13)); + else + return (__emul_fetch_reg(uf, IF_F3_RS2(insn))); +} + +u_long +__emul_f3_memop_addr(struct utrapframe *uf, u_int insn) +{ + u_long addr; + + addr = __emul_f3_op2(uf, insn) + __emul_fetch_reg(uf, IF_F3_RS1(insn)); + return (addr); +} diff --git a/lib/libc/sparc64/sys/__sparc_utrap_private.h b/lib/libc/sparc64/sys/__sparc_utrap_private.h index cd11ccd8f39e..798ed705cfc1 100644 --- a/lib/libc/sparc64/sys/__sparc_utrap_private.h +++ b/lib/libc/sparc64/sys/__sparc_utrap_private.h @@ -50,6 +50,16 @@ struct utrapframe { extern char __sparc_utrap_fp_disabled[]; extern char __sparc_utrap_gen[]; +int __emul_insn(struct utrapframe *uf); +u_long __emul_fetch_reg(struct utrapframe *uf, int reg); +void __emul_store_reg(struct utrapframe *uf, int reg, u_long val); +u_long __emul_f3_op2(struct utrapframe *uf, u_int insn); +u_long __emul_f3_memop_addr(struct utrapframe *uf, u_int insn); + void __sparc_utrap(struct utrapframe *); +void __utrap_write(const char *); +void __utrap_kill_self(int); +void __utrap_panic(const char *); + #endif diff --git a/lib/libc/sparc64/sys/__sparc_utrap_setup.c b/lib/libc/sparc64/sys/__sparc_utrap_setup.c index 68c30936ffb9..e39de99cc554 100644 --- a/lib/libc/sparc64/sys/__sparc_utrap_setup.c +++ b/lib/libc/sparc64/sys/__sparc_utrap_setup.c @@ -40,11 +40,10 @@ static const struct sparc_utrap_args ua[] = { { UT_FP_DISABLED, __sparc_utrap_fp_disabled, NULL, NULL, NULL }, { UT_FP_EXCEPTION_IEEE_754, __sparc_utrap_gen, NULL, NULL, NULL }, { UT_FP_EXCEPTION_OTHER, __sparc_utrap_gen, NULL, NULL, NULL }, -#if 0 { UT_ILLEGAL_INSTRUCTION, __sparc_utrap_gen, NULL, NULL, NULL }, +#if 0 { UT_MEM_ADDRESS_NOT_ALIGNED, __sparc_utrap_gen, NULL, NULL, NULL }, #endif - { UT_TRAP_INSTRUCTION_16, __sparc_utrap_gen, NULL, NULL, NULL }, }; static const struct sparc_utrap_install_args uia[] = {