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
This commit is contained in:
parent
6fba90f201
commit
822d2d6ac9
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=362122
@ -64,7 +64,6 @@ struct mdthread {
|
|||||||
int md_pc_count; /* performance counter */
|
int md_pc_count; /* performance counter */
|
||||||
int md_pc_spill; /* performance counter spill */
|
int md_pc_spill; /* performance counter spill */
|
||||||
void *md_tls;
|
void *md_tls;
|
||||||
size_t md_tls_tcb_offset; /* TCB offset */
|
|
||||||
#ifdef CPU_CNMIPS
|
#ifdef CPU_CNMIPS
|
||||||
struct octeon_cop2_state *md_cop2; /* kernel context */
|
struct octeon_cop2_state *md_cop2; /* kernel context */
|
||||||
struct octeon_cop2_state *md_ucop2; /* userland context */
|
struct octeon_cop2_state *md_ucop2; /* userland context */
|
||||||
@ -79,8 +78,7 @@ struct mdthread {
|
|||||||
#define MDTD_COP2USED 0x0002 /* Process used the COP2 */
|
#define MDTD_COP2USED 0x0002 /* Process used the COP2 */
|
||||||
|
|
||||||
struct mdproc {
|
struct mdproc {
|
||||||
/* Avoid empty structs because they are undefined behavior. */
|
size_t md_tls_tcb_offset; /* TCB offset */
|
||||||
long md_spare;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct syscall_args {
|
struct syscall_args {
|
||||||
|
@ -70,13 +70,15 @@ __FBSDID("$FreeBSD$");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSYM(TD_PCB, offsetof(struct thread, td_pcb));
|
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_UPTE, offsetof(struct thread, td_md.md_upte));
|
||||||
ASSYM(TD_KSTACK, offsetof(struct thread, td_kstack));
|
ASSYM(TD_KSTACK, offsetof(struct thread, td_kstack));
|
||||||
ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
|
ASSYM(TD_FLAGS, offsetof(struct thread, td_flags));
|
||||||
ASSYM(TD_LOCK, offsetof(struct thread, td_lock));
|
ASSYM(TD_LOCK, offsetof(struct thread, td_lock));
|
||||||
ASSYM(TD_MDFLAGS, offsetof(struct thread, td_md.md_flags));
|
ASSYM(TD_MDFLAGS, offsetof(struct thread, td_md.md_flags));
|
||||||
ASSYM(TD_MDTLS, offsetof(struct thread, td_md.md_tls));
|
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_REGS, offsetof(struct pcb, pcb_regs.zero));
|
||||||
ASSYM(U_PCB_CONTEXT, offsetof(struct pcb, pcb_context));
|
ASSYM(U_PCB_CONTEXT, offsetof(struct pcb, pcb_context));
|
||||||
|
@ -473,12 +473,15 @@ exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
|
|||||||
PCPU_SET(fpcurthread, (struct thread *)0);
|
PCPU_SET(fpcurthread, (struct thread *)0);
|
||||||
td->td_md.md_ss_addr = 0;
|
td->td_md.md_ss_addr = 0;
|
||||||
|
|
||||||
|
td->td_md.md_tls = NULL;
|
||||||
#ifdef COMPAT_FREEBSD32
|
#ifdef COMPAT_FREEBSD32
|
||||||
if (!SV_PROC_FLAG(td->td_proc, SV_LP64))
|
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
|
else
|
||||||
#endif
|
#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
|
int
|
||||||
|
@ -386,7 +386,8 @@ sw2:
|
|||||||
.globl cpu_switch_set_userlocal
|
.globl cpu_switch_set_userlocal
|
||||||
cpu_switch_set_userlocal:
|
cpu_switch_set_userlocal:
|
||||||
PTR_L t0, TD_MDTLS(a1) # Get TLS pointer
|
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
|
PTR_ADDU v0, t0, t1
|
||||||
MTC0 v0, MIPS_COP_0_USERLOCAL, 2 # write it to ULR for rdhwr
|
MTC0 v0, MIPS_COP_0_USERLOCAL, 2 # write it to ULR for rdhwr
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ sysarch(struct thread *td, struct sysarch_args *uap)
|
|||||||
*/
|
*/
|
||||||
if (cpuinfo.userlocal_reg == true) {
|
if (cpuinfo.userlocal_reg == true) {
|
||||||
mips_wr_userlocal((unsigned long)(uap->parms +
|
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);
|
return (0);
|
||||||
case MIPS_GET_TLS:
|
case MIPS_GET_TLS:
|
||||||
|
@ -902,7 +902,7 @@ trap(struct trapframe *trapframe)
|
|||||||
if (inst.RType.rd == 29) {
|
if (inst.RType.rd == 29) {
|
||||||
frame_regs = &(trapframe->zero);
|
frame_regs = &(trapframe->zero);
|
||||||
frame_regs[inst.RType.rt] = (register_t)(intptr_t)td->td_md.md_tls;
|
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);
|
trapframe->pc += sizeof(int);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -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 = 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_saved_intr = MIPS_SR_INT_IE;
|
||||||
td2->td_md.md_spinlock_count = 1;
|
td2->td_md.md_spinlock_count = 1;
|
||||||
#ifdef CPU_CNMIPS
|
#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_PX | MIPS_SR_UX | MIPS_SR_KX | MIPS_SR_SX) |
|
||||||
(MIPS_SR_INT_IE | MIPS_HARD_INT_MASK));
|
(MIPS_SR_INT_IE | MIPS_HARD_INT_MASK));
|
||||||
#endif
|
#endif
|
||||||
|
td->td_md.md_tls = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -473,16 +474,10 @@ int
|
|||||||
cpu_set_user_tls(struct thread *td, void *tls_base)
|
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;
|
td->td_md.md_tls = (char*)tls_base;
|
||||||
if (td == curthread && cpuinfo.userlocal_reg == true) {
|
if (td == curthread && cpuinfo.userlocal_reg == true) {
|
||||||
mips_wr_userlocal((unsigned long)tls_base +
|
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);
|
return (0);
|
||||||
|
Loading…
Reference in New Issue
Block a user