diff options
author | Leonid Yegoshin <Leonid.Yegoshin@imgtec.com> | 2013-12-12 11:15:15 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-03-26 18:09:16 -0400 |
commit | c1771216ab48bb077cee30e6d197a5a55f707101 (patch) | |
tree | cd76e7ac55516c4b3f237ea0617d0c5177ac2792 /arch/mips/kernel | |
parent | 9d8e573683ca85e2bd3cade8b5c42e195e6390ad (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.c | 86 |
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; |