MIPS: kernel: unaligned: Handle unaligned accesses for EVA

Handle unaligned accesses when we access userspace memory
EVA mode.

Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
This commit is contained in:
Leonid Yegoshin 2013-12-12 16:15:15 +00:00 committed by Ralf Baechle
parent 9d8e573683
commit c1771216ab

View file

@ -431,7 +431,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
unsigned long origpc; unsigned long origpc;
unsigned long orig31; unsigned long orig31;
void __user *fault_addr = NULL; void __user *fault_addr = NULL;
#ifdef CONFIG_EVA
mm_segment_t seg;
#endif
origpc = (unsigned long)pc; origpc = (unsigned long)pc;
orig31 = regs->regs[31]; orig31 = regs->regs[31];
@ -476,6 +478,88 @@ static void emulate_load_store_insn(struct pt_regs *regs,
* The remaining opcodes are the ones that are really of * The remaining opcodes are the ones that are really of
* interest. * interest.
*/ */
#ifdef CONFIG_EVA
case spec3_op:
/*
* we can land here only from kernel accessing user memory,
* so we need to "switch" the address limit to user space, so
* address check can work properly.
*/
seg = get_fs();
set_fs(USER_DS);
switch (insn.spec3_format.func) {
case lhe_op:
if (!access_ok(VERIFY_READ, addr, 2)) {
set_fs(seg);
goto sigbus;
}
LoadHW(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
}
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case lwe_op:
if (!access_ok(VERIFY_READ, addr, 4)) {
set_fs(seg);
goto sigbus;
}
LoadW(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
}
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case lhue_op:
if (!access_ok(VERIFY_READ, addr, 2)) {
set_fs(seg);
goto sigbus;
}
LoadHWU(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
}
compute_return_epc(regs);
regs->regs[insn.spec3_format.rt] = value;
break;
case she_op:
if (!access_ok(VERIFY_WRITE, addr, 2)) {
set_fs(seg);
goto sigbus;
}
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreHW(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
}
break;
case swe_op:
if (!access_ok(VERIFY_WRITE, addr, 4)) {
set_fs(seg);
goto sigbus;
}
compute_return_epc(regs);
value = regs->regs[insn.spec3_format.rt];
StoreW(addr, value, res);
if (res) {
set_fs(seg);
goto fault;
}
break;
default:
set_fs(seg);
goto sigill;
}
set_fs(seg);
break;
#endif
case lh_op: case lh_op:
if (!access_ok(VERIFY_READ, addr, 2)) if (!access_ok(VERIFY_READ, addr, 2))
goto sigbus; goto sigbus;