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 /arch/mips/kernel | |
| 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>
Diffstat (limited to 'arch/mips/kernel')
| -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; |
