From 822d2d6ac94fd32049de39edfe9ac7d596b4a09b Mon Sep 17 00:00:00 2001 From: John Baldwin Date: Fri, 12 Jun 2020 21:21:18 +0000 Subject: [PATCH] Various fixes to TLS for MIPS. - Clear the current thread's TLS pointer on exec. Previously the TLS pointer (and register) remain unchanged. - Explicitly clear the TLS pointer when new threads are created. - Make md_tls_tcb_offset per-process instead of per-thread. The layout of the TLS and TCB are identical for all threads in a process, it is only the TLS pointer values themselves that vary by thread. This also makes setting md_tls_tcb_offset in cpu_set_user_tls() redundant with the setting in exec_setregs(), so only set it in exec_setregs(). Submitted by: Alfredo Mazzinghi (1) Sponsored by: DARPA Differential Revision: https://reviews.freebsd.org/D24957 --- sys/mips/include/proc.h | 4 +--- sys/mips/mips/genassym.c | 4 +++- sys/mips/mips/pm_machdep.c | 7 +++++-- sys/mips/mips/swtch.S | 3 ++- sys/mips/mips/sys_machdep.c | 2 +- sys/mips/mips/trap.c | 2 +- sys/mips/mips/vm_machdep.c | 11 +++-------- 7 files changed, 16 insertions(+), 17 deletions(-) diff --git a/sys/mips/include/proc.h b/sys/mips/include/proc.h index e35e0622513a..696854f40992 100644 --- a/sys/mips/include/proc.h +++ b/sys/mips/include/proc.h @@ -64,7 +64,6 @@ struct mdthread { int md_pc_count; /* performance counter */ int md_pc_spill; /* performance counter spill */ void *md_tls; - size_t md_tls_tcb_offset; /* TCB offset */ #ifdef CPU_CNMIPS struct octeon_cop2_state *md_cop2; /* kernel context */ struct octeon_cop2_state *md_ucop2; /* userland context */ @@ -79,8 +78,7 @@ struct mdthread { #define MDTD_COP2USED 0x0002 /* Process used the COP2 */ struct mdproc { - /* Avoid empty structs because they are undefined behavior. */ - long md_spare; + size_t md_tls_tcb_offset; /* TCB offset */ }; struct syscall_args { diff --git a/sys/mips/mips/genassym.c b/sys/mips/mips/genassym.c index 57703be300a8..ed4cc08607cd 100644 --- a/sys/mips/mips/genassym.c +++ b/sys/mips/mips/genassym.c @@ -70,13 +70,15 @@ __FBSDID("$FreeBSD$"); #endif ASSYM(TD_PCB, offsetof(struct thread, td_pcb)); +ASSYM(TD_PROC, offsetof(struct thread, td_proc)); ASSYM(TD_UPTE, offsetof(struct thread, td_md.md_upte)); ASSYM(TD_KSTACK, offsetof(struct thread, td_kstack)); ASSYM(TD_FLAGS, offsetof(struct thread, td_flags)); ASSYM(TD_LOCK, offsetof(struct thread, td_lock)); ASSYM(TD_MDFLAGS, offsetof(struct thread, td_md.md_flags)); ASSYM(TD_MDTLS, offsetof(struct thread, td_md.md_tls)); -ASSYM(TD_MDTLS_TCB_OFFSET, offsetof(struct thread, td_md.md_tls_tcb_offset)); + +ASSYM(P_MDTLS_TCB_OFFSET, offsetof(struct proc, p_md.md_tls_tcb_offset)); ASSYM(U_PCB_REGS, offsetof(struct pcb, pcb_regs.zero)); ASSYM(U_PCB_CONTEXT, offsetof(struct pcb, pcb_context)); diff --git a/sys/mips/mips/pm_machdep.c b/sys/mips/mips/pm_machdep.c index 2fc70bc948e7..d211be33c0ab 100644 --- a/sys/mips/mips/pm_machdep.c +++ b/sys/mips/mips/pm_machdep.c @@ -473,12 +473,15 @@ exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack) PCPU_SET(fpcurthread, (struct thread *)0); td->td_md.md_ss_addr = 0; + td->td_md.md_tls = NULL; #ifdef COMPAT_FREEBSD32 if (!SV_PROC_FLAG(td->td_proc, SV_LP64)) - td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE32; + td->td_proc->p_md.md_tls_tcb_offset = TLS_TP_OFFSET + + TLS_TCB_SIZE32; else #endif - td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE; + td->td_proc->p_md.md_tls_tcb_offset = TLS_TP_OFFSET + + TLS_TCB_SIZE; } int diff --git a/sys/mips/mips/swtch.S b/sys/mips/mips/swtch.S index ef1b7abc84b9..8d357004c84a 100644 --- a/sys/mips/mips/swtch.S +++ b/sys/mips/mips/swtch.S @@ -386,7 +386,8 @@ sw2: .globl cpu_switch_set_userlocal cpu_switch_set_userlocal: PTR_L t0, TD_MDTLS(a1) # Get TLS pointer - PTR_L t1, TD_MDTLS_TCB_OFFSET(a1) # Get TLS/TCB offset + PTR_L t1, TD_PROC(a1) + PTR_L t1, P_MDTLS_TCB_OFFSET(t1) # Get TLS/TCB offset PTR_ADDU v0, t0, t1 MTC0 v0, MIPS_COP_0_USERLOCAL, 2 # write it to ULR for rdhwr diff --git a/sys/mips/mips/sys_machdep.c b/sys/mips/mips/sys_machdep.c index 5c4941ea75af..87158b5c3cf3 100644 --- a/sys/mips/mips/sys_machdep.c +++ b/sys/mips/mips/sys_machdep.c @@ -72,7 +72,7 @@ sysarch(struct thread *td, struct sysarch_args *uap) */ if (cpuinfo.userlocal_reg == true) { mips_wr_userlocal((unsigned long)(uap->parms + - td->td_md.md_tls_tcb_offset)); + td->td_proc->p_md.md_tls_tcb_offset)); } return (0); case MIPS_GET_TLS: diff --git a/sys/mips/mips/trap.c b/sys/mips/mips/trap.c index 9832dac06bba..52e0708740a7 100644 --- a/sys/mips/mips/trap.c +++ b/sys/mips/mips/trap.c @@ -902,7 +902,7 @@ trap(struct trapframe *trapframe) if (inst.RType.rd == 29) { frame_regs = &(trapframe->zero); frame_regs[inst.RType.rt] = (register_t)(intptr_t)td->td_md.md_tls; - frame_regs[inst.RType.rt] += td->td_md.md_tls_tcb_offset; + frame_regs[inst.RType.rt] += td->td_proc->p_md.md_tls_tcb_offset; trapframe->pc += sizeof(int); goto out; } diff --git a/sys/mips/mips/vm_machdep.c b/sys/mips/mips/vm_machdep.c index f5910056c9e8..752e77318b1f 100644 --- a/sys/mips/mips/vm_machdep.c +++ b/sys/mips/mips/vm_machdep.c @@ -141,7 +141,7 @@ cpu_fork(struct thread *td1, struct proc *p2, struct thread *td2, int flags) */ td2->td_md.md_tls = td1->td_md.md_tls; - td2->td_md.md_tls_tcb_offset = td1->td_md.md_tls_tcb_offset; + p2->p_md.md_tls_tcb_offset = td1->td_proc->p_md.md_tls_tcb_offset; td2->td_md.md_saved_intr = MIPS_SR_INT_IE; td2->td_md.md_spinlock_count = 1; #ifdef CPU_CNMIPS @@ -403,6 +403,7 @@ cpu_copy_thread(struct thread *td, struct thread *td0) (MIPS_SR_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX) | (MIPS_SR_INT_IE | MIPS_HARD_INT_MASK)); #endif + td->td_md.md_tls = NULL; } /* @@ -473,16 +474,10 @@ int cpu_set_user_tls(struct thread *td, void *tls_base) { -#if defined(__mips_n64) && defined(COMPAT_FREEBSD32) - if (td->td_proc && SV_PROC_FLAG(td->td_proc, SV_ILP32)) - td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE32; - else -#endif - td->td_md.md_tls_tcb_offset = TLS_TP_OFFSET + TLS_TCB_SIZE; td->td_md.md_tls = (char*)tls_base; if (td == curthread && cpuinfo.userlocal_reg == true) { mips_wr_userlocal((unsigned long)tls_base + - td->td_md.md_tls_tcb_offset); + td->td_proc->p_md.md_tls_tcb_offset); } return (0);