diff options
author | Markos Chandras <markos.chandras@imgtec.com> | 2015-03-09 10:54:52 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2015-04-10 09:41:45 -0400 |
commit | 6eae35485b26f9e51ab896eb8a936bed9908fdf6 (patch) | |
tree | 2b0d658ad890bdd012942abd736af3275dbfb72a | |
parent | 3563c32d6532ece53c9dd8905a8e41983ef9952f (diff) |
MIPS: unaligned: Fix regular load/store instruction emulation for EVA
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: <stable@vger.kernel.org> # v3.15+
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/9503/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r-- | arch/mips/kernel/unaligned.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index ab475903175f..7659da224fcd 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c | |||
@@ -1023,7 +1023,15 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1023 | if (!access_ok(VERIFY_READ, addr, 2)) | 1023 | if (!access_ok(VERIFY_READ, addr, 2)) |
1024 | goto sigbus; | 1024 | goto sigbus; |
1025 | 1025 | ||
1026 | LoadHW(addr, value, res); | 1026 | if (config_enabled(CONFIG_EVA)) { |
1027 | if (segment_eq(get_fs(), get_ds())) | ||
1028 | LoadHW(addr, value, res); | ||
1029 | else | ||
1030 | LoadHWE(addr, value, res); | ||
1031 | } else { | ||
1032 | LoadHW(addr, value, res); | ||
1033 | } | ||
1034 | |||
1027 | if (res) | 1035 | if (res) |
1028 | goto fault; | 1036 | goto fault; |
1029 | compute_return_epc(regs); | 1037 | compute_return_epc(regs); |
@@ -1034,7 +1042,15 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1034 | if (!access_ok(VERIFY_READ, addr, 4)) | 1042 | if (!access_ok(VERIFY_READ, addr, 4)) |
1035 | goto sigbus; | 1043 | goto sigbus; |
1036 | 1044 | ||
1037 | LoadW(addr, value, res); | 1045 | if (config_enabled(CONFIG_EVA)) { |
1046 | if (segment_eq(get_fs(), get_ds())) | ||
1047 | LoadW(addr, value, res); | ||
1048 | else | ||
1049 | LoadWE(addr, value, res); | ||
1050 | } else { | ||
1051 | LoadW(addr, value, res); | ||
1052 | } | ||
1053 | |||
1038 | if (res) | 1054 | if (res) |
1039 | goto fault; | 1055 | goto fault; |
1040 | compute_return_epc(regs); | 1056 | compute_return_epc(regs); |
@@ -1045,7 +1061,15 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1045 | if (!access_ok(VERIFY_READ, addr, 2)) | 1061 | if (!access_ok(VERIFY_READ, addr, 2)) |
1046 | goto sigbus; | 1062 | goto sigbus; |
1047 | 1063 | ||
1048 | LoadHWU(addr, value, res); | 1064 | if (config_enabled(CONFIG_EVA)) { |
1065 | if (segment_eq(get_fs(), get_ds())) | ||
1066 | LoadHWU(addr, value, res); | ||
1067 | else | ||
1068 | LoadHWUE(addr, value, res); | ||
1069 | } else { | ||
1070 | LoadHWU(addr, value, res); | ||
1071 | } | ||
1072 | |||
1049 | if (res) | 1073 | if (res) |
1050 | goto fault; | 1074 | goto fault; |
1051 | compute_return_epc(regs); | 1075 | compute_return_epc(regs); |
@@ -1104,7 +1128,16 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1104 | 1128 | ||
1105 | compute_return_epc(regs); | 1129 | compute_return_epc(regs); |
1106 | value = regs->regs[insn.i_format.rt]; | 1130 | value = regs->regs[insn.i_format.rt]; |
1107 | StoreHW(addr, value, res); | 1131 | |
1132 | if (config_enabled(CONFIG_EVA)) { | ||
1133 | if (segment_eq(get_fs(), get_ds())) | ||
1134 | StoreHW(addr, value, res); | ||
1135 | else | ||
1136 | StoreHWE(addr, value, res); | ||
1137 | } else { | ||
1138 | StoreHW(addr, value, res); | ||
1139 | } | ||
1140 | |||
1108 | if (res) | 1141 | if (res) |
1109 | goto fault; | 1142 | goto fault; |
1110 | break; | 1143 | break; |
@@ -1115,7 +1148,16 @@ static void emulate_load_store_insn(struct pt_regs *regs, | |||
1115 | 1148 | ||
1116 | compute_return_epc(regs); | 1149 | compute_return_epc(regs); |
1117 | value = regs->regs[insn.i_format.rt]; | 1150 | value = regs->regs[insn.i_format.rt]; |
1118 | StoreW(addr, value, res); | 1151 | |
1152 | if (config_enabled(CONFIG_EVA)) { | ||
1153 | if (segment_eq(get_fs(), get_ds())) | ||
1154 | StoreW(addr, value, res); | ||
1155 | else | ||
1156 | StoreWE(addr, value, res); | ||
1157 | } else { | ||
1158 | StoreW(addr, value, res); | ||
1159 | } | ||
1160 | |||
1119 | if (res) | 1161 | if (res) |
1120 | goto fault; | 1162 | goto fault; |
1121 | break; | 1163 | break; |