NPTL, round one.
authorRalf Baechle <ralf@linux-mips.org>
Wed, 13 Apr 2005 17:43:59 +0000 (17:43 +0000)
committerRalf Baechle <ralf@linux-mips.org>
Sat, 29 Oct 2005 18:31:06 +0000 (19:31 +0100)
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
14 files changed:
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/linux32.c
arch/mips/kernel/process.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/ptrace32.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/syscall.c
arch/mips/kernel/traps.c
include/asm-mips/inst.h
include/asm-mips/thread_info.h
include/asm-mips/unistd.h

index 2c11abb5a406d02688a6d635c873a1e8b1397a1d..af69cdbdd50ee337568de4032ba4fb668524fe66 100644 (file)
@@ -95,6 +95,7 @@ void output_thread_info_defines(void)
        offset("#define TI_PRE_COUNT       ", struct thread_info, preempt_count);
        offset("#define TI_ADDR_LIMIT      ", struct thread_info, addr_limit);
        offset("#define TI_RESTART_BLOCK   ", struct thread_info, restart_block);
+       offset("#define TI_TP_VALUE        ", struct thread_info, tp_value);
        constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER);
        constant("#define _THREAD_SIZE       ", THREAD_SIZE);
        constant("#define _THREAD_MASK       ", THREAD_MASK);
index e8e886dd52d6af9db48204dfef710cfc999fdc3d..330cf84d21feaf298636fe09b6d9be10d2637d03 100644 (file)
@@ -1468,3 +1468,30 @@ sysn32_rt_sigtimedwait(const sigset_t __user *uthese,
        }
        return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize);
 }
+
+save_static_function(sys32_clone);
+__attribute_used__ noinline static int
+_sys32_clone(nabi_no_regargs struct pt_regs regs)
+{
+       unsigned long clone_flags;
+       unsigned long newsp;
+       int __user *parent_tidptr, *child_tidptr;
+
+       clone_flags = regs.regs[4];
+       newsp = regs.regs[5];
+       if (!newsp)
+               newsp = regs.regs[29];
+       parent_tidptr = (int *) regs.regs[6];
+
+       /* Use __dummy4 instead of getting it off the stack, so that
+          syscall() works.  */
+       child_tidptr = (int __user *) __dummy4;
+       return do_fork(clone_flags, newsp, &regs, 0,
+                      parent_tidptr, child_tidptr);
+}
+
+extern asmlinkage void sys_set_thread_area(u32 addr);
+asmlinkage void sys32_set_thread_area(u32 addr)
+{
+       sys_set_thread_area(AA(addr));
+}
index 2b7a44deb85640141cf95121998e16b3e7e5682d..368526af5f5e1e43336ce450ff304ac4bb70a546 100644 (file)
@@ -89,6 +89,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        struct thread_info *ti = p->thread_info;
        struct pt_regs *childregs;
        long childksp;
+       p->set_child_tid = p->clear_child_tid = NULL;
 
        childksp = (unsigned long)ti + THREAD_SIZE - 32;
 
@@ -134,6 +135,9 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
        childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
        clear_tsk_thread_flag(p, TIF_USEDFPU);
 
+       if (clone_flags & CLONE_SETTLS)
+               ti->tp_value = regs->regs[7];
+
        return 0;
 }
 
index 2c7fc7472fb2c8f5eac742891e2b3d05193f5b7e..649c90dee38eb9bd3c0f13c885d36e68247ec44f 100644 (file)
@@ -289,6 +289,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                ret = ptrace_detach(child, data);
                break;
 
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(child->thread_info->tp_value,
+                               (unsigned long __user *) data);
+               break;
+
        default:
                ret = ptrace_request(child, request, addr, data);
                break;
index a8a72c9a1ccad21093e08ccb6392545ca6f05520..eb446e525908829632ca5bc34186fbd7635fa5e2 100644 (file)
@@ -268,6 +268,11 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
                wake_up_process(child);
                break;
 
+       case PTRACE_GET_THREAD_AREA:
+               ret = put_user(child->thread_info->tp_value,
+                               (unsigned int __user *) (unsigned long) data);
+               break;
+
        case PTRACE_DETACH: /* detach a process that was attached. */
                ret = ptrace_detach(child, data);
                break;
index 9c4bb917d47619a709e0daff832df3451a605079..6fa1112512c812729c6bf46fe3e210dd03b02ca6 100644 (file)
@@ -623,6 +623,7 @@ einval:     li      v0, -EINVAL
        sys     sys_add_key             5
        sys     sys_request_key         4
        sys     sys_keyctl              5
+       sys     sys_set_thread_area     1
 
        .endm
 
