diff options
author | marcel <marcel@FreeBSD.org> | 2003-10-23 06:32:34 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2003-10-23 06:32:34 +0000 |
commit | c3d0eca2a74609d6922853a0cd3d609293a1ff94 (patch) | |
tree | 46918bced70cb5277f668238c1cd89537d98e972 /sys | |
parent | a1e162fe3601066bc41595f61834755406788a64 (diff) | |
download | FreeBSD-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.c | 718 |
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); } |