diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-04-13 13:43:59 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 14:31:06 -0400 |
commit | 3c37026d43c47bec4710cbda286f4a17f416f5e6 (patch) | |
tree | 8bf206dc3ee4337ac9839c0e9e26ec4513996670 /arch/mips/kernel/traps.c | |
parent | 38551576a35f1b48b6b359470d6e876c5b671ab6 (diff) |
NPTL, round one.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 94d9141c04c1..15fed0202154 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode) | |||
360 | #define OFFSET 0x0000ffff | 360 | #define OFFSET 0x0000ffff |
361 | #define LL 0xc0000000 | 361 | #define LL 0xc0000000 |
362 | #define SC 0xe0000000 | 362 | #define SC 0xe0000000 |
363 | #define SPEC3 0x7c000000 | ||
364 | #define RD 0x0000f800 | ||
365 | #define FUNC 0x0000003f | ||
366 | #define RDHWR 0x0000003b | ||
363 | 367 | ||
364 | /* | 368 | /* |
365 | * The ll_bit is cleared by r*_switch.S | 369 | * The ll_bit is cleared by r*_switch.S |
@@ -495,6 +499,37 @@ static inline int simulate_llsc(struct pt_regs *regs) | |||
495 | return -EFAULT; /* Strange things going on ... */ | 499 | return -EFAULT; /* Strange things going on ... */ |
496 | } | 500 | } |
497 | 501 | ||
502 | /* | ||
503 | * Simulate trapping 'rdhwr' instructions to provide user accessible | ||
504 | * registers not implemented in hardware. The only current use of this | ||
505 | * is the thread area pointer. | ||
506 | */ | ||
507 | static inline int simulate_rdhwr(struct pt_regs *regs) | ||
508 | { | ||
509 | struct thread_info *ti = current->thread_info; | ||
510 | unsigned int opcode; | ||
511 | |||
512 | if (unlikely(get_insn_opcode(regs, &opcode))) | ||
513 | return -EFAULT; | ||
514 | |||
515 | if (unlikely(compute_return_epc(regs))) | ||
516 | return -EFAULT; | ||
517 | |||
518 | if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) { | ||
519 | int rd = (opcode & RD) >> 11; | ||
520 | int rt = (opcode & RT) >> 16; | ||
521 | switch (rd) { | ||
522 | case 29: | ||
523 | regs->regs[rt] = ti->tp_value; | ||
524 | break; | ||
525 | default: | ||
526 | return -EFAULT; | ||
527 | } | ||
528 | } | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
498 | asmlinkage void do_ov(struct pt_regs *regs) | 533 | asmlinkage void do_ov(struct pt_regs *regs) |
499 | { | 534 | { |
500 | siginfo_t info; | 535 | siginfo_t info; |
@@ -641,6 +676,9 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
641 | if (!simulate_llsc(regs)) | 676 | if (!simulate_llsc(regs)) |
642 | return; | 677 | return; |
643 | 678 | ||
679 | if (!simulate_rdhwr(regs)) | ||
680 | return; | ||
681 | |||
644 | force_sig(SIGILL, current); | 682 | force_sig(SIGILL, current); |
645 | } | 683 | } |
646 | 684 | ||
@@ -654,11 +692,13 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
654 | 692 | ||
655 | switch (cpid) { | 693 | switch (cpid) { |
656 | case 0: | 694 | case 0: |
657 | if (cpu_has_llsc) | 695 | if (!cpu_has_llsc) |
658 | break; | 696 | if (!simulate_llsc(regs)) |
697 | return; | ||
659 | 698 | ||
660 | if (!simulate_llsc(regs)) | 699 | if (!simulate_rdhwr(regs)) |
661 | return; | 700 | return; |
701 | |||
662 | break; | 702 | break; |
663 | 703 | ||
664 | case 1: | 704 | case 1: |