diff options
author | wsm <none@none> | 2005-09-12 10:21:36 -0700 |
---|---|---|
committer | wsm <none@none> | 2005-09-12 10:21:36 -0700 |
commit | 4e8a0fa6fce12b5763c5ec0a8fdc66de5f4d8214 (patch) | |
tree | 77cd451a0d0f5840303d485e71c27dc8ddee1858 /usr/src/uts | |
parent | 66ac517ef5ae556eb413e14e9546003581b9045f (diff) | |
download | illumos-gate-4e8a0fa6fce12b5763c5ec0a8fdc66de5f4d8214.tar.gz |
6303214 unimplemented_{LDD,STD} traps need to be handled
6312645 little endian LDD/STD simulation is inconsistent with hardware
Diffstat (limited to 'usr/src/uts')
-rw-r--r-- | usr/src/uts/sparc/sys/simulate.h | 3 | ||||
-rw-r--r-- | usr/src/uts/sparc/v9/os/simulator.c | 184 | ||||
-rw-r--r-- | usr/src/uts/sparc/v9/sys/machtrap.h | 2 | ||||
-rw-r--r-- | usr/src/uts/sun4/os/trap.c | 69 | ||||
-rw-r--r-- | usr/src/uts/sun4v/ml/trap_table.s | 4 |
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 */ |