diff options
-rw-r--r-- | arch/sh/kernel/traps_32.c | 68 |
1 files changed, 23 insertions, 45 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 2e58f7a6b746..7154a7b2135b 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c | |||
@@ -147,6 +147,21 @@ static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err) | |||
147 | return -EFAULT; | 147 | return -EFAULT; |
148 | } | 148 | } |
149 | 149 | ||
150 | static inline void sign_extend(unsigned int count, unsigned char *dst) | ||
151 | { | ||
152 | #ifdef __LITTLE_ENDIAN__ | ||
153 | if ((count == 2) && dst[1] & 0x80) { | ||
154 | dst[2] = 0xff; | ||
155 | dst[3] = 0xff; | ||
156 | } | ||
157 | #else | ||
158 | if ((count == 2) && dst[2] & 0x80) { | ||
159 | dst[0] = 0xff; | ||
160 | dst[1] = 0xff; | ||
161 | } | ||
162 | #endif | ||
163 | } | ||
164 | |||
150 | /* | 165 | /* |
151 | * handle an instruction that does an unaligned memory access by emulating the | 166 | * handle an instruction that does an unaligned memory access by emulating the |
152 | * desired behaviour | 167 | * desired behaviour |
@@ -178,25 +193,13 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
178 | dst = (unsigned char*) rn; | 193 | dst = (unsigned char*) rn; |
179 | *(unsigned long*)dst = 0; | 194 | *(unsigned long*)dst = 0; |
180 | 195 | ||
181 | #ifdef __LITTLE_ENDIAN__ | 196 | #if !defined(__LITTLE_ENDIAN__) |
182 | if (copy_from_user(dst, src, count)) | ||
183 | goto fetch_fault; | ||
184 | |||
185 | if ((count == 2) && dst[1] & 0x80) { | ||
186 | dst[2] = 0xff; | ||
187 | dst[3] = 0xff; | ||
188 | } | ||
189 | #else | ||
190 | dst += 4-count; | 197 | dst += 4-count; |
191 | 198 | #endif | |
192 | if (__copy_user(dst, src, count)) | 199 | if (copy_from_user(dst, src, count)) |
193 | goto fetch_fault; | 200 | goto fetch_fault; |
194 | 201 | ||
195 | if ((count == 2) && dst[2] & 0x80) { | 202 | sign_extend(count, dst); |
196 | dst[0] = 0xff; | ||
197 | dst[1] = 0xff; | ||
198 | } | ||
199 | #endif | ||
200 | } else { | 203 | } else { |
201 | /* to memory */ | 204 | /* to memory */ |
202 | src = (unsigned char*) rm; | 205 | src = (unsigned char*) rm; |
@@ -253,25 +256,12 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
253 | dst = (unsigned char*) rn; | 256 | dst = (unsigned char*) rn; |
254 | *(unsigned long*)dst = 0; | 257 | *(unsigned long*)dst = 0; |
255 | 258 | ||
256 | #ifdef __LITTLE_ENDIAN__ | 259 | #if !defined(__LITTLE_ENDIAN__) |
257 | if (copy_from_user(dst, src, count)) | ||
258 | goto fetch_fault; | ||
259 | |||
260 | if ((count == 2) && dst[1] & 0x80) { | ||
261 | dst[2] = 0xff; | ||
262 | dst[3] = 0xff; | ||
263 | } | ||
264 | #else | ||
265 | dst += 4-count; | 260 | dst += 4-count; |
266 | 261 | #endif | |
267 | if (copy_from_user(dst, src, count)) | 262 | if (copy_from_user(dst, src, count)) |
268 | goto fetch_fault; | 263 | goto fetch_fault; |
269 | 264 | sign_extend(count, dst); | |
270 | if ((count == 2) && dst[2] & 0x80) { | ||
271 | dst[0] = 0xff; | ||
272 | dst[1] = 0xff; | ||
273 | } | ||
274 | #endif | ||
275 | ret = 0; | 265 | ret = 0; |
276 | break; | 266 | break; |
277 | 267 | ||
@@ -299,21 +289,9 @@ static int handle_unaligned_ins(u16 instruction, struct pt_regs *regs) | |||
299 | #if !defined(__LITTLE_ENDIAN__) | 289 | #if !defined(__LITTLE_ENDIAN__) |
300 | dst += 2; | 290 | dst += 2; |
301 | #endif | 291 | #endif |
302 | |||
303 | if (copy_from_user(dst, src, 2)) | 292 | if (copy_from_user(dst, src, 2)) |
304 | goto fetch_fault; | 293 | goto fetch_fault; |
305 | 294 | sign_extend(2, dst); | |
306 | #ifdef __LITTLE_ENDIAN__ | ||
307 | if (dst[1] & 0x80) { | ||
308 | dst[2] = 0xff; | ||
309 | dst[3] = 0xff; | ||
310 | } | ||
311 | #else | ||
312 | if (dst[2] & 0x80) { | ||
313 | dst[0] = 0xff; | ||
314 | dst[1] = 0xff; | ||
315 | } | ||
316 | #endif | ||
317 | ret = 0; | 295 | ret = 0; |
318 | break; | 296 | break; |
319 | } | 297 | } |