aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel
diff options
context:
space:
mode:
authorLeonid Yegoshin <Leonid.Yegoshin@imgtec.com>2013-12-12 11:15:15 -0500
committerRalf Baechle <ralf@linux-mips.org>2014-03-26 18:09:16 -0400
commitc1771216ab48bb077cee30e6d197a5a55f707101 (patch)
treecd76e7ac55516c4b3f237ea0617d0c5177ac2792 /arch/mips/kernel
parent9d8e573683ca85e2bd3cade8b5c42e195e6390ad (diff)
MIPS: kernel: unaligned: Handle unaligned accesses for EVA
Handle unaligned accesses when we access userspace memory EVA mode. Signed-off-by: Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Diffstat (limited to 'arch/mips/kernel')
-rw-r--r--arch/mips/kernel/unaligned.c86
1 files changed, 85 insertions, 1 deletions
diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c
index 5ec8f00b51b5..2b3517214d6d 100644
--- a/arch/mips/kernel/unaligned.c
+++ b/arch/mips/kernel/unaligned.c
@@ -431,7 +431,9 @@ static void emulate_load_store_insn(struct pt_regs *regs,
431 unsigned long origpc; 431 unsigned long origpc;
432 unsigned long orig31; 432 unsigned long orig31;
433 void __user *fault_addr = NULL; 433 void __user *fault_addr = NULL;
434 434#ifdef CONFIG_EVA
435 mm_segment_t seg;
436#endif
435 origpc = (unsigned long)pc; 437 origpc = (unsigned long)pc;
436 orig31 = regs->regs[31]; 438 orig31 = regs->regs[31];
437 439
@@ -476,6 +478,88 @@ static void emulate_load_store_insn(struct pt_regs *regs,
476 * The remaining opcodes are the ones that are really of 478 * The remaining opcodes are the ones that are really of
477 * interest. 479 * interest.
478 */ 480 */
481#ifdef CONFIG_EVA
482 case spec3_op:
483 /*
484 * we can land here only from kernel accessing user memory,
485 * so we need to "switch" the address limit to user space, so
486 * address check can work properly.
487 */
488 seg = get_fs();
489 set_fs(USER_DS);
490 switch (insn.spec3_format.func) {
491 case lhe_op:
492 if (!access_ok(VERIFY_READ, addr, 2)) {
493 set_fs(seg);
494 goto sigbus;
495 }
496 LoadHW(addr, value, res);
497 if (res) {
498 set_fs(seg);
499 goto fault;
500 }
501 compute_return_epc(regs);
502 regs->regs[insn.spec3_format.rt] = value;
503 break;
504 case lwe_op:
505 if (!access_ok(VERIFY_READ, addr, 4)) {
506 set_fs(seg);
507 goto sigbus;
508 }
509 LoadW(addr, value, res);
510 if (res) {
511 set_fs(seg);
512 goto fault;
513 }
514 compute_return_epc(regs);
515 regs->regs[insn.spec3_format.rt] = value;
516 break;
517 case lhue_op:
518 if (!access_ok(VERIFY_READ, addr, 2)) {
519 set_fs(seg);
520 goto sigbus;
521 }
522 LoadHWU(addr, value, res);
523 if (res) {
524 set_fs(seg);
525 goto fault;
526 }
527 compute_return_epc(regs);
528 regs->regs[insn.spec3_format.rt] = value;
529 break;
530 case she_op:
531 if (!access_ok(VERIFY_WRITE, addr, 2)) {
532 set_fs(seg);
533 goto sigbus;
534 }
535 compute_return_epc(regs);
536 value = regs->regs[insn.spec3_format.rt];
537 StoreHW(addr, value, res);
538 if (res) {
539 set_fs(seg);
540 goto fault;
541 }
542 break;
543 case swe_op:
544 if (!access_ok(VERIFY_WRITE, addr, 4)) {
545 set_fs(seg);
546 goto sigbus;
547 }
548 compute_return_epc(regs);
549 value = regs->regs[insn.spec3_format.rt];
550 StoreW(addr, value, res);
551 if (res) {
552 set_fs(seg);
553 goto fault;
554 }
555 break;
556 default:
557 set_fs(seg);
558 goto sigill;
559 }
560 set_fs(seg);
561 break;
562#endif
479 case lh_op: 563 case lh_op:
480 if (!access_ok(VERIFY_READ, addr, 2)) 564 if (!access_ok(VERIFY_READ, addr, 2))
481 goto sigbus; 565 goto sigbus;