aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/kernel/traps_32.c')
-rw-r--r--arch/sh/kernel/traps_32.c59
1 files changed, 34 insertions, 25 deletions
diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c
index 25b1b8672cf0..baa4fa368dce 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -172,6 +172,11 @@ static inline void sign_extend(unsigned int count, unsigned char *dst)
172#endif 172#endif
173} 173}
174 174
175static struct mem_access user_mem_access = {
176 copy_from_user,
177 copy_to_user,
178};
179
175/* 180/*
176 * handle an instruction that does an unaligned memory access by emulating the 181 * handle an instruction that does an unaligned memory access by emulating the
177 * desired behaviour 182 * desired behaviour
@@ -179,7 +184,8 @@ static inline void sign_extend(unsigned int count, unsigned char *dst)
179 * (if that instruction is in a branch delay slot) 184 * (if that instruction is in a branch delay slot)
180 * - return 0 if emulation okay, -EFAULT on existential error 185 * - return 0 if emulation okay, -EFAULT on existential error
181 */ 186 */
182static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs) 187static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs,
188 struct mem_access *ma)
183{ 189{
184 int ret, index, count; 190 int ret, index, count;
185 unsigned long *rm, *rn; 191 unsigned long *rm, *rn;
@@ -206,7 +212,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
206#if !defined(__LITTLE_ENDIAN__) 212#if !defined(__LITTLE_ENDIAN__)
207 dst += 4-count; 213 dst += 4-count;
208#endif 214#endif
209 if (copy_from_user(dst, src, count)) 215 if (ma->from(dst, src, count))
210 goto fetch_fault; 216 goto fetch_fault;
211 217
212 sign_extend(count, dst); 218 sign_extend(count, dst);
@@ -219,7 +225,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
219 dst = (unsigned char*) *rn; 225 dst = (unsigned char*) *rn;
220 dst += regs->regs[0]; 226 dst += regs->regs[0];
221 227
222 if (copy_to_user(dst, src, count)) 228 if (ma->to(dst, src, count))
223 goto fetch_fault; 229 goto fetch_fault;
224 } 230 }
225 ret = 0; 231 ret = 0;
@@ -230,7 +236,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
230 dst = (unsigned char*) *rn; 236 dst = (unsigned char*) *rn;
231 dst += (instruction&0x000F)<<2; 237 dst += (instruction&0x000F)<<2;
232 238
233 if (copy_to_user(dst,src,4)) 239 if (ma->to(dst, src, 4))
234 goto fetch_fault; 240 goto fetch_fault;
235 ret = 0; 241 ret = 0;
236 break; 242 break;
@@ -243,7 +249,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
243#if !defined(__LITTLE_ENDIAN__) 249#if !defined(__LITTLE_ENDIAN__)
244 src += 4-count; 250 src += 4-count;
245#endif 251#endif
246 if (copy_to_user(dst, src, count)) 252 if (ma->to(dst, src, count))
247 goto fetch_fault; 253 goto fetch_fault;
248 ret = 0; 254 ret = 0;
249 break; 255 break;
@@ -254,7 +260,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
254 dst = (unsigned char*) rn; 260 dst = (unsigned char*) rn;
255 *(unsigned long*)dst = 0; 261 *(unsigned long*)dst = 0;
256 262
257 if (copy_from_user(dst,src,4)) 263 if (ma->from(dst, src, 4))
258 goto fetch_fault; 264 goto fetch_fault;
259 ret = 0; 265 ret = 0;
260 break; 266 break;
@@ -269,7 +275,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
269#if !defined(__LITTLE_ENDIAN__) 275#if !defined(__LITTLE_ENDIAN__)
270 dst += 4-count; 276 dst += 4-count;
271#endif 277#endif
272 if (copy_from_user(dst, src, count)) 278 if (ma->from(dst, src, count))
273 goto fetch_fault; 279 goto fetch_fault;
274 sign_extend(count, dst); 280 sign_extend(count, dst);
275 ret = 0; 281 ret = 0;
@@ -285,7 +291,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
285 dst = (unsigned char*) *rm; /* called Rn in the spec */ 291 dst = (unsigned char*) *rm; /* called Rn in the spec */
286 dst += (instruction&0x000F)<<1; 292 dst += (instruction&0x000F)<<1;
287 293
288 if (copy_to_user(dst, src, 2)) 294 if (ma->to(dst, src, 2))
289 goto fetch_fault; 295 goto fetch_fault;
290 ret = 0; 296 ret = 0;
291 break; 297 break;
@@ -299,7 +305,7 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
299#if !defined(__LITTLE_ENDIAN__) 305#if !defined(__LITTLE_ENDIAN__)
300 dst += 2; 306 dst += 2;
301#endif 307#endif
302 if (copy_from_user(dst, src, 2)) 308 if (ma->from(dst, src, 2))
303 goto fetch_fault; 309 goto fetch_fault;
304 sign_extend(2, dst); 310 sign_extend(2, dst);
305 ret = 0; 311 ret = 0;
@@ -320,8 +326,9 @@ static int handle_unaligned_ins(opcode_t instruction, struct pt_regs *regs)
320 * emulate the instruction in the delay slot 326 * emulate the instruction in the delay slot
321 * - fetches the instruction from PC+2 327 * - fetches the instruction from PC+2
322 */ 328 */
323static inline int handle_unaligned_delayslot(struct pt_regs *regs, 329static inline int handle_delayslot(struct pt_regs *regs,
324 opcode_t old_instruction) 330 opcode_t old_instruction,
331 struct mem_access *ma)
325{ 332{
326 opcode_t instruction; 333 opcode_t instruction;
327 void *addr = (void *)(regs->pc + instruction_size(old_instruction)); 334 void *addr = (void *)(regs->pc + instruction_size(old_instruction));
@@ -336,7 +343,7 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs,
336 regs, 0); 343 regs, 0);
337 } 344 }
338 345
339 return handle_unaligned_ins(instruction, regs); 346 return handle_unaligned_ins(instruction, regs, ma);
340} 347}
341 348
342/* 349/*
@@ -362,7 +369,8 @@ static inline int handle_unaligned_delayslot(struct pt_regs *regs,
362 369
363static int handle_unaligned_notify_count = 10; 370static int handle_unaligned_notify_count = 10;
364 371
365static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs) 372int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs,
373 struct mem_access *ma)
366{ 374{
367 u_int rm; 375 u_int rm;
368 int ret, index; 376 int ret, index;
@@ -385,19 +393,19 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
385 case 0x0000: 393 case 0x0000:
386 if (instruction==0x000B) { 394 if (instruction==0x000B) {
387 /* rts */ 395 /* rts */
388 ret = handle_unaligned_delayslot(regs, instruction); 396 ret = handle_delayslot(regs, instruction, ma);
389 if (ret==0) 397 if (ret==0)
390 regs->pc = regs->pr; 398 regs->pc = regs->pr;
391 } 399 }
392 else if ((instruction&0x00FF)==0x0023) { 400 else if ((instruction&0x00FF)==0x0023) {
393 /* braf @Rm */ 401 /* braf @Rm */
394 ret = handle_unaligned_delayslot(regs, instruction); 402 ret = handle_delayslot(regs, instruction, ma);
395 if (ret==0) 403 if (ret==0)
396 regs->pc += rm + 4; 404 regs->pc += rm + 4;
397 } 405 }
398 else if ((instruction&0x00FF)==0x0003) { 406 else if ((instruction&0x00FF)==0x0003) {
399 /* bsrf @Rm */ 407 /* bsrf @Rm */
400 ret = handle_unaligned_delayslot(regs, instruction); 408 ret = handle_delayslot(regs, instruction, ma);
401 if (ret==0) { 409 if (ret==0) {
402 regs->pr = regs->pc + 4; 410 regs->pr = regs->pc + 4;
403 regs->pc += rm + 4; 411 regs->pc += rm + 4;
@@ -418,13 +426,13 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
418 case 0x4000: 426 case 0x4000:
419 if ((instruction&0x00FF)==0x002B) { 427 if ((instruction&0x00FF)==0x002B) {
420 /* jmp @Rm */ 428 /* jmp @Rm */
421 ret = handle_unaligned_delayslot(regs, instruction); 429 ret = handle_delayslot(regs, instruction, ma);
422 if (ret==0) 430 if (ret==0)
423 regs->pc = rm; 431 regs->pc = rm;
424 } 432 }
425 else if ((instruction&0x00FF)==0x000B) { 433 else if ((instruction&0x00FF)==0x000B) {
426 /* jsr @Rm */ 434 /* jsr @Rm */
427 ret = handle_unaligned_delayslot(regs, instruction); 435 ret = handle_delayslot(regs, instruction, ma);
428 if (ret==0) { 436 if (ret==0) {
429 regs->pr = regs->pc + 4; 437 regs->pr = regs->pc + 4;
430 regs->pc = rm; 438 regs->pc = rm;
@@ -451,7 +459,7 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
451 case 0x0B00: /* bf lab - no delayslot*/ 459 case 0x0B00: /* bf lab - no delayslot*/
452 break; 460 break;
453 case 0x0F00: /* bf/s lab */ 461 case 0x0F00: /* bf/s lab */
454 ret = handle_unaligned_delayslot(regs, instruction); 462 ret = handle_delayslot(regs, instruction, ma);
455 if (ret==0) { 463 if (ret==0) {
456#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) 464#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
457 if ((regs->sr & 0x00000001) != 0) 465 if ((regs->sr & 0x00000001) != 0)
@@ -464,7 +472,7 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
464 case 0x0900: /* bt lab - no delayslot */ 472 case 0x0900: /* bt lab - no delayslot */
465 break; 473 break;
466 case 0x0D00: /* bt/s lab */ 474 case 0x0D00: /* bt/s lab */
467 ret = handle_unaligned_delayslot(regs, instruction); 475 ret = handle_delayslot(regs, instruction, ma);
468 if (ret==0) { 476 if (ret==0) {
469#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB) 477#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
470 if ((regs->sr & 0x00000001) == 0) 478 if ((regs->sr & 0x00000001) == 0)
@@ -478,13 +486,13 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
478 break; 486 break;
479 487
480 case 0xA000: /* bra label */ 488 case 0xA000: /* bra label */
481 ret = handle_unaligned_delayslot(regs, instruction); 489 ret = handle_delayslot(regs, instruction, ma);
482 if (ret==0) 490 if (ret==0)
483 regs->pc += SH_PC_12BIT_OFFSET(instruction); 491 regs->pc += SH_PC_12BIT_OFFSET(instruction);
484 break; 492 break;
485 493
486 case 0xB000: /* bsr label */ 494 case 0xB000: /* bsr label */
487 ret = handle_unaligned_delayslot(regs, instruction); 495 ret = handle_delayslot(regs, instruction, ma);
488 if (ret==0) { 496 if (ret==0) {
489 regs->pr = regs->pc + 4; 497 regs->pr = regs->pc + 4;
490 regs->pc += SH_PC_12BIT_OFFSET(instruction); 498 regs->pc += SH_PC_12BIT_OFFSET(instruction);
@@ -495,7 +503,7 @@ static int handle_unaligned_access(opcode_t instruction, struct pt_regs *regs)
495 503
496 /* handle non-delay-slot instruction */ 504 /* handle non-delay-slot instruction */
497 simple: 505 simple:
498 ret = handle_unaligned_ins(instruction, regs); 506 ret = handle_unaligned_ins(instruction, regs, ma);
499 if (ret==0) 507 if (ret==0)
500 regs->pc += instruction_size(instruction); 508 regs->pc += instruction_size(instruction);
501 return ret; 509 return ret;
@@ -558,7 +566,8 @@ asmlinkage void do_address_error(struct pt_regs *regs,
558 goto uspace_segv; 566 goto uspace_segv;
559 } 567 }
560 568
561 tmp = handle_unaligned_access(instruction, regs); 569 tmp = handle_unaligned_access(instruction, regs,
570 &user_mem_access);
562 set_fs(oldfs); 571 set_fs(oldfs);
563 572
564 if (tmp==0) 573 if (tmp==0)
@@ -587,7 +596,7 @@ uspace_segv:
587 die("insn faulting in do_address_error", regs, 0); 596 die("insn faulting in do_address_error", regs, 0);
588 } 597 }
589 598
590 handle_unaligned_access(instruction, regs); 599 handle_unaligned_access(instruction, regs, &user_mem_access);
591 set_fs(oldfs); 600 set_fs(oldfs);
592 } 601 }
593} 602}