summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgallatin <gallatin@FreeBSD.org>2001-03-05 21:21:01 +0000
committergallatin <gallatin@FreeBSD.org>2001-03-05 21:21:01 +0000
commit879f1f29f60b127a5399eec123c5b4aa2282a98f (patch)
treee89e3df56337400dc95d988e76c7f80c014e56aa
parent724856f88e1ffb72fefd7587d42aef40e12a9c69 (diff)
downloadFreeBSD-src-879f1f29f60b127a5399eec123c5b4aa2282a98f.zip
FreeBSD-src-879f1f29f60b127a5399eec123c5b4aa2282a98f.tar.gz
handle reserved/unimplemented instruction (opDec) faults
This lets us run programs containing newer (eg bwx) instructions on older (eg EV5 and less) machines. One win is that we can now run Acrobat4 on EV4s and EV5s. Obtained from: NetBSD Glanced at by: mjacob
-rw-r--r--sys/alpha/alpha/db_instruction.h19
-rw-r--r--sys/alpha/alpha/trap.c170
2 files changed, 187 insertions, 2 deletions
diff --git a/sys/alpha/alpha/db_instruction.h b/sys/alpha/alpha/db_instruction.h
index 172b651..19133d2 100644
--- a/sys/alpha/alpha/db_instruction.h
+++ b/sys/alpha/alpha/db_instruction.h
@@ -62,6 +62,15 @@ typedef union {
unsigned int bits;
/*
+ * Generic instruction pseudo format; look at
+ * opcode to see how to interpret the rest.
+ */
+ struct {
+ unsigned bits : 26,
+ opcode : 6;
+ } generic_format;
+
+ /*
* Memory instructions contain a 16 bit
* signed immediate value and two register
* specifiers
@@ -111,6 +120,16 @@ typedef union {
* specifier. Bit 12 sez which is which.
*/
struct {
+ unsigned rc : 5,
+ function : 7,
+ is_lit : 1,
+ sbz_or_litlo : 3,
+ rb_or_lithi : 5,
+ ra : 5,
+ opcode : 6;
+ } operate_generic_format;
+
+ struct {
unsigned rd : 5,
function : 7,
sbz : 4,
diff --git a/sys/alpha/alpha/trap.c b/sys/alpha/alpha/trap.c
index 0941a9f..9800090 100644
--- a/sys/alpha/alpha/trap.c
+++ b/sys/alpha/alpha/trap.c
@@ -69,6 +69,7 @@
#ifdef DDB
#include <ddb/ddb.h>
#endif
+#include <alpha/alpha/db_instruction.h> /* for handle_opdec() */
unsigned long Sfloat_to_reg __P((unsigned int));
unsigned int reg_to_Sfloat __P((unsigned long));
@@ -81,6 +82,7 @@ unsigned long Gfloat_reg_cvt __P((unsigned long));
int unaligned_fixup __P((unsigned long, unsigned long,
unsigned long, struct proc *));
+int handle_opdec(struct proc *p, u_int64_t *ucodep);
static void printtrap __P((const unsigned long, const unsigned long,
const unsigned long, const unsigned long, struct trapframe *, int, int));
@@ -346,8 +348,9 @@ trap(a0, a1, a2, entry, framep)
break;
case ALPHA_IF_CODE_OPDEC:
- ucode = a0; /* trap type */
- i = SIGILL;
+ i = handle_opdec(p, &ucode);
+ if (i == 0)
+ goto out;
break;
case ALPHA_IF_CODE_FEN:
@@ -1141,3 +1144,166 @@ unaligned_fixup(va, opcode, reg, p)
out:
return (signal);
}
+
+
+/*
+ * Reserved/unimplemented instruction (opDec fault) handler
+ *
+ * Argument is the process that caused it. No useful information
+ * is passed to the trap handler other than the fault type. The
+ * address of the instruction that caused the fault is 4 less than
+ * the PC stored in the trap frame.
+ *
+ * If the instruction is emulated successfully, this function returns 0.
+ * Otherwise, this function returns the signal to deliver to the process,
+ * and fills in *ucodep with the code to be delivered.
+ */
+int
+handle_opdec(p, ucodep)
+ struct proc *p;
+ u_int64_t *ucodep;
+{
+ alpha_instruction inst;
+ register_t *regptr, memaddr;
+ u_int64_t inst_pc;
+ int sig;
+
+ /*
+ * Read USP into frame in case it's going to be used or modified.
+ * This keeps us from having to check for it in lots of places
+ * later.
+ */
+ p->p_md.md_tf->tf_regs[FRAME_SP] = alpha_pal_rdusp();
+
+ inst_pc = memaddr = p->p_md.md_tf->tf_regs[FRAME_PC] - 4;
+ if (copyin((caddr_t)inst_pc, &inst, sizeof (inst)) != 0) {
+ /*
+ * really, this should never happen, but in case it
+ * does we handle it.
+ */
+ printf("WARNING: handle_opdec() couldn't fetch instruction\n");
+ goto sigsegv;
+ }
+
+ switch (inst.generic_format.opcode) {
+ case op_ldbu:
+ case op_ldwu:
+ case op_stw:
+ case op_stb:
+ regptr = irp(p, inst.mem_format.rs);
+ if (regptr != NULL)
+ memaddr = *regptr;
+ else
+ memaddr = 0;
+ memaddr += inst.mem_format.displacement;
+
+ regptr = irp(p, inst.mem_format.rd);
+
+ if (inst.mem_format.opcode == op_ldwu ||
+ inst.mem_format.opcode == op_stw) {
+ if (memaddr & 0x01) {
+ sig = unaligned_fixup(memaddr,
+ inst.mem_format.opcode,
+ inst.mem_format.rd, p);
+ if (sig)
+ goto unaligned_fixup_sig;
+ break;
+ }
+ }
+
+ if (inst.mem_format.opcode == op_ldbu) {
+ u_int8_t b;
+
+ /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
+ if (copyin((caddr_t)memaddr, &b, sizeof (b)) != 0)
+ goto sigsegv;
+ if (regptr != NULL)
+ *regptr = b;
+ } else if (inst.mem_format.opcode == op_ldwu) {
+ u_int16_t w;
+
+ /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
+ if (copyin((caddr_t)memaddr, &w, sizeof (w)) != 0)
+ goto sigsegv;
+ if (regptr != NULL)
+ *regptr = w;
+ } else if (inst.mem_format.opcode == op_stw) {
+ u_int16_t w;
+
+ /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
+ w = (regptr != NULL) ? *regptr : 0;
+ if (copyout(&w, (caddr_t)memaddr, sizeof (w)) != 0)
+ goto sigsegv;
+ } else if (inst.mem_format.opcode == op_stb) {
+ u_int8_t b;
+
+ /* XXX ONLY WORKS ON LITTLE-ENDIAN ALPHA */
+ b = (regptr != NULL) ? *regptr : 0;
+ if (copyout(&b, (caddr_t)memaddr, sizeof (b)) != 0)
+ goto sigsegv;
+ }
+ break;
+
+ case op_intmisc:
+ if (inst.operate_generic_format.function == op_sextb &&
+ inst.operate_generic_format.ra == 31) {
+ int8_t b;
+
+ if (inst.operate_generic_format.is_lit) {
+ b = inst.operate_lit_format.literal;
+ } else {
+ if (inst.operate_reg_format.sbz != 0)
+ goto sigill;
+ regptr = irp(p, inst.operate_reg_format.rt);
+ b = (regptr != NULL) ? *regptr : 0;
+ }
+
+ regptr = irp(p, inst.operate_generic_format.rc);
+ if (regptr != NULL)
+ *regptr = b;
+ break;
+ }
+ if (inst.operate_generic_format.function == op_sextw &&
+ inst.operate_generic_format.ra == 31) {
+ int16_t w;
+
+ if (inst.operate_generic_format.is_lit) {
+ w = inst.operate_lit_format.literal;
+ } else {
+ if (inst.operate_reg_format.sbz != 0)
+ goto sigill;
+ regptr = irp(p, inst.operate_reg_format.rt);
+ w = (regptr != NULL) ? *regptr : 0;
+ }
+
+ regptr = irp(p, inst.operate_generic_format.rc);
+ if (regptr != NULL)
+ *regptr = w;
+ break;
+ }
+ goto sigill;
+
+ default:
+ goto sigill;
+ }
+
+ /*
+ * Write back USP. Note that in the error cases below,
+ * nothing will have been successfully modified so we don't
+ * have to write it out.
+ */
+ alpha_pal_wrusp(p->p_md.md_tf->tf_regs[FRAME_SP]);
+
+ return (0);
+
+sigill:
+ *ucodep = ALPHA_IF_CODE_OPDEC; /* trap type */
+ return (SIGILL);
+
+sigsegv:
+ sig = SIGSEGV;
+ p->p_md.md_tf->tf_regs[FRAME_PC] = inst_pc; /* re-run instr. */
+unaligned_fixup_sig:
+ *ucodep = memaddr; /* faulting address */
+ return (sig);
+}
OpenPOWER on IntegriCloud