index ffb22a2068bf960a95291b7063ca83424ee44f43..d11f99b0ae53204d59cb13ca5fade648609965a6 100644 (file)
@@ -449,3 +449,4 @@ sys_call_table:
        PTR     sys_add_key
        PTR     sys_request_key                 /* 5240 */
        PTR     sys_keyctl
+       PTR     sys_set_thread_area
index d912218259e5cba7aa9f3eec19c23c6b494c9edc..ce030412efbe30477d89cd88fb5906fe859c7ef3 100644 (file)
@@ -363,3 +363,4 @@ EXPORT(sysn32_call_table)
        PTR     sys_add_key
        PTR     sys_request_key
        PTR     sys_keyctl                      /* 6245 */
+       PTR     sys_set_thread_area
index 1017176bdce9d6aaaaa0d7dc516dc4fc183caa9b..f49182ea73f891bb846f2dc4396952f15bd1e8bb 100644 (file)
@@ -322,7 +322,7 @@ sys_call_table:
        PTR     sys32_ipc
        PTR     sys_fsync
        PTR     sys32_sigreturn
-       PTR     sys_clone                       /* 4120 */
+       PTR     sys32_clone                     /* 4120 */
        PTR     sys_setdomainname
        PTR     sys32_newuname
        PTR     sys_ni_syscall                  /* sys_modify_ldt */
@@ -485,4 +485,5 @@ sys_call_table:
        PTR     sys_add_key                     /* 4280 */
        PTR     sys_request_key
        PTR     sys_keyctl
+       PTR     sys_set_thread_area
        .size   sys_call_table,.-sys_call_table
index 8fde242596f9f01a27f61bbb8ed8f217b0679fa0..ee98eeb65e85f833009c7d3226fbb614db73e65a 100644 (file)
@@ -7,6 +7,7 @@
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  * Copyright (C) 2001 MIPS Technologies, Inc.
  */
+#include <linux/config.h>
 #include <linux/a.out.h>
 #include <linux/errno.h>
 #include <linux/linkage.h>
@@ -176,14 +177,28 @@ _sys_clone(nabi_no_regargs struct pt_regs regs)
 {
        unsigned long clone_flags;
        unsigned long newsp;
-       int *parent_tidptr, *child_tidptr;
+       int __user *parent_tidptr, *child_tidptr;
 
        clone_flags = regs.regs[4];
        newsp = regs.regs[5];
        if (!newsp)
                newsp = regs.regs[29];
-       parent_tidptr = (int *) regs.regs[6];
-       child_tidptr = (int *) regs.regs[7];
+       parent_tidptr = (int __user *) regs.regs[6];
+#ifdef CONFIG_32BIT
+       /* We need to fetch the fifth argument off the stack.  */
+       child_tidptr = NULL;
+       if (clone_flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) {
+               int __user *__user *usp = (int __user *__user *) regs.regs[29];
+               if (regs.regs[2] == __NR_syscall) {
+                       if (get_user (child_tidptr, &usp[5]))
+                               return -EFAULT;
+               }
+               else if (get_user (child_tidptr, &usp[4]))
+                       return -EFAULT;
+       }
+#else
+       child_tidptr = (int __user *) regs.regs[8];
+#endif
        return do_fork(clone_flags, newsp, &regs, 0,
                       parent_tidptr, child_tidptr);
 }
@@ -245,6 +260,16 @@ asmlinkage int sys_olduname(struct oldold_utsname * name)
        return error;
 }
 
+void sys_set_thread_area(unsigned long addr)
+{
+       struct thread_info *ti = current->thread_info;
+
+       ti->tp_value = addr;
+
+       /* If some future MIPS implementation has this register in hardware,
+        * we will need to update it here (and in context switches).  */
+}
+
 asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
 {
        int     tmp, len;
index 94d9141c04c17ede6bb7382983c37ba5d56de6f9..15fed0202154ff85c69b46fa4beb20e7c6c69162 100644 (file)
@@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct pt_regs *regs, unsigned int *opcode)
 #define OFFSET 0x0000ffff
 #define LL     0xc0000000
 #define SC     0xe0000000
+#define SPEC3  0x7c000000
+#define RD     0x0000f800
+#define FUNC   0x0000003f
+#define RDHWR  0x0000003b
 
 /*
  * The ll_bit is cleared by r*_switch.S
@@ -495,6 +499,37 @@ static inline int simulate_llsc(struct pt_regs *regs)
        return -EFAULT;                 /* Strange things going on ... */
 }
 
