summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2003-10-23 06:32:34 +0000
committermarcel <marcel@FreeBSD.org>2003-10-23 06:32:34 +0000
commitc3d0eca2a74609d6922853a0cd3d609293a1ff94 (patch)
tree46918bced70cb5277f668238c1cd89537d98e972 /sys
parenta1e162fe3601066bc41595f61834755406788a64 (diff)
downloadFreeBSD-src-c3d0eca2a74609d6922853a0cd3d609293a1ff94.zip
FreeBSD-src-c3d0eca2a74609d6922853a0cd3d609293a1ff94.tar.gz
Reimplement unaligned_fixup() using the new disassembler and a
mcontext_t for the register values. Currently only ld8 and ldfd instructions are handled as those are the ones we need now (a misaligned ld8 occurs 4 times in ntpd(8) and a misaligned ldfd occurs once in mozilla 1.4 and 1.5). Other instructions are added when needed.
Diffstat (limited to 'sys')
-rw-r--r--sys/ia64/ia64/unaligned.c718
1 files changed, 136 insertions, 582 deletions
diff --git a/sys/ia64/ia64/unaligned.c b/sys/ia64/ia64/unaligned.c
index 3b15652..41380bd 100644
--- a/sys/ia64/ia64/unaligned.c
+++ b/sys/ia64/ia64/unaligned.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2003 Marcel Moolenaar
* Copyright (c) 2001 Doug Rabson
* All rights reserved.
*
@@ -34,627 +35,180 @@
#include <vm/vm.h>
#include <vm/vm_extern.h>
#include <machine/frame.h>
-#include <machine/inst.h>
+#include <machine/md_var.h>
+#include <ia64/disasm/disasm.h>
-#define sign_extend(imm, w) (((int64_t)(imm) << (64 - (w))) >> (64 - (w)))
-
-static int ia64_unaligned_print = 1; /* warn about unaligned accesses */
-static int ia64_unaligned_fix = 1; /* fix up unaligned accesses */
-static int ia64_unaligned_sigbus = 0; /* don't SIGBUS on fixed-up accesses */
+static int ia64_unaligned_print = 1; /* warn about unaligned accesses. */
+static int ia64_unaligned_sigbus = 0; /* SIGBUS on all unaligned accesses. */
SYSCTL_INT(_machdep, OID_AUTO, unaligned_print, CTLFLAG_RW,
&ia64_unaligned_print, 0, "warn about unaligned accesses");
-SYSCTL_INT(_machdep, OID_AUTO, unaligned_fix, CTLFLAG_RW,
- &ia64_unaligned_fix, 0, "fix up unaligned accesses (if possible)");
-
SYSCTL_INT(_machdep, OID_AUTO, unaligned_sigbus, CTLFLAG_RW,
&ia64_unaligned_sigbus, 0, "do not SIGBUS on fixed-up accesses");
-int unaligned_fixup(struct trapframe *framep, struct thread *td);
-
-enum type {
- LD_SA,
- LD_S,
- LD_A,
- LD_C_CLR,
- LD_C_NC,
- LD
-};
-
-struct decoding {
- int isload; /* non-zero if load */
- enum type type; /* type of load or store */
- int basereg; /* address to load or store */
- int reg; /* register number to load or store */
- int width; /* number of bytes */
- int update; /* update value for basereg */
- int updateisreg; /* non-zero if update is a register */
- int fence; /* non-zero if fence needed */
-};
-
-static int
-unaligned_decode_M1(union ia64_instruction ins, struct decoding *d)
-{
- static enum type types[] = {
- LD, LD_S, LD_A, LD_SA, LD,
- LD, LD, LD_C_CLR, LD_C_NC, LD_C_CLR
- };
- d->isload = 1;
- d->type = types[ins.M1.x6 >> 2];
- d->basereg = ins.M1.r3;
- d->reg = ins.M1.r1;
- d->width = (1 << (ins.M1.x6 & 3));
- if ((ins.M1.x6 >= 0x14 && ins.M1.x6 <= 0x17)
- || (ins.M1.x6 >= 0x28 && ins.M1.x6 <= 0x2b))
- d->fence = 1;
- return 1;
-}
-
-static int
-unaligned_decode_M2(union ia64_instruction ins, struct decoding *d)
-{
- static enum type types[] = {
- LD, LD_S, LD_A, LD_SA, LD,
- LD, LD, LD_C_CLR, LD_C_NC, LD_C_CLR
- };
- d->isload = 1;
- d->type = types[ins.M1.x6 >> 2];
- d->basereg = ins.M2.r3;
- d->reg = ins.M2.r1;
- d->width = (1 << (ins.M2.x6 & 3));
- d->update = ins.M2.r2;
- d->updateisreg = 1;
- if ((ins.M2.x6 >= 0x14 && ins.M2.x6 <= 0x17)
- || (ins.M2.x6 >= 0x28 && ins.M2.x6 <= 0x2b))
- d->fence = 1;
- return 1;
-}
-
-static int
-unaligned_decode_M3(union ia64_instruction ins, struct decoding *d)
-{
- static enum type types[] = {
- LD, LD_S, LD_A, LD_SA, LD,
- LD, LD, LD_C_CLR, LD_C_NC, LD_C_CLR
- };
- d->isload = 1;
- d->type = types[ins.M1.x6 >> 2];
- d->basereg = ins.M3.r3;
- d->reg = ins.M3.r1;
- d->width = (1 << (ins.M3.x6 & 3));
- d->update = sign_extend((ins.M3.s << 8)
- | (ins.M3.i << 7)
- | ins.M3.imm7b, 9);
- if ((ins.M3.x6 >= 0x14 && ins.M3.x6 <= 0x17)
- || (ins.M3.x6 >= 0x28 && ins.M3.x6 <= 0x2b))
- d->fence = 1;
- return 1;
-}
-
-static int
-unaligned_decode_M4(union ia64_instruction ins, struct decoding *d)
-{
- d->isload = 0;
- d->basereg = ins.M4.r3;
- d->reg = ins.M4.r2;
- d->width = (1 << (ins.M4.x6 & 3));
- if (ins.M4.x6 >= 0x34 && ins.M4.x6 <= 0x37)
- d->fence = 1;
- return 1;
-}
-
-static int
-unaligned_decode_M5(union ia64_instruction ins, struct decoding *d)
+static void *
+fpreg_ptr(mcontext_t *mc, int fr)
{
- d->isload = 0;
- d->basereg = ins.M5.r3;
- d->reg = ins.M5.r2;
- d->width = (1 << (ins.M5.x6 & 3));
- d->update = sign_extend((ins.M5.s << 8)
- | (ins.M5.i << 7)
- | ins.M5.imm7a, 9);
- if (ins.M5.x6 >= 0x34 && ins.M5.x6 <= 0x37)
- d->fence = 1;
- return 1;
+ union _ia64_fpreg *p;
+
+ if (fr <= 1 || fr >= 128)
+ return (NULL);
+ if (fr >= 32) {
+ p = &mc->mc_high_fp.fr32;
+ fr -= 32;
+ } else if (fr >= 16) {
+ p = &mc->mc_preserved_fp.fr16;
+ fr -= 16;
+ } else if (fr >= 6) {
+ p = &mc->mc_scratch_fp.fr6;
+ fr -= 6;
+ } else {
+ p = &mc->mc_preserved_fp.fr2;
+ fr -= 2;
+ }
+ return ((void*)(p + fr));
}
-static int
-read_register(struct trapframe *framep, struct thread *td,
- int reg, u_int64_t *valuep)
+static void *
+greg_ptr(mcontext_t *mc, int gr)
{
-
- if (reg < 32) {
- switch (reg) {
- case 0: *valuep = 0; break;
- case 1: *valuep = framep->tf_special.gp; break;
- case 2: *valuep = framep->tf_scratch.gr2; break;
- case 3: *valuep = framep->tf_scratch.gr3; break;
- case 8: *valuep = framep->tf_scratch.gr8; break;
- case 9: *valuep = framep->tf_scratch.gr9; break;
- case 10: *valuep = framep->tf_scratch.gr10; break;
- case 11: *valuep = framep->tf_scratch.gr11; break;
- case 12: *valuep = framep->tf_special.sp; break;
- case 13: *valuep = framep->tf_special.tp; break;
- case 14: *valuep = framep->tf_scratch.gr14; break;
- case 15: *valuep = framep->tf_scratch.gr15; break;
- case 16: *valuep = framep->tf_scratch.gr16; break;
- case 17: *valuep = framep->tf_scratch.gr17; break;
- case 18: *valuep = framep->tf_scratch.gr18; break;
- case 19: *valuep = framep->tf_scratch.gr19; break;
- case 20: *valuep = framep->tf_scratch.gr20; break;
- case 21: *valuep = framep->tf_scratch.gr21; break;
- case 22: *valuep = framep->tf_scratch.gr22; break;
- case 23: *valuep = framep->tf_scratch.gr23; break;
- case 24: *valuep = framep->tf_scratch.gr24; break;
- case 25: *valuep = framep->tf_scratch.gr25; break;
- case 26: *valuep = framep->tf_scratch.gr26; break;
- case 27: *valuep = framep->tf_scratch.gr27; break;
- case 28: *valuep = framep->tf_scratch.gr28; break;
- case 29: *valuep = framep->tf_scratch.gr29; break;
- case 30: *valuep = framep->tf_scratch.gr30; break;
- case 31: *valuep = framep->tf_scratch.gr31; break;
- default:
- return (EINVAL);
- }
+ uint64_t *p;
+
+ if (gr <= 0 || gr >= 32 + (mc->mc_special.cfm & 0x7f))
+ return (NULL);
+ if (gr >= 32) {
+ p = (void*)mc->mc_special.bspstore;
+ p += gr - 32;
+ gr = 0;
+ } else if (gr >= 14) {
+ p = &mc->mc_scratch.gr14;
+ gr -= 14;
+ } else if (gr == 13) {
+ p = &mc->mc_special.tp;
+ gr = 0;
+ } else if (gr == 12) {
+ p = &mc->mc_special.sp;
+ gr = 0;
+ } else if (gr >= 8) {
+ p = &mc->mc_scratch.gr8;
+ gr -= 8;
+ } else if (gr >= 4) {
+ p = &mc->mc_preserved.gr4;
+ gr -= 4;
+ } else if (gr >= 2) {
+ p = &mc->mc_scratch.gr2;
+ gr -= 2;
} else {
-#if 0
- u_int64_t cfm = framep->tf_special.cfm;
- u_int64_t *bsp = (u_int64_t *)(td->td_kstack +
- framep->tf_ndirty);
- int sof = cfm & 0x7f;
- int sor = 8*((cfm >> 14) & 15);
- int rrb_gr = (cfm >> 18) & 0x7f;
-
- /*
- * Skip back to the start of the interrupted frame.
- */
- bsp = ia64_rse_previous_frame(bsp, sof);
-
- if (reg - 32 > sof)
- return EINVAL;
- if (reg - 32 < sor) {
- if (reg - 32 + rrb_gr >= sor)
- reg = reg + rrb_gr - sor;
- else
- reg = reg + rrb_gr;
- }
-
- *valuep = *ia64_rse_register_address(bsp, reg);
- return (0);
-#else
- return (EINVAL);
-#endif
+ p = &mc->mc_special.gp;
+ gr = 0;
}
- return (0);
+ return ((void*)(p + gr));
}
static int
-write_register(struct trapframe *framep, struct thread *td,
- int reg, u_int64_t value)
+fixup(struct asm_inst *i, mcontext_t *mc, uint64_t va)
{
-
- if (reg < 32) {
- switch (reg) {
- case 1: framep->tf_special.gp = value; break;
- case 2: framep->tf_scratch.gr2 = value; break;
- case 3: framep->tf_scratch.gr3 = value; break;
- case 8: framep->tf_scratch.gr8 = value; break;
- case 9: framep->tf_scratch.gr9 = value; break;
- case 10: framep->tf_scratch.gr10 = value; break;
- case 11: framep->tf_scratch.gr11 = value; break;
- case 12: framep->tf_special.sp = value; break;
- case 13: framep->tf_special.tp = value; break;
- case 14: framep->tf_scratch.gr14 = value; break;
- case 15: framep->tf_scratch.gr15 = value; break;
- case 16: framep->tf_scratch.gr16 = value; break;
- case 17: framep->tf_scratch.gr17 = value; break;
- case 18: framep->tf_scratch.gr18 = value; break;
- case 19: framep->tf_scratch.gr19 = value; break;
- case 20: framep->tf_scratch.gr20 = value; break;
- case 21: framep->tf_scratch.gr21 = value; break;
- case 22: framep->tf_scratch.gr22 = value; break;
- case 23: framep->tf_scratch.gr23 = value; break;
- case 24: framep->tf_scratch.gr24 = value; break;
- case 25: framep->tf_scratch.gr25 = value; break;
- case 26: framep->tf_scratch.gr26 = value; break;
- case 27: framep->tf_scratch.gr27 = value; break;
- case 28: framep->tf_scratch.gr28 = value; break;
- case 29: framep->tf_scratch.gr29 = value; break;
- case 30: framep->tf_scratch.gr30 = value; break;
- case 31: framep->tf_scratch.gr31 = value; break;
- default:
+ union {
+ double d;
+ uint64_t i;
+ } buf;
+ void *reg;
+ uint64_t postinc;
+
+ switch (i->i_op) {
+ case ASM_OP_LD8:
+ copyin((void*)va, (void*)&buf.i, 8);
+ reg = greg_ptr(mc, (int)i->i_oper[1].o_value);
+ if (reg == NULL)
return (EINVAL);
- }
- } else {
-#if 0
- u_int64_t cfm = framep->tf_special.cfm;
- u_int64_t *bsp = (u_int64_t *) (td->td_kstack
- + framep->tf_ndirty);
- int sof = cfm & 0x7f;
- int sor = 8*((cfm >> 14) & 15);
- int rrb_gr = (cfm >> 18) & 0x7f;
-
- /*
- * Skip back to the start of the interrupted frame.
- */
- bsp = ia64_rse_previous_frame(bsp, sof);
-
- if (reg - 32 > sof)
- return EINVAL;
- if (reg - 32 < sor) {
- if (reg - 32 + rrb_gr >= sor)
- reg = reg + rrb_gr - sor;
- else
- reg = reg + rrb_gr;
- }
-
- *ia64_rse_register_address(bsp, reg) = value;
- return 0;
-#else
- return (EINVAL);
-#endif
+ suword(reg, buf.i);
+ break;
+ case ASM_OP_LDFD:
+ copyin((void*)va, (void*)&buf.d, 8);
+ reg = fpreg_ptr(mc, (int)i->i_oper[1].o_value);
+ if (reg == NULL)
+ return (EINVAL);
+ spillfd((void*)&buf.d, reg);
+ break;
+ default:
+ return (ENOENT);
}
- return (0);
-}
-/*
- * Messy.
- */
-static void
-invala_e(int reg)
-{
- switch (reg) {
- case 0: __asm __volatile("invala.e r0"); break;
- case 1: __asm __volatile("invala.e r1"); break;
- case 2: __asm __volatile("invala.e r2"); break;
- case 3: __asm __volatile("invala.e r3"); break;
- case 4: __asm __volatile("invala.e r4"); break;
- case 5: __asm __volatile("invala.e r5"); break;
- case 6: __asm __volatile("invala.e r6"); break;
- case 7: __asm __volatile("invala.e r7"); break;
- case 8: __asm __volatile("invala.e r8"); break;
- case 9: __asm __volatile("invala.e r9"); break;
- case 10: __asm __volatile("invala.e r10"); break;
- case 11: __asm __volatile("invala.e r11"); break;
- case 12: __asm __volatile("invala.e r12"); break;
- case 13: __asm __volatile("invala.e r13"); break;
- case 14: __asm __volatile("invala.e r14"); break;
- case 15: __asm __volatile("invala.e r15"); break;
- case 16: __asm __volatile("invala.e r16"); break;
- case 17: __asm __volatile("invala.e r17"); break;
- case 18: __asm __volatile("invala.e r18"); break;
- case 19: __asm __volatile("invala.e r19"); break;
- case 20: __asm __volatile("invala.e r20"); break;
- case 21: __asm __volatile("invala.e r21"); break;
- case 22: __asm __volatile("invala.e r22"); break;
- case 23: __asm __volatile("invala.e r23"); break;
- case 24: __asm __volatile("invala.e r24"); break;
- case 25: __asm __volatile("invala.e r25"); break;
- case 26: __asm __volatile("invala.e r26"); break;
- case 27: __asm __volatile("invala.e r27"); break;
- case 28: __asm __volatile("invala.e r28"); break;
- case 29: __asm __volatile("invala.e r29"); break;
- case 30: __asm __volatile("invala.e r30"); break;
- case 31: __asm __volatile("invala.e r31"); break;
- case 32: __asm __volatile("invala.e r32"); break;
- case 33: __asm __volatile("invala.e r33"); break;
- case 34: __asm __volatile("invala.e r34"); break;
- case 35: __asm __volatile("invala.e r35"); break;
- case 36: __asm __volatile("invala.e r36"); break;
- case 37: __asm __volatile("invala.e r37"); break;
- case 38: __asm __volatile("invala.e r38"); break;
- case 39: __asm __volatile("invala.e r39"); break;
- case 40: __asm __volatile("invala.e r40"); break;
- case 41: __asm __volatile("invala.e r41"); break;
- case 42: __asm __volatile("invala.e r42"); break;
- case 43: __asm __volatile("invala.e r43"); break;
- case 44: __asm __volatile("invala.e r44"); break;
- case 45: __asm __volatile("invala.e r45"); break;
- case 46: __asm __volatile("invala.e r46"); break;
- case 47: __asm __volatile("invala.e r47"); break;
- case 48: __asm __volatile("invala.e r48"); break;
- case 49: __asm __volatile("invala.e r49"); break;
- case 50: __asm __volatile("invala.e r50"); break;
- case 51: __asm __volatile("invala.e r51"); break;
- case 52: __asm __volatile("invala.e r52"); break;
- case 53: __asm __volatile("invala.e r53"); break;
- case 54: __asm __volatile("invala.e r54"); break;
- case 55: __asm __volatile("invala.e r55"); break;
- case 56: __asm __volatile("invala.e r56"); break;
- case 57: __asm __volatile("invala.e r57"); break;
- case 58: __asm __volatile("invala.e r58"); break;
- case 59: __asm __volatile("invala.e r59"); break;
- case 60: __asm __volatile("invala.e r60"); break;
- case 61: __asm __volatile("invala.e r61"); break;
- case 62: __asm __volatile("invala.e r62"); break;
- case 63: __asm __volatile("invala.e r63"); break;
- case 64: __asm __volatile("invala.e r64"); break;
- case 65: __asm __volatile("invala.e r65"); break;
- case 66: __asm __volatile("invala.e r66"); break;
- case 67: __asm __volatile("invala.e r67"); break;
- case 68: __asm __volatile("invala.e r68"); break;
- case 69: __asm __volatile("invala.e r69"); break;
- case 70: __asm __volatile("invala.e r70"); break;
- case 71: __asm __volatile("invala.e r71"); break;
- case 72: __asm __volatile("invala.e r72"); break;
- case 73: __asm __volatile("invala.e r73"); break;
- case 74: __asm __volatile("invala.e r74"); break;
- case 75: __asm __volatile("invala.e r75"); break;
- case 76: __asm __volatile("invala.e r76"); break;
- case 77: __asm __volatile("invala.e r77"); break;
- case 78: __asm __volatile("invala.e r78"); break;
- case 79: __asm __volatile("invala.e r79"); break;
- case 80: __asm __volatile("invala.e r80"); break;
- case 81: __asm __volatile("invala.e r81"); break;
- case 82: __asm __volatile("invala.e r82"); break;
- case 83: __asm __volatile("invala.e r83"); break;
- case 84: __asm __volatile("invala.e r84"); break;
- case 85: __asm __volatile("invala.e r85"); break;
- case 86: __asm __volatile("invala.e r86"); break;
- case 87: __asm __volatile("invala.e r87"); break;
- case 88: __asm __volatile("invala.e r88"); break;
- case 89: __asm __volatile("invala.e r89"); break;
- case 90: __asm __volatile("invala.e r90"); break;
- case 91: __asm __volatile("invala.e r91"); break;
- case 92: __asm __volatile("invala.e r92"); break;
- case 93: __asm __volatile("invala.e r93"); break;
- case 94: __asm __volatile("invala.e r94"); break;
- case 95: __asm __volatile("invala.e r95"); break;
- case 96: __asm __volatile("invala.e r96"); break;
- case 97: __asm __volatile("invala.e r97"); break;
- case 98: __asm __volatile("invala.e r98"); break;
- case 99: __asm __volatile("invala.e r99"); break;
- case 100: __asm __volatile("invala.e r100"); break;
- case 101: __asm __volatile("invala.e r101"); break;
- case 102: __asm __volatile("invala.e r102"); break;
- case 103: __asm __volatile("invala.e r103"); break;
- case 104: __asm __volatile("invala.e r104"); break;
- case 105: __asm __volatile("invala.e r105"); break;
- case 106: __asm __volatile("invala.e r106"); break;
- case 107: __asm __volatile("invala.e r107"); break;
- case 108: __asm __volatile("invala.e r108"); break;
- case 109: __asm __volatile("invala.e r109"); break;
- case 110: __asm __volatile("invala.e r110"); break;
- case 111: __asm __volatile("invala.e r111"); break;
- case 112: __asm __volatile("invala.e r112"); break;
- case 113: __asm __volatile("invala.e r113"); break;
- case 114: __asm __volatile("invala.e r114"); break;
- case 115: __asm __volatile("invala.e r115"); break;
- case 116: __asm __volatile("invala.e r116"); break;
- case 117: __asm __volatile("invala.e r117"); break;
- case 118: __asm __volatile("invala.e r118"); break;
- case 119: __asm __volatile("invala.e r119"); break;
- case 120: __asm __volatile("invala.e r120"); break;
- case 121: __asm __volatile("invala.e r121"); break;
- case 122: __asm __volatile("invala.e r122"); break;
- case 123: __asm __volatile("invala.e r123"); break;
- case 124: __asm __volatile("invala.e r124"); break;
- case 125: __asm __volatile("invala.e r125"); break;
- case 126: __asm __volatile("invala.e r126"); break;
- case 127: __asm __volatile("invala.e r127"); break;
+ /* Handle post-increment. */
+ if (i->i_oper[3].o_type == ASM_OPER_GREG) {
+ reg = greg_ptr(mc, (int)i->i_oper[3].o_value);
+ if (reg == NULL)
+ return (EINVAL);
+ postinc = fuword(reg);
+ } else
+ postinc = (i->i_oper[3].o_type == ASM_OPER_IMM)
+ ? i->i_oper[3].o_value : 0;
+ if (postinc != 0) {
+ reg = greg_ptr(mc, (int)i->i_oper[3].o_value);
+ if (reg == NULL)
+ return (EINVAL);
+ postinc += fuword(reg);
+ suword(reg, postinc);
}
+ return (0);
}
int
-unaligned_fixup(struct trapframe *framep, struct thread *td)
+unaligned_fixup(struct trapframe *tf, struct thread *td)
{
- vm_offset_t va = framep->tf_special.ifa;
- int doprint, dofix, dosigbus;
- int signal, size = 0;
- unsigned long uac;
- struct proc *p;
- u_int64_t low, high;
- struct ia64_bundle b;
- int slot;
- union ia64_instruction ins;
- int decoded;
- struct decoding dec;
-
- /*
- * Figure out what actions to take.
- */
-
- if (td) {
- uac = td->td_md.md_flags & MDP_UAC_MASK;
- p = td->td_proc;
- } else {
- uac = 0;
- p = NULL;
+ mcontext_t context;
+ struct asm_bundle bundle;
+ int error, slot;
+
+ /* Sanity checks. */
+ if (!(tf->tf_special.isr & IA64_ISR_R) ||
+ (tf->tf_special.isr & (IA64_ISR_W|IA64_ISR_X|IA64_ISR_NA))) {
+ printf("%s: unexpected cr.isr value\n", __func__);
+ return (SIGILL);
}
- doprint = ia64_unaligned_print && !(uac & MDP_UAC_NOPRINT);
- dofix = ia64_unaligned_fix && !(uac & MDP_UAC_NOFIX);
- dosigbus = ia64_unaligned_sigbus | (uac & MDP_UAC_SIGBUS);
+ slot = ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_0) ? 0 :
+ ((tf->tf_special.psr & IA64_PSR_RI) == IA64_PSR_RI_1) ? 1 : 2;
/*
- * If psr.ac is set, then clearly the user program *wants* to
- * fault.
+ *
*/
- if (framep->tf_special.psr & IA64_PSR_AC) {
- dofix = 0;
- dosigbus = 1;
+ if (ia64_unaligned_print) {
+ uprintf("pid %d (%s): unaligned access: va=0x%lx, pc=0x%lx\n",
+ td->td_proc->p_pid, td->td_proc->p_comm,
+ tf->tf_special.ifa, tf->tf_special.iip + slot);
}
/*
- * See if the user can access the memory in question.
- * Even if it's an unknown opcode, SEGV if the access
- * should have failed.
+ * If PSR.ac is set, then the process wants to know about misaligned
+ * loads and stores. Send it a SIGBUS so that it can deal with them.
+ * We also send a SIGBUS if configured to do so.
*/
- if (!useracc((caddr_t)va, size ? size : 1, VM_PROT_WRITE)) {
- signal = SIGSEGV;
- goto out;
- }
+ if ((tf->tf_special.psr & IA64_PSR_AC) || ia64_unaligned_sigbus)
+ return (SIGBUS);
- /*
- * Read the instruction bundle and attempt to decode the
- * offending instruction.
- * XXX assume that the instruction is in an 'M' slot.
- */
- copyin((const void *) framep->tf_special.iip, &low, 8);
- copyin((const void *) (framep->tf_special.iip + 8), &high, 8);
- ia64_unpack_bundle(low, high, &b);
- slot = (framep->tf_special.psr >> 41) & 3;
- ins.ins = b.slot[slot];
-
- decoded = 0;
- bzero(&dec, sizeof(dec));
- if (ins.M1.op == 4) {
- if (ins.M1.m == 0 && ins.M1.x == 0) {
- /* Table 4-29 */
- if (ins.M1.x6 < 0x30)
- decoded = unaligned_decode_M1(ins, &dec);
- else
- decoded = unaligned_decode_M4(ins, &dec);
- } else if (ins.M1.m == 1 && ins.M1.x == 0) {
- /* Table 4-30 */
- decoded = unaligned_decode_M2(ins, &dec);
- }
- } else if (ins.M1.op == 5) {
- /* Table 4-31 */
- if (ins.M1.x6 < 0x30)
- decoded = unaligned_decode_M3(ins, &dec);
- else
- decoded = unaligned_decode_M5(ins, &dec);
- }
-
- /*
- * If we're supposed to be noisy, squawk now.
- */
- if (doprint) {
- uprintf("pid %d (%s): unaligned access: va=0x%lx pc=0x%lx",
- p->p_pid, p->p_comm, va, framep->tf_special.iip);
- if (decoded) {
- uprintf(" op=");
- if (dec.isload) {
- static char *ldops[] = {
- "ld%d.sa", "ld%d.s", "ld%d.a",
- "ld%d.c.clr", "ld%d.c.nc", "ld%d"
- };
- uprintf(ldops[dec.type], dec.width);
- uprintf(" r%d=[r%d]", dec.reg, dec.basereg);
- } else {
- uprintf("st%d [r%d]=r%d", dec.width,
- dec.basereg, dec.reg);
- }
- if (dec.updateisreg)
- uprintf(",r%d\n", dec.update);
- else if (dec.update)
- uprintf(",%d\n", dec.update);
- else
- uprintf("\n");
- } else {
- uprintf("\n");
- }
- }
-
- /*
- * If we should try to fix it and know how, give it a shot.
- *
- * We never allow bad data to be unknowingly used by the
- * user process. That is, if we decide not to fix up an
- * access we cause a SIGBUS rather than letting the user
- * process go on without warning.
- *
- * If we're trying to do a fixup, we assume that things
- * will be botched. If everything works out OK,
- * unaligned_{load,store}_* clears the signal flag.
- */
- signal = 0;
- if (dofix && decoded) {
- u_int64_t addr, update, value, isr;
- int error = 0;
-
- /*
- * We only really need this if the current bspstore
- * hasn't advanced past the user's register frame. Its
- * hardly worth trying to optimise though.
- */
- __asm __volatile("flushrs");
-
- isr = framep->tf_special.isr;
- error = read_register(framep, td, dec.basereg, &addr);
- if (error) {
- signal = SIGBUS;
- goto out;
- }
- if (dec.updateisreg) {
- error = read_register(framep, td, dec.update, &update);
- if (error) {
- signal = SIGBUS;
- goto out;
- }
- } else {
- update = dec.update;
- }
+ if (!asm_decode(tf->tf_special.iip, &bundle))
+ return (SIGILL);
- /* Assume little-endian */
- if (dec.isload) {
- /*
- * Sanity checks.
- */
- if (!(isr & IA64_ISR_R)
- || (isr & (IA64_ISR_W|IA64_ISR_X|IA64_ISR_NA))) {
- printf("unaligned_fixup: unexpected cr.isr value\n");
- signal = SIGBUS;
- goto out;
- }
+ get_mcontext(td, &context, 0);
- if (dec.type == LD_SA || dec.type == LD_A) {
- invala_e(dec.reg);
- goto out;
- }
- if (dec.type == LD_C_CLR)
- invala_e(dec.reg);
- if (dec.type == LD_S)
- /* XXX not quite sure what to do here */;
+ error = fixup(bundle.b_inst + slot, &context, tf->tf_special.ifa);
+ if (error == ENOENT) {
+ printf("unhandled misaligned memory access:\n\t");
+ asm_print_inst(&bundle, slot, tf->tf_special.iip);
+ return (SIGILL);
+ } else if (error != 0)
+ return (SIGBUS);
- value = 0;
- if (!error && dec.fence)
- ia64_mf();
- error = copyin((const void *)addr, &value, dec.width);
- if (!error)
- error = write_register(framep, td, dec.reg,
- value);
- if (!error && update)
- error = write_register(framep, td, dec.basereg,
- addr + update);
- } else {
- error = read_register(framep, td, dec.reg, &value);
- if (!error)
- error = copyout(&value, (void *)addr,
- dec.width);
- if (!error && dec.fence)
- ia64_mf();
- if (!error && update)
- error = write_register(framep, td, dec.basereg,
- addr + update);
- }
- if (error) {
- signal = SIGBUS;
- } else {
- /*
- * Advance to the instruction following the
- * one which faulted.
- */
- if ((framep->tf_special.psr & IA64_PSR_RI)
- == IA64_PSR_RI_2) {
- framep->tf_special.psr &= ~IA64_PSR_RI;
- framep->tf_special.iip += 16;
- } else {
- framep->tf_special.psr += IA64_PSR_RI_1;
- }
- }
- } else {
- signal = SIGBUS;
- }
+ set_mcontext(td, &context);
- /*
- * Force SIGBUS if requested.
- */
- if (dosigbus)
- signal = SIGBUS;
+ /* Advance to the next instruction. */
+ if (slot == 2) {
+ tf->tf_special.psr &= ~IA64_PSR_RI;
+ tf->tf_special.iip += 16;
+ } else
+ tf->tf_special.psr += IA64_PSR_RI_1;
-out:
- return (signal);
+ return (0);
}
OpenPOWER on IntegriCloud