Page MenuHomeFreeBSD

D50482.id155906.diff
No OneTemporary

D50482.id155906.diff

diff --git a/lib/libsys/amd64/Makefile.sys b/lib/libsys/amd64/Makefile.sys
--- a/lib/libsys/amd64/Makefile.sys
+++ b/lib/libsys/amd64/Makefile.sys
@@ -3,6 +3,7 @@
amd64_get_gsbase.c \
amd64_set_fsbase.c \
amd64_set_gsbase.c \
+ amd64_set_tlsbase.c \
rfork_thread.S
MDASM= vfork.S cerror.S getcontext.S
diff --git a/lib/libsys/amd64/Symbol.sys.map b/lib/libsys/amd64/Symbol.sys.map
--- a/lib/libsys/amd64/Symbol.sys.map
+++ b/lib/libsys/amd64/Symbol.sys.map
@@ -13,6 +13,10 @@
x86_pkru_unprotect_range;
};
+FBSD_1.8 {
+ amd64_set_tlsbase;
+};
+
FBSDprivate_1.0 {
_vfork;
};
diff --git a/lib/libsys/amd64/amd64_set_tlsbase.c b/lib/libsys/amd64/amd64_set_tlsbase.c
new file mode 100644
--- /dev/null
+++ b/lib/libsys/amd64/amd64_set_tlsbase.c
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define _WANT_P_OSREL
+#include <sys/param.h>
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+#include <x86/ifunc.h>
+#include "libc_private.h"
+
+static int
+amd64_set_tlsbase_syscall(void *addr)
+{
+ return (sysarch(AMD64_SET_TLSBASE, &addr));
+}
+
+DEFINE_UIFUNC(, int, amd64_set_tlsbase, (void *))
+{
+ if (__getosreldate() >= P_OSREL_TLSBASE)
+ return (amd64_set_tlsbase_syscall);
+ return (amd64_set_fsbase);
+}
diff --git a/libexec/rtld-elf/amd64/reloc.c b/libexec/rtld-elf/amd64/reloc.c
--- a/libexec/rtld-elf/amd64/reloc.c
+++ b/libexec/rtld-elf/amd64/reloc.c
@@ -543,10 +543,12 @@
addr = allocate_tls(objs, 0, TLS_TCB_SIZE, TLS_TCB_ALIGN);
/*
- * This does not use _tcb_set() as it calls amd64_set_fsbase()
+ * This does not use _tcb_set() as it calls amd64_set_tlsbase()
* which is an ifunc and rtld must not use ifuncs.
*/
- if (__getosreldate() >= P_OSREL_WRFSBASE &&
+ if (__getosreldate() >= P_OSREL_TLSBASE)
+ sysarch(AMD64_SET_TLSBASE, &addr);
+ else if (__getosreldate() >= P_OSREL_WRFSBASE &&
(cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0)
wrfsbase((uintptr_t)addr);
else
diff --git a/sys/amd64/amd64/exec_machdep.c b/sys/amd64/amd64/exec_machdep.c
--- a/sys/amd64/amd64/exec_machdep.c
+++ b/sys/amd64/amd64/exec_machdep.c
@@ -209,6 +209,8 @@
regs->tf_fs = _ufssel;
regs->tf_gs = _ugssel;
regs->tf_flags = TF_HASSEGS;
+ if ((pcb->pcb_flags & PCB_TLSBASE) != 0)
+ pcb->pcb_fsbase = pcb->pcb_tlsbase;
PROC_LOCK(p);
mtx_lock(&psp->ps_mtx);
}
@@ -379,9 +381,9 @@
user_ldt_free(td);
update_pcb_bases(pcb);
- pcb->pcb_fsbase = 0;
+ pcb->pcb_fsbase = pcb->pcb_tlsbase = 0;
pcb->pcb_gsbase = 0;
- clear_pcb_flags(pcb, PCB_32BIT);
+ clear_pcb_flags(pcb, PCB_32BIT | PCB_TLSBASE);
pcb->pcb_initial_fpucw = __INITIAL_FPUCW__;
saved_rflags = regs->tf_rflags & PSL_T;
diff --git a/sys/amd64/amd64/ptrace_machdep.c b/sys/amd64/amd64/ptrace_machdep.c
--- a/sys/amd64/amd64/ptrace_machdep.c
+++ b/sys/amd64/amd64/ptrace_machdep.c
@@ -368,6 +368,27 @@
cpu_ptrace_setbase(td, req, rv);
break;
+ case PT_GETTLSBASE:
+ pcb = td->td_pcb;
+ if ((pcb->pcb_flags & PCB_TLSBASE) != 0)
+ error = copyout(&pcb->pcb_tlsbase, addr, sizeof(*r));
+ else
+ error = ESRCH;
+ break;
+
+ case PT_SETTLSBASE:
+ pcb = td->td_pcb;
+ error = copyin(addr, &rv, sizeof(rv));
+ if (error != 0)
+ break;
+ if (rv >= td->td_proc->p_sysent->sv_maxuser) {
+ error = EINVAL;
+ break;
+ }
+ pcb->pcb_tlsbase = rv;
+ set_pcb_flags(pcb, PCB_TLSBASE);
+ break;
+
default:
error = EINVAL;
break;
diff --git a/sys/amd64/amd64/sys_machdep.c b/sys/amd64/amd64/sys_machdep.c
--- a/sys/amd64/amd64/sys_machdep.c
+++ b/sys/amd64/amd64/sys_machdep.c
@@ -206,6 +206,8 @@
case AMD64_GET_XFPUSTATE:
case AMD64_SET_PKRU:
case AMD64_CLEAR_PKRU:
+ case AMD64_GET_TLSBASE:
+ case AMD64_SET_TLSBASE:
break;
case I386_SET_IOPERM:
@@ -311,14 +313,27 @@
error = copyout(&pcb->pcb_fsbase, uap->parms,
sizeof(pcb->pcb_fsbase));
break;
+ case AMD64_GET_TLSBASE:
+ if ((pcb->pcb_flags & PCB_TLSBASE) == 0) {
+ error = ESRCH;
+ } else {
+ error = copyout(&pcb->pcb_tlsbase, uap->parms,
+ sizeof(pcb->pcb_tlsbase));
+ }
+ break;
case AMD64_SET_FSBASE:
+ case AMD64_SET_TLSBASE:
error = copyin(uap->parms, &a64base, sizeof(a64base));
if (error == 0) {
if (a64base < curproc->p_sysent->sv_maxuser) {
set_pcb_flags(pcb, PCB_FULL_IRET);
pcb->pcb_fsbase = a64base;
td->td_frame->tf_fs = _ufssel;
+ if (uap->op == AMD64_SET_TLSBASE) {
+ pcb->pcb_tlsbase = a64base;
+ set_pcb_flags(pcb, PCB_TLSBASE);
+ }
} else
error = EINVAL;
}
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -156,7 +156,7 @@
/* Kernel threads start with clean FPU and segment bases. */
if ((td2->td_pflags & TDP_KTHREAD) != 0) {
- pcb2->pcb_fsbase = 0;
+ pcb2->pcb_fsbase = pcb2->pcb_tlsbase = 0;
pcb2->pcb_gsbase = 0;
clear_pcb_flags(pcb2, PCB_FPUINITDONE | PCB_USERFPUINITDONE |
PCB_KERNFPU | PCB_KERNFPU_THR);
@@ -182,7 +182,7 @@
* pcb2->pcb_savefpu: cloned above.
* pcb2->pcb_flags: cloned above.
* pcb2->pcb_onfault: cloned above (always NULL here?).
- * pcb2->pcb_[fg]sbase: cloned above
+ * pcb2->pcb_[f,g,tls]sbase: cloned above
*/
pcb2->pcb_tssp = NULL;
@@ -663,14 +663,14 @@
return (EINVAL);
pcb = td->td_pcb;
- set_pcb_flags(pcb, PCB_FULL_IRET);
+ set_pcb_flags(pcb, PCB_FULL_IRET | PCB_TLSBASE);
#ifdef COMPAT_FREEBSD32
if (SV_PROC_FLAG(td->td_proc, SV_ILP32)) {
pcb->pcb_gsbase = (register_t)tls_base;
return (0);
}
#endif
- pcb->pcb_fsbase = (register_t)tls_base;
+ pcb->pcb_fsbase = pcb->pcb_tlsbase = (register_t)tls_base;
return (0);
}
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -958,4 +958,5 @@
/* Return via doreti so that we can change to a different %cs */
set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
+ clear_pcb_flags(pcb, PCB_TLSBASE);
}
diff --git a/sys/amd64/include/pcb.h b/sys/amd64/include/pcb.h
--- a/sys/amd64/include/pcb.h
+++ b/sys/amd64/include/pcb.h
@@ -84,6 +84,7 @@
#define PCB_KERNFPU_THR 0x0020 /* fpu_kern_thread() */
#define PCB_32BIT 0x0040 /* process has 32 bit context (segs etc) */
#define PCB_FPUNOSAVE 0x0080 /* no save area for current FPU ctx */
+#define PCB_TLSBASE 0x0100 /* tlsbase was set */
uint16_t pcb_initial_fpucw;
@@ -104,7 +105,8 @@
struct savefpu *pcb_save;
- uint64_t pcb_pad[5];
+ register_t pcb_tlsbase; /* not same as pcb_fsbase */
+ uint64_t pcb_pad[4];
};
/* Per-CPU state saved during suspend and resume. */
diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -247,7 +247,7 @@
pcb->pcb_fsbase = 0;
pcb->pcb_gsbase = 0;
- clear_pcb_flags(pcb, PCB_32BIT);
+ clear_pcb_flags(pcb, PCB_32BIT | PCB_TLSBASE);
pcb->pcb_initial_fpucw = __LINUX_NPXCW__;
set_pcb_flags(pcb, PCB_FULL_IRET);
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -580,6 +580,10 @@
if (td->td_proc->p_md.md_ldt != NULL)
user_ldt_free(td);
+ /* Do full restore on return so that we can change to a different %cs */
+ set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
+ clear_pcb_flags(pcb, PCB_TLSBASE);
+
critical_enter();
wrmsr(MSR_FSBASE, 0);
wrmsr(MSR_KGSBASE, 0); /* User value while we're in the kernel */
@@ -605,9 +609,6 @@
x86_clear_dbregs(pcb);
fpstate_drop(td);
-
- /* Do full restore on return so that we can change to a different %cs */
- set_pcb_flags(pcb, PCB_32BIT | PCB_FULL_IRET);
}
/*
diff --git a/sys/sys/param.h b/sys/sys/param.h
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -73,7 +73,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1500043
+#define __FreeBSD_version 1500044
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
@@ -106,6 +106,7 @@
#define P_OSREL_POWERPC_NEW_AUX_ARGS 1300070
#define P_OSREL_TIDPID 1400079
#define P_OSREL_ARM64_SPSR 1400084
+#define P_OSREL_TLSBASE 1500044
#define P_OSREL_MAJOR(x) ((x) / 100000)
#endif
diff --git a/sys/x86/include/frame.h b/sys/x86/include/frame.h
--- a/sys/x86/include/frame.h
+++ b/sys/x86/include/frame.h
@@ -152,6 +152,7 @@
#define TF_HASSEGS 0x1
#define TF_HASBASES 0x2
#define TF_HASFPXSTATE 0x4
+#define TF_RESERV0 0x8 /* no tlsbase in the trapframe */
#endif /* __amd64__ */
#endif /* _MACHINE_FRAME_H_ */
diff --git a/sys/x86/include/ptrace.h b/sys/x86/include/ptrace.h
--- a/sys/x86/include/ptrace.h
+++ b/sys/x86/include/ptrace.h
@@ -54,6 +54,8 @@
#define PT_SETFSBASE (PT_FIRSTMACH + 8)
#define PT_GETGSBASE (PT_FIRSTMACH + 9)
#define PT_SETGSBASE (PT_FIRSTMACH + 10)
+#define PT_GETTLSBASE (PT_FIRSTMACH + 11)
+#define PT_SETTLSBASE (PT_FIRSTMACH + 12)
/* Argument structure for PT_GETXSTATE_INFO. */
struct ptrace_xstate_info {
diff --git a/sys/x86/include/sysarch.h b/sys/x86/include/sysarch.h
--- a/sys/x86/include/sysarch.h
+++ b/sys/x86/include/sysarch.h
@@ -61,6 +61,8 @@
#define AMD64_GET_XFPUSTATE 132
#define AMD64_SET_PKRU 133
#define AMD64_CLEAR_PKRU 134
+#define AMD64_GET_TLSBASE 135
+#define AMD64_SET_TLSBASE 136
/* Flags for AMD64_SET_PKRU */
#define AMD64_PKRU_EXCL 0x0001
diff --git a/sys/x86/include/tls.h b/sys/x86/include/tls.h
--- a/sys/x86/include/tls.h
+++ b/sys/x86/include/tls.h
@@ -69,7 +69,7 @@
_tcb_set(struct tcb *tcb)
{
#ifdef __amd64__
- amd64_set_fsbase(tcb);
+ amd64_set_tlsbase(tcb);
#else
i386_set_gsbase(tcb);
#endif
diff --git a/sys/x86/include/ucontext.h b/sys/x86/include/ucontext.h
--- a/sys/x86/include/ucontext.h
+++ b/sys/x86/include/ucontext.h
@@ -99,7 +99,9 @@
#define _MC_HASSEGS 0x1
#define _MC_HASBASES 0x2
#define _MC_HASFPXSTATE 0x4
-#define _MC_FLAG_MASK (_MC_HASSEGS | _MC_HASBASES | _MC_HASFPXSTATE)
+#define _MC_HASTLSBASE 0x8
+#define _MC_FLAG_MASK (_MC_HASSEGS | _MC_HASBASES | _MC_HASFPXSTATE | \
+ _MC_HASTLSBASE)
typedef struct __mcontext {
/*
@@ -158,7 +160,9 @@
__register_t mc_xfpustate;
__register_t mc_xfpustate_len;
- long mc_spare[4];
+ __register_t mc_tlsbase;
+
+ long mc_spare[3];
} mcontext_t;
#endif /* __amd64__ */

File Metadata

Mime Type
text/plain
Expires
Wed, Apr 8, 9:30 AM (8 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31091660
Default Alt Text
D50482.id155906.diff (11 KB)

Event Timeline