+/*
+ * Simulate trapping 'rdhwr' instructions to provide user accessible
+ * registers not implemented in hardware.  The only current use of this
+ * is the thread area pointer.
+ */
+static inline int simulate_rdhwr(struct pt_regs *regs)
+{
+       struct thread_info *ti = current->thread_info;
+       unsigned int opcode;
+
+       if (unlikely(get_insn_opcode(regs, &opcode)))
+               return -EFAULT;
+
+       if (unlikely(compute_return_epc(regs)))
+               return -EFAULT;
+
+       if ((opcode & OPCODE) == SPEC3 && (opcode & FUNC) == RDHWR) {
+               int rd = (opcode & RD) >> 11;
+               int rt = (opcode & RT) >> 16;
+               switch (rd) {
+                       case 29:
+                               regs->regs[rt] = ti->tp_value;
+                               break;
+                       default:
+                               return -EFAULT;
+               }
+       }
+
+       return 0;
+}
+
 asmlinkage void do_ov(struct pt_regs *regs)
 {
        siginfo_t info;
@@ -641,6 +676,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
                if (!simulate_llsc(regs))
                        return;
 
+       if (!simulate_rdhwr(regs))
+               return;
+
        force_sig(SIGILL, current);
 }
 
@@ -654,11 +692,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
        switch (cpid) {
        case 0:
-               if (cpu_has_llsc)
-                       break;
+               if (!cpu_has_llsc)
+                       if (!simulate_llsc(regs))
+                               return;
 
-               if (!simulate_llsc(regs))
+               if (!simulate_rdhwr(regs))
                        return;
+
                break;
 
        case 1:
index 6ad517241768d71a7aa0e6a5218091e6a386798b..df912c2b381f65c744743b429304b04a513cfb63 100644 (file)
@@ -28,7 +28,7 @@ enum major_op {
        sdl_op, sdr_op, swr_op, cache_op,
        ll_op, lwc1_op, lwc2_op, pref_op,
        lld_op, ldc1_op, ldc2_op, ld_op,
-       sc_op, swc1_op, swc2_op, major_3b_op, /* Opcode 0x3b is unused */
+       sc_op, swc1_op, swc2_op, rdhwr_op,
        scd_op, sdc1_op, sdc2_op, sd_op
 };
 
index 66a0c2ae7d658a39105321a6a624147d19dd1a16..e6c24472e03fa64ffd95837137b0528e12083df5 100644 (file)
@@ -26,6 +26,7 @@ struct thread_info {
        struct task_struct      *task;          /* main task structure */
        struct exec_domain      *exec_domain;   /* execution domain */
        unsigned long           flags;          /* low level flags */
+       unsigned long           tp_value;       /* thread pointer */
        __u32                   cpu;            /* current CPU */
        int                     preempt_count;  /* 0 => preemptable, <0 => BUG */
 
index ad4d48056307ea704f13b2ec0f44053816c7cdb0..6be69c3a691f762f6c99b3537d51346fea354b46 100644 (file)
 #define __NR_add_key                   (__NR_Linux + 280)
 #define __NR_request_key               (__NR_Linux + 281)
 #define __NR_keyctl                    (__NR_Linux + 282)
+#define __NR_set_thread_area           (__NR_Linux + 283)
 
 /*
  * Offset of the last Linux o32 flavoured syscall
  */
-#define __NR_Linux_syscalls            282
+#define __NR_Linux_syscalls            283
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
 
 #define __NR_O32_Linux                 4000
-#define __NR_O32_Linux_syscalls                282
+#define __NR_O32_Linux_syscalls                283
 
 #if _MIPS_SIM == _MIPS_SIM_ABI64
 
 #define __NR_add_key                   (__NR_Linux + 239)
 #define __NR_request_key               (__NR_Linux + 240)
 #define __NR_keyctl                    (__NR_Linux + 241)
+#define __NR_set_thread_area           (__NR_Linux + 242)
 
 /*
  * Offset of the last Linux 64-bit flavoured syscall
  */
-#define __NR_Linux_syscalls            241
+#define __NR_Linux_syscalls            242
 
 #endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
 
 #define __NR_64_Linux                  5000
-#define __NR_64_Linux_syscalls         241
+#define __NR_64_Linux_syscalls         242
 
 #if _MIPS_SIM == _MIPS_SIM_NABI32
 
 #define __NR_add_key                   (__NR_Linux + 243)
 #define __NR_request_key               (__NR_Linux + 244)
 #define __NR_keyctl                    (__NR_Linux + 245)
+#define __NR_set_thread_area           (__NR_Linux + 246)
 
 /*
  * Offset of the last N32 flavoured syscall
  */
-#define __NR_Linux_syscalls            245
+#define __NR_Linux_syscalls            246
 
 #endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
 
 #define __NR_N32_Linux                 6000
-#define __NR_N32_Linux_syscalls                245
+#define __NR_N32_Linux_syscalls                246
 
 #ifndef __ASSEMBLY__