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:
parent
9d8e573683
commit
c1771216ab
1 changed files with 85 additions and 1 deletions
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue