aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNathan Whitehorn <nwhitehorn@FreeBSD.org>2012-04-11 00:00:40 +0000
committerNathan Whitehorn <nwhitehorn@FreeBSD.org>2012-04-11 00:00:40 +0000
commit88fe385600deb9cd7dd23fbdf16efa4999193d4e (patch)
treefa4399d543adb338238e40a89c2c950e43bc75b5 /sys
parent43faa6b266e29cba16bfaf497d9f8cc10cf6bc91 (diff)
downloadsrc-88fe385600deb9cd7dd23fbdf16efa4999193d4e.tar.gz
src-88fe385600deb9cd7dd23fbdf16efa4999193d4e.zip
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
Notes
Notes: svn path=/head/; revision=234115
Diffstat (limited to 'sys')
-rw-r--r--sys/powerpc/powerpc/exec_machdep.c14
1 files changed, 12 insertions, 2 deletions
diff --git a/sys/powerpc/powerpc/exec_machdep.c b/sys/powerpc/powerpc/exec_machdep.c
index ec88d9faaea7..a23fd4c0fd13 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) {