* NPTL support for the kernel
@ 2005-03-16 14:11 Daniel Jacobowitz
2005-03-21 20:34 ` Daniel Jacobowitz
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Jacobowitz @ 2005-03-16 14:11 UTC (permalink / raw)
To: ralf, linux-mips
Here's a kernel patch to enable NPTL support. This doesn't include Maciej's
uber-fast rdhwr emulation; I believe we ought to include both the fast and
slow paths, since the slow path will handle use of other destination
registers. Changes:
- Clone takes five arguments, not four. Um, this bit is gross.
- New syscall sys_set_thread_area. Only glibc uses this.
- Emulation of the rdhwr instruction. This version is only loosely
based on the emulation on the malta branch; the major difference
is that I fixed ll/sc/rdhwr emulation in branch delay slots.
GCC 4.1 will generate rdhwr in branch delay slots in some
conditions.
- PTRACE_GET_THREAD_AREA support for GDB.
How's it look? I've just finished hopefully final tests for the
glibc bits, and will post them once this patch is resolved.
[Credit goes to Manish Lachwani at MontaVista for writing the
first draft of this patch, though he won't recognize most of this
copy :-)]
Index: linux/arch/mips/kernel/syscall.c
===================================================================
--- linux.orig/arch/mips/kernel/syscall.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/syscall.c 2005-03-15 10:30:09.000000000 -0500
@@ -176,14 +176,28 @@ _sys_clone(nabi_no_regargs struct pt_reg
{
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_MIPS32
+ /* 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, ®s, 0,
parent_tidptr, child_tidptr);
}
@@ -245,6 +259,16 @@ asmlinkage int sys_olduname(struct oldol
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: linux/arch/mips/kernel/traps.c
===================================================================
--- linux.orig/arch/mips/kernel/traps.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/traps.c 2005-03-15 10:33:48.000000000 -0500
@@ -360,6 +360,10 @@ static inline int get_insn_opcode(struct
#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
@@ -408,9 +412,10 @@ static inline void simulate_ll(struct pt
preempt_enable();
+ compute_return_epc(regs);
+
regs->regs[(opcode & RT) >> 16] = value;
- compute_return_epc(regs);
return;
sig:
@@ -446,9 +451,9 @@ static inline void simulate_sc(struct pt
preempt_disable();
if (ll_bit == 0 || ll_task != current) {
- regs->regs[reg] = 0;
preempt_enable();
compute_return_epc(regs);
+ regs->regs[reg] = 0;
return;
}
@@ -459,9 +464,8 @@ static inline void simulate_sc(struct pt
goto sig;
}
- regs->regs[reg] = 1;
-
compute_return_epc(regs);
+ regs->regs[reg] = 1;
return;
sig:
@@ -494,6 +498,37 @@ static inline int simulate_llsc(struct p
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;
@@ -640,6 +675,9 @@ asmlinkage void do_ri(struct pt_regs *re
if (!simulate_llsc(regs))
return;
+ if (!simulate_rdhwr(regs))
+ return;
+
force_sig(SIGILL, current);
}
@@ -653,11 +691,13 @@ asmlinkage void do_cpu(struct pt_regs *r
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: linux/arch/mips/kernel/process.c
===================================================================
--- linux.orig/arch/mips/kernel/process.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/process.c 2005-03-16 09:04:04.049856461 -0500
@@ -89,6 +89,7 @@ int copy_thread(int nr, unsigned long cl
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 cl
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: linux/include/asm-mips/inst.h
===================================================================
--- linux.orig/include/asm-mips/inst.h 2005-03-15 10:09:23.000000000 -0500
+++ linux/include/asm-mips/inst.h 2005-03-15 10:09:29.000000000 -0500
@@ -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: linux/arch/mips/kernel/ptrace.c
===================================================================
--- linux.orig/arch/mips/kernel/ptrace.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/ptrace.c 2005-03-15 10:09:29.000000000 -0500
@@ -287,6 +287,11 @@ asmlinkage int sys_ptrace(long request,
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: linux/include/asm-mips/thread_info.h
===================================================================
--- linux.orig/include/asm-mips/thread_info.h 2005-03-15 10:09:23.000000000 -0500
+++ linux/include/asm-mips/thread_info.h 2005-03-15 10:34:51.000000000 -0500
@@ -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 */
__s32 preempt_count; /* 0 => preemptable, <0 => BUG */
Index: linux/arch/mips/kernel/offset.c
===================================================================
--- linux.orig/arch/mips/kernel/offset.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/offset.c 2005-03-15 10:09:29.000000000 -0500
@@ -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: linux/arch/mips/kernel/scall64-o32.S
===================================================================
--- linux.orig/arch/mips/kernel/scall64-o32.S 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/scall64-o32.S 2005-03-15 10:29:46.000000000 -0500
@@ -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: linux/arch/mips/kernel/linux32.c
===================================================================
--- linux.orig/arch/mips/kernel/linux32.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/linux32.c 2005-03-15 10:29:02.000000000 -0500
@@ -1471,3 +1471,38 @@ sysn32_rt_sigtimedwait(const sigset_t __
}
return sys_rt_sigtimedwait(uthese, uinfo, uts, sigsetsize);
}
+
+save_static_function(sys32_clone);
+__attribute_used__ noinline static int
+_sys32_clone(unsigned long __dummy0,
+ unsigned long __dummy1,
+ unsigned long __dummy2,
+ unsigned long __dummy3,
+ unsigned long __dummy4,
+ unsigned long __dummy5,
+ unsigned long __dummy6,
+ unsigned long __dummy7,
+ 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, ®s, 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: linux/arch/mips/kernel/ptrace32.c
===================================================================
--- linux.orig/arch/mips/kernel/ptrace32.c 2005-03-15 10:09:23.000000000 -0500
+++ linux/arch/mips/kernel/ptrace32.c 2005-03-15 10:09:29.000000000 -0500
@@ -268,6 +268,11 @@ asmlinkage int sys32_ptrace(int request,
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: linux/arch/mips/kernel/scall32-o32.S
===================================================================
--- linux.orig/arch/mips/kernel/scall32-o32.S 2005-03-15 10:04:30.000000000 -0500
+++ linux/arch/mips/kernel/scall32-o32.S 2005-03-15 10:29:24.000000000 -0500
@@ -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: linux/include/asm-mips/unistd.h
===================================================================
--- linux.orig/include/asm-mips/unistd.h 2005-02-02 09:17:33.000000000 -0500
+++ linux/include/asm-mips/unistd.h 2005-03-15 10:26:02.000000000 -0500
@@ -303,16 +303,17 @@
#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
@@ -562,16 +563,17 @@
#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
@@ -825,16 +827,17 @@
#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__
Index: linux/arch/mips/kernel/scall64-64.S
===================================================================
--- linux.orig/arch/mips/kernel/scall64-64.S 2005-01-20 16:26:58.000000000 -0500
+++ linux/arch/mips/kernel/scall64-64.S 2005-03-15 10:29:48.000000000 -0500
@@ -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: linux/arch/mips/kernel/scall64-n32.S
===================================================================
--- linux.orig/arch/mips/kernel/scall64-n32.S 2005-03-15 10:09:21.000000000 -0500
+++ linux/arch/mips/kernel/scall64-n32.S 2005-03-16 09:04:03.388011517 -0500
@@ -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
--
Daniel Jacobowitz
CodeSourcery, LLC
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: NPTL support for the kernel
2005-03-16 14:11 NPTL support for the kernel Daniel Jacobowitz
@ 2005-03-21 20:34 ` Daniel Jacobowitz
2005-03-22 1:21 ` Kumba
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Jacobowitz @ 2005-03-21 20:34 UTC (permalink / raw)
To: ralf, linux-mips
On Wed, Mar 16, 2005 at 09:11:52AM -0500, Daniel Jacobowitz wrote:
> Here's a kernel patch to enable NPTL support. This doesn't include Maciej's
> uber-fast rdhwr emulation; I believe we ought to include both the fast and
> slow paths, since the slow path will handle use of other destination
> registers. Changes:
>
> - Clone takes five arguments, not four. Um, this bit is gross.
> - New syscall sys_set_thread_area. Only glibc uses this.
> - Emulation of the rdhwr instruction. This version is only loosely
> based on the emulation on the malta branch; the major difference
> is that I fixed ll/sc/rdhwr emulation in branch delay slots.
> GCC 4.1 will generate rdhwr in branch delay slots in some
> conditions.
> - PTRACE_GET_THREAD_AREA support for GDB.
Ping?
--
Daniel Jacobowitz
CodeSourcery, LLC
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: NPTL support for the kernel
2005-03-21 20:34 ` Daniel Jacobowitz
@ 2005-03-22 1:21 ` Kumba
2005-03-22 1:41 ` David Daney
0 siblings, 1 reply; 5+ messages in thread
From: Kumba @ 2005-03-22 1:21 UTC (permalink / raw)
To: linux-mips
Daniel Jacobowitz wrote:
>
> Ping?
>
Doesn't this need the glibc side of things to be effective?, or is it testable
w/o that component?
--Kumba
--
"Such is oft the course of deeds that move the wheels of the world: small
hands do them because they must, while the eyes of the great are elsewhere."
--Elrond
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: NPTL support for the kernel
2005-03-22 1:21 ` Kumba
@ 2005-03-22 1:41 ` David Daney
2005-03-22 3:21 ` Daniel Jacobowitz
0 siblings, 1 reply; 5+ messages in thread
From: David Daney @ 2005-03-22 1:41 UTC (permalink / raw)
To: Kumba; +Cc: linux-mips
Kumba wrote:
> Daniel Jacobowitz wrote:
>
>>
>> Ping?
>>
>
> Doesn't this need the glibc side of things to be effective?, or is it
> testable w/o that component?
I think the main point is that it should not break existing code.
We need NPTL support in all three of GCC, Linux kernel and glibc before
it can be tested. If it doesn't break existing code, I think it should
go in the kernel so that we have something on which to test gcc and glibc.
Just my $0.02
David Daney.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: NPTL support for the kernel
2005-03-22 1:41 ` David Daney
@ 2005-03-22 3:21 ` Daniel Jacobowitz
0 siblings, 0 replies; 5+ messages in thread
From: Daniel Jacobowitz @ 2005-03-22 3:21 UTC (permalink / raw)
To: David Daney; +Cc: Kumba, linux-mips
On Mon, Mar 21, 2005 at 05:41:51PM -0800, David Daney wrote:
> Kumba wrote:
> >Daniel Jacobowitz wrote:
> >
> >>
> >>Ping?
> >>
> >
> >Doesn't this need the glibc side of things to be effective?, or is it
> >testable w/o that component?
It is testable independently. Also, I posted the glibc bits last week.
> I think the main point is that it should not break existing code.
Of course. It doesn't. The only thing it could possibly break would
be four-argument clone (it's supposed to be five argument, and the
missing argument conventionally goes in the middle... oops). But
I strongly believe nothing is yet using the four-argument form so I
synced MIPS with the rest of the world.
> We need NPTL support in all three of GCC, Linux kernel and glibc before
> it can be tested. If it doesn't break existing code, I think it should
> go in the kernel so that we have something on which to test gcc and glibc.
GCC support was committed two weeks ago, BTW.
--
Daniel Jacobowitz
CodeSourcery, LLC
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2005-03-22 3:22 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-16 14:11 NPTL support for the kernel Daniel Jacobowitz
2005-03-21 20:34 ` Daniel Jacobowitz
2005-03-22 1:21 ` Kumba
2005-03-22 1:41 ` David Daney
2005-03-22 3:21 ` Daniel Jacobowitz
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox