diff --git a/sys/arm/arm/exec_machdep.c b/sys/arm/arm/exec_machdep.c --- a/sys/arm/arm/exec_machdep.c +++ b/sys/arm/arm/exec_machdep.c @@ -205,6 +205,8 @@ if (rv != 0) return (rv); } + mcp->mc_flags = _MC_TLS_VALID; + mcp->mc_tpidr = (register_t)get_tls(); return (0); } @@ -272,6 +274,8 @@ if (vfp != NULL) set_vfpcontext(td, vfp); #endif + if ((mcp->mc_flags & _MC_TLS_VALID) != 0) + set_tls((void *)mcp->mc_tpidr); return (0); } diff --git a/sys/arm/include/ucontext.h b/sys/arm/include/ucontext.h --- a/sys/arm/include/ucontext.h +++ b/sys/arm/include/ucontext.h @@ -82,7 +82,10 @@ */ __size_t mc_vfp_size; void *mc_vfp_ptr; - unsigned int mc_spare[33]; + unsigned int mc_flags; +#define _MC_TLS_VALID 0x2 /* Set when mc_tpidr is valid */ + __greg_t mc_tpidr; + unsigned int mc_spare[31]; } mcontext_t; #define UC_ diff --git a/sys/arm64/arm64/exec_machdep.c b/sys/arm64/arm64/exec_machdep.c --- a/sys/arm64/arm64/exec_machdep.c +++ b/sys/arm64/arm64/exec_machdep.c @@ -455,6 +455,8 @@ mcp->mc_gpregs.gp_sp = tf->tf_sp; mcp->mc_gpregs.gp_lr = tf->tf_lr; mcp->mc_gpregs.gp_elr = tf->tf_elr; + mcp->mc_flags = _MC_TLS_VALID; + mcp->mc_tpidr = READ_SPECIALREG(tpidr_el0); get_fpcontext(td, mcp); return (0); @@ -504,6 +506,8 @@ READ_SPECIALREG(mdscr_el1) | MDSCR_SS); isb(); } + if ((mcp->mc_flags & _MC_TLS_VALID) != 0) + WRITE_SPECIALREG(tpidr_el0, mcp->mc_tpidr); set_fpcontext(td, mcp); return (0); diff --git a/sys/arm64/arm64/freebsd32_machdep.c b/sys/arm64/arm64/freebsd32_machdep.c --- a/sys/arm64/arm64/freebsd32_machdep.c +++ b/sys/arm64/arm64/freebsd32_machdep.c @@ -195,6 +195,8 @@ mcp->mc_vfp_size = 0; mcp->mc_vfp_ptr = 0; + mcp->mc_flags = _MC_TLS_VALID; + mcp->mc_tpidr = READ_SPECIALREG(tpidrro_el0); memset(mcp->mc_spare, 0, sizeof(mcp->mc_spare)); } @@ -232,6 +234,11 @@ tf->tf_x[i] = mcp->mc_gregset[i]; tf->tf_elr = mcp->mc_gregset[15]; tf->tf_spsr = spsr; + if ((mcp->mc_flags & _MC_TLS_VALID) != 0) { + /* Set both to match cpu_set_user_tls */ + WRITE_SPECIALREG(tpidr_el0, mcp->mc_tpidr); + WRITE_SPECIALREG(tpidrro_el0, mcp->mc_tpidr); + } #ifdef VFP if (mcp->mc_vfp_size == sizeof(mc_vfp) && mcp->mc_vfp_ptr != 0) { if (copyin((void *)(uintptr_t)mcp->mc_vfp_ptr, &mc_vfp, diff --git a/sys/arm64/include/ucontext.h b/sys/arm64/include/ucontext.h --- a/sys/arm64/include/ucontext.h +++ b/sys/arm64/include/ucontext.h @@ -54,8 +54,10 @@ struct fpregs mc_fpregs; int mc_flags; #define _MC_FP_VALID 0x1 /* Set when mc_fpregs has valid data */ +#define _MC_TLS_VALID 0x2 /* Set when mc_tpidr is valid */ int mc_pad; /* Padding */ - __uint64_t mc_spare[8]; /* Space for expansion, set to zero */ + __register_t mc_tpidr; + __uint64_t mc_spare[7]; /* Space for expansion, set to zero */ }; typedef struct __mcontext mcontext_t; @@ -66,7 +68,9 @@ uint32_t mc_gregset[17]; uint32_t mc_vfp_size; uint32_t mc_vfp_ptr; - uint32_t mc_spare[33]; + uint32_t mc_flags; + uint32_t mc_tpidr; + uint32_t mc_spare[31]; } mcontext32_t; typedef struct __ucontext32 {