summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornwhitehorn <nwhitehorn@FreeBSD.org>2012-04-11 00:00:40 +0000
committernwhitehorn <nwhitehorn@FreeBSD.org>2012-04-11 00:00:40 +0000
commit5ff92b1d9cf05d81d6ba6e43fbac5f0e1005df63 (patch)
treefa4399d543adb338238e40a89c2c950e43bc75b5
parentf0d73b67412f77f8ec067ccb7e25190dce1a3a14 (diff)
downloadFreeBSD-src-5ff92b1d9cf05d81d6ba6e43fbac5f0e1005df63.zip
FreeBSD-src-5ff92b1d9cf05d81d6ba6e43fbac5f0e1005df63.tar.gz
Do not restore the register holding the TLS pointer when doing various
usermode context switches (long jumps and ucontext operations). If these are used across threads, multiple threads can end up with the same TLS base. Madness will then result. This makes behavior on PPC match that on x86 systems and on Linux. MFC after: 10 days
-rw-r--r--lib/libc/powerpc/gen/_setjmp.S1
-rw-r--r--lib/libc/powerpc/gen/setjmp.S1
-rw-r--r--lib/libc/powerpc/gen/sigsetjmp.S1
-rw-r--r--lib/libc/powerpc64/gen/_setjmp.S1
-rw-r--r--lib/libc/powerpc64/gen/setjmp.S1
-rw-r--r--lib/libc/powerpc64/gen/sigsetjmp.S1
-rw-r--r--sys/powerpc/powerpc/exec_machdep.c14
7 files changed, 12 insertions, 8 deletions
diff --git a/lib/libc/powerpc/gen/_setjmp.S b/lib/libc/powerpc/gen/_setjmp.S
index 9b9f86e..bbf8644 100644
--- a/lib/libc/powerpc/gen/_setjmp.S
+++ b/lib/libc/powerpc/gen/_setjmp.S
@@ -63,7 +63,6 @@ ENTRY(_longjmp)
lmw %r9,20(%r3)
mtlr %r11
mtcr %r12
- mr %r2,%r9
mr %r1,%r10
or. %r3,%r4,%r4
bnelr
diff --git a/lib/libc/powerpc/gen/setjmp.S b/lib/libc/powerpc/gen/setjmp.S
index 447ba57..6df4f93 100644
--- a/lib/libc/powerpc/gen/setjmp.S
+++ b/lib/libc/powerpc/gen/setjmp.S
@@ -75,7 +75,6 @@ ENTRY(__longjmp)
mr %r6,%r4 /* save val param */
mtlr %r11 /* r11 -> link reg */
mtcr %r12 /* r12 -> condition reg */
- mr %r2,%r9 /* r9 -> global ptr */
mr %r1,%r10 /* r10 -> stackptr */
mr %r4,%r3
li %r3,3 /* SIG_SETMASK */
diff --git a/lib/libc/powerpc/gen/sigsetjmp.S b/lib/libc/powerpc/gen/sigsetjmp.S
index 5a6fd21..9639dd1 100644
--- a/lib/libc/powerpc/gen/sigsetjmp.S
+++ b/lib/libc/powerpc/gen/sigsetjmp.S
@@ -80,7 +80,6 @@ ENTRY(siglongjmp)
mr %r6,%r4
mtlr %r11
mtcr %r12
- mr %r2,%r9
mr %r1,%r10
or. %r7,%r7,%r7
beq 1f
diff --git a/lib/libc/powerpc64/gen/_setjmp.S b/lib/libc/powerpc64/gen/_setjmp.S
index a5c247d..ac0555e 100644
--- a/lib/libc/powerpc64/gen/_setjmp.S
+++ b/lib/libc/powerpc64/gen/_setjmp.S
@@ -86,7 +86,6 @@ ENTRY(_longjmp)
ld %r10,40 + 1*8(%r3)
ld %r11,40 + 2*8(%r3)
ld %r12,40 + 3*8(%r3)
- ld %r13,40 + 4*8(%r3)
ld %r14,40 + 5*8(%r3)
ld %r15,40 + 6*8(%r3)
ld %r16,40 + 7*8(%r3)
diff --git a/lib/libc/powerpc64/gen/setjmp.S b/lib/libc/powerpc64/gen/setjmp.S
index deda7c5..8fe2852 100644
--- a/lib/libc/powerpc64/gen/setjmp.S
+++ b/lib/libc/powerpc64/gen/setjmp.S
@@ -99,7 +99,6 @@ ENTRY(__longjmp)
ld %r10,40 + 1*8(%r3)
ld %r11,40 + 2*8(%r3)
ld %r12,40 + 3*8(%r3)
- ld %r13,40 + 4*8(%r3)
ld %r14,40 + 5*8(%r3)
ld %r15,40 + 6*8(%r3)
ld %r16,40 + 7*8(%r3)
diff --git a/lib/libc/powerpc64/gen/sigsetjmp.S b/lib/libc/powerpc64/gen/sigsetjmp.S
index 7b50f9f..d5341ea 100644
--- a/lib/libc/powerpc64/gen/sigsetjmp.S
+++ b/lib/libc/powerpc64/gen/sigsetjmp.S
@@ -103,7 +103,6 @@ ENTRY(siglongjmp)
ld %r10,40 + 1*8(%r3)
ld %r11,40 + 2*8(%r3)
ld %r12,40 + 3*8(%r3)
- ld %r13,40 + 4*8(%r3)
ld %r14,40 + 5*8(%r3)
ld %r15,40 + 6*8(%r3)
ld %r16,40 + 7*8(%r3)
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index ec88d9f..a23fd4c 100644
--- a/sys/powerpc/powerpc/exec_machdep.c
+++ b/sys/powerpc/powerpc/exec_machdep.c
@@ -441,6 +441,7 @@ set_mcontext(struct thread *td, const mcontext_t *mcp)
{
struct pcb *pcb;
struct trapframe *tf;
+ register_t tls;
pcb = td->td_pcb;
tf = td->td_frame;
@@ -448,16 +449,25 @@ set_mcontext(struct thread *td, const mcontext_t *mcp)
if (mcp->mc_vers != _MC_VERSION || mcp->mc_len != sizeof(*mcp))
return (EINVAL);
- #ifdef AIM
+#ifdef AIM
/*
* Don't let the user set privileged MSR bits
*/
if ((mcp->mc_srr1 & PSL_USERSTATIC) != (tf->srr1 & PSL_USERSTATIC)) {
return (EINVAL);
}
- #endif
+#endif
+ /* Copy trapframe, preserving TLS pointer across context change */
+ if (SV_PROC_FLAG(td->td_proc, SV_LP64))
+ tls = tf->fixreg[13];
+ else
+ tls = tf->fixreg[2];
memcpy(tf, mcp->mc_frame, sizeof(mcp->mc_frame));
+ if (SV_PROC_FLAG(td->td_proc, SV_LP64))
+ tf->fixreg[13] = tls;
+ else
+ tf->fixreg[2] = tls;
#ifdef AIM
if (mcp->mc_flags & _MC_FP_VALID) {
OpenPOWER on IntegriCloud