void handle_unaligned(struct pt_regs *regs)
{ static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5); unsignedlong newbase = R1(regs->iir)?regs->gr[R1(regs->iir)]:0; int modify = 0; int ret = ERR_NOTHANDLED;
__inc_irq_stat(irq_unaligned_count);
/* log a message with pacing */ if (user_mode(regs)) { if (current->thread.flags & PARISC_UAC_SIGBUS) { goto force_sigbus;
}
if (!(current->thread.flags & PARISC_UAC_NOPRINT) &&
__ratelimit(&ratelimit)) {
printk(KERN_WARNING "%s(%d): unaligned access to " RFMT " at ip " RFMT " (iir " RFMT ")\n",
current->comm, task_pid_nr(current), regs->ior,
regs->iaoq[0], regs->iir); #ifdef DEBUG_UNALIGNED
show_regs(regs); #endif
}
if (!unaligned_enabled) goto force_sigbus;
} else { static DEFINE_RATELIMIT_STATE(kernel_ratelimit, 5 * HZ, 5); if (!(current->thread.flags & PARISC_UAC_NOPRINT) &&
!no_unaligned_warning &&
__ratelimit(&kernel_ratelimit))
pr_warn("Kernel: unaligned access to " RFMT " in %pS " "(iir " RFMT ")\n",
regs->ior, (void *)regs->iaoq[0], regs->iir);
}
/* handle modification - OK, it's ugly, see the instruction manual */ switch (MAJOR_OP(regs->iir))
{ case 0x03: case 0x09: case 0x0b: if (regs->iir&0x20)
{
modify = 1; if (regs->iir&0x1000) /* short loads */ if (regs->iir&0x200)
newbase += IM5_3(regs->iir); else
newbase += IM5_2(regs->iir); elseif (regs->iir&0x2000) /* scaled indexed */
{ int shift=0; switch (regs->iir & OPCODE1_MASK)
{ case OPCODE_LDH_I:
shift= 1; break; case OPCODE_LDW_I:
shift= 2; break; case OPCODE_LDD_I: case OPCODE_LDDA_I:
shift= 3; break;
}
newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0)<<shift;
} else/* simple indexed */
newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0);
} break; case 0x13: case 0x1b:
modify = 1;
newbase += IM14(regs->iir); break; case 0x14: case 0x1c: if (regs->iir&8)
{
modify = 1;
newbase += IM14(regs->iir&~0xe);
} break; case 0x16: case 0x1e:
modify = 1;
newbase += IM14(regs->iir&6); break; case 0x17: case 0x1f: if (regs->iir&4)
{
modify = 1;
newbase += IM14(regs->iir&~4);
} break;
}
/* TODO: make this cleaner... */ switch (regs->iir & OPCODE1_MASK)
{ case OPCODE_LDH_I: case OPCODE_LDH_S:
ret = emulate_ldh(regs, R3(regs->iir)); break;
case OPCODE_LDW_I: case OPCODE_LDWA_I: case OPCODE_LDW_S: case OPCODE_LDWA_S:
ret = emulate_ldw(regs, R3(regs->iir), 0); break;
case OPCODE_STH:
ret = emulate_sth(regs, R2(regs->iir)); break;
case OPCODE_STW: case OPCODE_STWA:
ret = emulate_stw(regs, R2(regs->iir), 0); break;
#ifdef CONFIG_64BIT case OPCODE_LDD_I: case OPCODE_LDDA_I: case OPCODE_LDD_S: case OPCODE_LDDA_S:
ret = emulate_ldd(regs, R3(regs->iir), 0); break;
case OPCODE_STD: case OPCODE_STDA:
ret = emulate_std(regs, R2(regs->iir), 0); break; #endif
case OPCODE_FLDWX: case OPCODE_FLDWS: case OPCODE_FLDWXR: case OPCODE_FLDWSR:
ret = emulate_ldw(regs, FR3(regs->iir), 1); break;
case OPCODE_FLDDX: case OPCODE_FLDDS:
ret = emulate_ldd(regs, R3(regs->iir), 1); break;
case OPCODE_FSTWX: case OPCODE_FSTWS: case OPCODE_FSTWXR: case OPCODE_FSTWSR:
ret = emulate_stw(regs, FR3(regs->iir), 1); break;
case OPCODE_FSTDX: case OPCODE_FSTDS:
ret = emulate_std(regs, R3(regs->iir), 1); break;
case OPCODE_LDCD_I: case OPCODE_LDCW_I: case OPCODE_LDCD_S: case OPCODE_LDCW_S:
ret = ERR_NOTHANDLED; /* "undefined", but lets kill them. */ break;
} switch (regs->iir & OPCODE2_MASK)
{ case OPCODE_FLDD_L:
ret = emulate_ldd(regs,R2(regs->iir),1); break; case OPCODE_FSTD_L:
ret = emulate_std(regs, R2(regs->iir),1); break; #ifdef CONFIG_64BIT case OPCODE_LDD_L:
ret = emulate_ldd(regs, R2(regs->iir),0); break; case OPCODE_STD_L:
ret = emulate_std(regs, R2(regs->iir),0); break; #endif
} switch (regs->iir & OPCODE3_MASK)
{ case OPCODE_FLDW_L:
ret = emulate_ldw(regs, R2(regs->iir), 1); break; case OPCODE_LDW_M:
ret = emulate_ldw(regs, R2(regs->iir), 0); break;
case OPCODE_FSTW_L:
ret = emulate_stw(regs, R2(regs->iir),1); break; case OPCODE_STW_M:
ret = emulate_stw(regs, R2(regs->iir),0); break;
} switch (regs->iir & OPCODE4_MASK)
{ case OPCODE_LDH_L:
ret = emulate_ldh(regs, R2(regs->iir)); break; case OPCODE_LDW_L: case OPCODE_LDWM:
ret = emulate_ldw(regs, R2(regs->iir),0); break; case OPCODE_STH_L:
ret = emulate_sth(regs, R2(regs->iir)); break; case OPCODE_STW_L: case OPCODE_STWM:
ret = emulate_stw(regs, R2(regs->iir),0); break;
}
if (ret == ERR_NOTHANDLED)
printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
DPRINTF("ret = %d\n", ret);
if (ret)
{ /* * The unaligned handler failed. * If we were called by __get_user() or __put_user() jump * to it's exception fixup handler instead of crashing.
*/ if (!user_mode(regs) && fixup_exception(regs)) return;
printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
die_if_kernel("Unaligned data reference", regs, 28);
case OPCODE_LDH_I: case OPCODE_LDH_S: case OPCODE_STH:
align_mask = 1UL; break;
case OPCODE_LDW_I: case OPCODE_LDWA_I: case OPCODE_LDW_S: case OPCODE_LDWA_S: case OPCODE_STW: case OPCODE_STWA:
align_mask = 3UL; break;
default: switch (regs->iir & OPCODE4_MASK) { case OPCODE_LDH_L: case OPCODE_STH_L:
align_mask = 1UL; break; case OPCODE_LDW_L: case OPCODE_LDWM: case OPCODE_STW_L: case OPCODE_STWM:
align_mask = 3UL; break;
} break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.