aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2005-04-13 13:43:59 -0400
committerRalf Baechle <ralf@linux-mips.org>2005-10-29 14:31:06 -0400
commit3c37026d43c47bec4710cbda286f4a17f416f5e6 (patch)
tree8bf206dc3ee4337ac9839c0e9e26ec4513996670 /arch/mips/kernel/traps.c
parent38551576a35f1b48b6b359470d6e876c5b671ab6 (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.c46
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 */
507static 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
498asmlinkage void do_ov(struct pt_regs *regs) 533asmlinkage 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: