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: |
