summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/uts/sparc/sys/simulate.h3
-rw-r--r--usr/src/uts/sparc/v9/os/simulator.c184
-rw-r--r--usr/src/uts/sparc/v9/sys/machtrap.h2
-rw-r--r--usr/src/uts/sun4/os/trap.c69
-rw-r--r--usr/src/uts/sun4v/ml/trap_table.s4
5 files changed, 253 insertions, 9 deletions
diff --git a/usr/src/uts/sparc/sys/simulate.h b/usr/src/uts/sparc/sys/simulate.h
index 7ae629dd1f..56bc95f7bb 100644
--- a/usr/src/uts/sparc/sys/simulate.h
+++ b/usr/src/uts/sparc/sys/simulate.h
@@ -20,7 +20,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 1991-1998,2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -145,6 +145,7 @@ extern "C" {
extern int32_t fetch_user_instr(caddr_t);
extern int simulate_unimp(struct regs *, caddr_t *);
+extern int simulate_lddstd(struct regs *, caddr_t *);
extern int do_unaligned(struct regs *, caddr_t *);
extern int calc_memaddr(struct regs *, caddr_t *);
extern int is_atomic(struct regs *);
diff --git a/usr/src/uts/sparc/v9/os/simulator.c b/usr/src/uts/sparc/v9/os/simulator.c
index a6600d2d32..e24d2ef56d 100644
--- a/usr/src/uts/sparc/v9/os/simulator.c
+++ b/usr/src/uts/sparc/v9/os/simulator.c
@@ -53,6 +53,7 @@
#include <vm/page.h>
#include <sys/model.h>
#include <vm/seg_vn.h>
+#include <sys/byteorder.h>
#define IS_IBIT_SET(x) (x & 0x2000)
#define IS_VIS1(op, op3)(op == 2 && op3 == 0x36)
@@ -301,13 +302,24 @@ do_unaligned(struct regs *rp, caddr_t *badaddr)
}
}
} else {
- if (lddstdflg) {
+ if (lddstdflg) { /* combine the data */
if (getreg(rp, rd, &data.l[0], badaddr))
return (SIMU_FAULT);
if (getreg(rp, rd+1, &data.l[1], badaddr))
return (SIMU_FAULT);
- data.i[0] = data.i[1]; /* combine the data */
- data.i[1] = data.i[3];
+ if (ltlend) {
+ /*
+ * For STD, each 32-bit word is byte-
+ * swapped individually. For
+ * simplicity we don't want to do that
+ * below, so we swap the words now to
+ * get the desired result in the end.
+ */
+ data.i[0] = data.i[3];
+ } else {
+ data.i[0] = data.i[1];
+ data.i[1] = data.i[3];
+ }
} else {
if (getreg(rp, rd, &data.l[0], badaddr))
return (SIMU_FAULT);
@@ -507,10 +519,20 @@ do_unaligned(struct regs *rp, caddr_t *badaddr)
}
} else {
if (lddstdflg) { /* split the data */
- data.i[2] = 0;
- data.i[3] = data.i[1];
- data.i[1] = data.i[0];
+ if (ltlend) {
+ /*
+ * For LDD, each 32-bit word is byte-
+ * swapped individually. We didn't
+ * do that above, but this will give
+ * us the desired result.
+ */
+ data.i[3] = data.i[0];
+ } else {
+ data.i[3] = data.i[1];
+ data.i[1] = data.i[0];
+ }
data.i[0] = 0;
+ data.i[2] = 0;
if (putreg(&data.l[0], rp, rd, badaddr) == -1)
goto badret;
if (putreg(&data.l[1], rp, rd+1, badaddr) == -1)
@@ -526,6 +548,156 @@ badret:
return (SIMU_FAULT);
}
+
+int
+simulate_lddstd(struct regs *rp, caddr_t *badaddr)
+{
+ uint_t inst, op3, asi = 0;
+ uint_t rd, rs1, rs2;
+ int rv = 0;
+ int nf = 0, ltlend = 0, usermode;
+ int immflg;
+ uint64_t reven;
+ uint64_t rodd;
+ caddr_t addr;
+ uint64_t val;
+ uint64_t data;
+
+ usermode = USERMODE(rp->r_tstate);
+
+ if (usermode)
+ inst = fetch_user_instr((caddr_t)rp->r_pc);
+ else
+ inst = *(uint_t *)rp->r_pc;
+
+ op3 = (inst >> 19) & 0x3f;
+ rd = (inst >> 25) & 0x1f;
+ rs1 = (inst >> 14) & 0x1f;
+ rs2 = inst & 0x1f;
+ immflg = (inst >> 13) & 1;
+
+ if (USERMODE(rp->r_tstate))
+ (void) flush_user_windows_to_stack(NULL);
+ else
+ flush_windows();
+
+ if ((op3 >> 4) & 1) { /* is this LDDA/STDA? */
+ if (immflg) {
+ asi = (uint_t)(rp->r_tstate >> TSTATE_ASI_SHIFT) &
+ TSTATE_ASI_MASK;
+ } else {
+ asi = (inst >> 5) & 0xff;
+ }
+ switch (asi) {
+ case ASI_P:
+ case ASI_S:
+ break;
+ case ASI_PNF:
+ case ASI_SNF:
+ nf = 1;
+ break;
+ case ASI_PL:
+ case ASI_SL:
+ ltlend = 1;
+ break;
+ case ASI_PNFL:
+ case ASI_SNFL:
+ ltlend = 1;
+ nf = 1;
+ break;
+ case ASI_AIUP:
+ case ASI_AIUS:
+ usermode = 1;
+ break;
+ case ASI_AIUPL:
+ case ASI_AIUSL:
+ usermode = 1;
+ ltlend = 1;
+ break;
+ default:
+ return (SIMU_ILLEGAL);
+ }
+ }
+
+ if (getreg(rp, rs1, &val, badaddr))
+ return (SIMU_FAULT);
+ addr = (caddr_t)val; /* convert to 32/64 bit address */
+
+ /* check immediate bit and use immediate field or reg (rs2) */
+ if (immflg) {
+ int imm;
+ imm = inst & 0x1fff; /* mask out immediate field */
+ imm <<= 19; /* sign extend it */
+ imm >>= 19;
+ addr += imm; /* compute address */
+ } else {
+ if (getreg(rp, rs2, &val, badaddr))
+ return (SIMU_FAULT);
+ addr += val;
+ }
+
+ /*
+ * T_UNIMP_LDD and T_UNIMP_STD are higher priority than
+ * T_ALIGNMENT. So we have to make sure that the address is
+ * kosher before trying to use it, because the hardware hasn't
+ * checked it for us yet.
+ */
+ if (((uintptr_t)addr & 0x7) != 0) {
+ if (curproc->p_fixalignment)
+ return (do_unaligned(rp, badaddr));
+ else
+ return (SIMU_UNALIGN);
+ }
+
+ /*
+ * If this is a 32-bit program, chop the address accordingly.
+ */
+ if (curproc->p_model == DATAMODEL_ILP32 && usermode)
+ addr = (caddr_t)(caddr32_t)addr;
+
+ if ((inst >> 21) & 1) { /* store */
+ if (getreg(rp, rd, &reven, badaddr))
+ return (SIMU_FAULT);
+ if (getreg(rp, rd+1, &rodd, badaddr))
+ return (SIMU_FAULT);
+ if (ltlend) {
+ reven = BSWAP_32(reven);
+ rodd = BSWAP_32(rodd);
+ }
+ data = (reven << 32) | rodd;
+ if (usermode) {
+ if (suword64_nowatch(addr, data) == -1)
+ return (SIMU_FAULT);
+ } else {
+ *(uint64_t *)addr = data;
+ }
+ } else { /* load */
+ if (usermode) {
+ if (fuword64_nowatch(addr, &data)) {
+ if (nf)
+ data = 0;
+ else
+ return (SIMU_FAULT);
+ }
+ } else
+ data = *(uint64_t *)addr;
+
+ reven = (data >> 32);
+ rodd = (uint64_t)(uint32_t)data;
+ if (ltlend) {
+ reven = BSWAP_32(reven);
+ rodd = BSWAP_32(rodd);
+ }
+
+ if (putreg(&reven, rp, rd, badaddr) == -1)
+ return (SIMU_FAULT);
+ if (putreg(&rodd, rp, rd+1, badaddr) == -1)
+ return (SIMU_FAULT);
+ }
+ return (SIMU_SUCCESS);
+}
+
+
/*
* simulate popc
*/
diff --git a/usr/src/uts/sparc/v9/sys/machtrap.h b/usr/src/uts/sparc/v9/sys/machtrap.h
index 09ca0edae8..7f4b3cd4cd 100644
--- a/usr/src/uts/sparc/v9/sys/machtrap.h
+++ b/usr/src/uts/sparc/v9/sys/machtrap.h
@@ -53,6 +53,8 @@ extern "C" {
#define T_INSTR_ERROR 0x00A
#define T_UNIMP_INSTR 0x010
#define T_PRIV_INSTR 0x011
+#define T_UNIMP_LDD 0x012
+#define T_UNIMP_STD 0x013
#define T_FP_DISABLED 0x020
#define T_FP_EXCEPTION_IEEE 0x021
#define T_FP_EXCEPTION_OTHER 0x022
diff --git a/usr/src/uts/sun4/os/trap.c b/usr/src/uts/sun4/os/trap.c
index 9bb6440546..8cd6c11b2c 100644
--- a/usr/src/uts/sun4/os/trap.c
+++ b/usr/src/uts/sun4/os/trap.c
@@ -958,6 +958,75 @@ trap(struct regs *rp, caddr_t addr, uint32_t type, uint32_t mmu_fsr)
}
break;
+ case T_UNIMP_LDD + T_USER:
+ case T_UNIMP_STD + T_USER:
+ if (tudebug)
+ showregs(type, rp, (caddr_t)0, 0);
+ switch (simulate_lddstd(rp, &badaddr)) {
+ case SIMU_SUCCESS:
+ /* skip the successfully simulated instruction */
+ rp->r_pc = rp->r_npc;
+ rp->r_npc += 4;
+ goto out;
+ /*NOTREACHED*/
+
+ case SIMU_FAULT:
+ if (nfload(rp, NULL))
+ goto out;
+ siginfo.si_signo = SIGSEGV;
+ siginfo.si_code = SEGV_MAPERR;
+ siginfo.si_addr = badaddr;
+ fault = FLTBOUNDS;
+ break;
+
+ case SIMU_UNALIGN:
+ if (nfload(rp, NULL))
+ goto out;
+ siginfo.si_signo = SIGBUS;
+ siginfo.si_code = BUS_ADRALN;
+ siginfo.si_addr = badaddr;
+ fault = FLTACCESS;
+ break;
+
+ case SIMU_ILLEGAL:
+ default:
+ siginfo.si_signo = SIGILL;
+ siginfo.si_code = ILL_ILLOPC;
+ siginfo.si_addr = (caddr_t)rp->r_pc;
+ fault = FLTILL;
+ break;
+ }
+ break;
+
+ case T_UNIMP_LDD:
+ case T_UNIMP_STD:
+ if (simulate_lddstd(rp, &badaddr) == SIMU_SUCCESS) {
+ /* skip the successfully simulated instruction */
+ rp->r_pc = rp->r_npc;
+ rp->r_npc += 4;
+ goto cleanup;
+ /*NOTREACHED*/
+ }
+ /*
+ * A third party driver executed an {LDD,STD,LDDA,STDA}
+ * that we couldn't simulate.
+ */
+ if (nfload(rp, NULL))
+ goto cleanup;
+
+ if (curthread->t_lofault) {
+ if (lodebug) {
+ showregs(type, rp, addr, 0);
+ traceback((caddr_t)rp->r_sp);
+ }
+ rp->r_g1 = EFAULT;
+ rp->r_pc = curthread->t_lofault;
+ rp->r_npc = rp->r_pc + 4;
+ goto cleanup;
+ }
+ (void) die(type, rp, addr, 0);
+ /*NOTREACHED*/
+
case T_IDIV0 + T_USER: /* integer divide by zero */
case T_DIV0 + T_USER: /* integer divide by zero */
if (tudebug && tudebugfpe)
diff --git a/usr/src/uts/sun4v/ml/trap_table.s b/usr/src/uts/sun4v/ml/trap_table.s
index d2b1bb50f2..2f47413e18 100644
--- a/usr/src/uts/sun4v/ml/trap_table.s
+++ b/usr/src/uts/sun4v/ml/trap_table.s
@@ -1118,8 +1118,8 @@ trap_table0:
NOT; NOT4; /* 00B - 00F reserved */
ILLTRAP_INSTR; /* 010 illegal instruction */
TRAP(T_PRIV_INSTR); /* 011 privileged opcode */
- NOT; /* 012 unimplemented LDD */
- NOT; /* 013 unimplemented STD */
+ TRAP(T_UNIMP_LDD); /* 012 unimplemented LDD */
+ TRAP(T_UNIMP_STD); /* 013 unimplemented STD */
NOT4; NOT4; NOT4; /* 014 - 01F reserved */
FP_DISABLED_TRAP; /* 020 fp disabled */
FP_IEEE_TRAP; /* 021 fp exception ieee 754 */