| From 6eae35485b26f9e51ab896eb8a936bed9908fdf6 Mon Sep 17 00:00:00 2001 |
| From: Markos Chandras <markos.chandras@imgtec.com> |
| Date: Mon, 9 Mar 2015 14:54:52 +0000 |
| Subject: MIPS: unaligned: Fix regular load/store instruction emulation for EVA |
| |
| From: Markos Chandras <markos.chandras@imgtec.com> |
| |
| commit 6eae35485b26f9e51ab896eb8a936bed9908fdf6 upstream. |
| |
| When emulating a regular lh/lw/lhu/sh/sw we need to use the appropriate |
| instruction if we are in EVA mode. This is necessary for userspace |
| applications which trigger alignment exceptions. In such case, the |
| userspace load/store instruction needs to be emulated with the correct |
| eva/non-eva instruction by the kernel emulator. |
| |
| Signed-off-by: Markos Chandras <markos.chandras@imgtec.com> |
| Fixes: c1771216ab48 ("MIPS: kernel: unaligned: Handle unaligned accesses for EVA") |
| Cc: linux-mips@linux-mips.org |
| Patchwork: https://patchwork.linux-mips.org/patch/9503/ |
| Signed-off-by: Ralf Baechle <ralf@linux-mips.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/mips/kernel/unaligned.c | 52 ++++++++++++++++++++++++++++++++++++++----- |
| 1 file changed, 47 insertions(+), 5 deletions(-) |
| |
| --- a/arch/mips/kernel/unaligned.c |
| +++ b/arch/mips/kernel/unaligned.c |
| @@ -1023,7 +1023,15 @@ static void emulate_load_store_insn(stru |
| if (!access_ok(VERIFY_READ, addr, 2)) |
| goto sigbus; |
| |
| - LoadHW(addr, value, res); |
| + if (config_enabled(CONFIG_EVA)) { |
| + if (segment_eq(get_fs(), get_ds())) |
| + LoadHW(addr, value, res); |
| + else |
| + LoadHWE(addr, value, res); |
| + } else { |
| + LoadHW(addr, value, res); |
| + } |
| + |
| if (res) |
| goto fault; |
| compute_return_epc(regs); |
| @@ -1034,7 +1042,15 @@ static void emulate_load_store_insn(stru |
| if (!access_ok(VERIFY_READ, addr, 4)) |
| goto sigbus; |
| |
| - LoadW(addr, value, res); |
| + if (config_enabled(CONFIG_EVA)) { |
| + if (segment_eq(get_fs(), get_ds())) |
| + LoadW(addr, value, res); |
| + else |
| + LoadWE(addr, value, res); |
| + } else { |
| + LoadW(addr, value, res); |
| + } |
| + |
| if (res) |
| goto fault; |
| compute_return_epc(regs); |
| @@ -1045,7 +1061,15 @@ static void emulate_load_store_insn(stru |
| if (!access_ok(VERIFY_READ, addr, 2)) |
| goto sigbus; |
| |
| - LoadHWU(addr, value, res); |
| + if (config_enabled(CONFIG_EVA)) { |
| + if (segment_eq(get_fs(), get_ds())) |
| + LoadHWU(addr, value, res); |
| + else |
| + LoadHWUE(addr, value, res); |
| + } else { |
| + LoadHWU(addr, value, res); |
| + } |
| + |
| if (res) |
| goto fault; |
| compute_return_epc(regs); |
| @@ -1104,7 +1128,16 @@ static void emulate_load_store_insn(stru |
| |
| compute_return_epc(regs); |
| value = regs->regs[insn.i_format.rt]; |
| - StoreHW(addr, value, res); |
| + |
| + if (config_enabled(CONFIG_EVA)) { |
| + if (segment_eq(get_fs(), get_ds())) |
| + StoreHW(addr, value, res); |
| + else |
| + StoreHWE(addr, value, res); |
| + } else { |
| + StoreHW(addr, value, res); |
| + } |
| + |
| if (res) |
| goto fault; |
| break; |
| @@ -1115,7 +1148,16 @@ static void emulate_load_store_insn(stru |
| |
| compute_return_epc(regs); |
| value = regs->regs[insn.i_format.rt]; |
| - StoreW(addr, value, res); |
| + |
| + if (config_enabled(CONFIG_EVA)) { |
| + if (segment_eq(get_fs(), get_ds())) |
| + StoreW(addr, value, res); |
| + else |
| + StoreWE(addr, value, res); |
| + } else { |
| + StoreW(addr, value, res); |
| + } |
| + |
| if (res) |
| goto fault; |
| break; |