git: 6d6a82416b88 - stable/15 - amd64: support for tracking per-thread 'disable splitlocks' state

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 29 Sep 2026 00:31:57 UTC
The branch stable/15 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=6d6a82416b88183036577b824068a26919797791

commit 6d6a82416b88183036577b824068a26919797791
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-09-18 14:33:54 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-09-29 00:27:15 +0000

    amd64: support for tracking per-thread 'disable splitlocks' state
    
    (cherry picked from commit e318f24c0f53b52bd280b827509ad752db0497bf)
---
 sys/amd64/amd64/exec_machdep.c     | 10 ++++++++++
 sys/amd64/amd64/machdep.c          | 36 ++++++++++++++++++++++++++++++++++++
 sys/amd64/amd64/pmap.c             | 14 ++++++++++++++
 sys/amd64/amd64/vm_machdep.c       |  2 ++
 sys/amd64/ia32/ia32_signal.c       |  1 +
 sys/amd64/include/md_var.h         |  5 +++++
 sys/amd64/include/proc.h           |  2 ++
 sys/amd64/linux/linux_sysvec.c     |  1 +
 sys/amd64/linux32/linux32_sysvec.c |  1 +
 9 files changed, 72 insertions(+)

diff --git a/sys/amd64/amd64/exec_machdep.c b/sys/amd64/amd64/exec_machdep.c
index 12562968a4e3..698a81911e14 100644
--- a/sys/amd64/amd64/exec_machdep.c
+++ b/sys/amd64/amd64/exec_machdep.c
@@ -406,6 +406,15 @@ x86_clear_dbregs(struct pcb *pcb)
 	clear_pcb_flags(pcb, PCB_DBREGS);
 }
 
+void
+exec_splitlock(struct thread *td)
+{
+	if (ia32_splitlock_force)
+		enable_splitlock(td);
+	else if (ia32_splitlock)
+		disable_splitlock(td);
+}
+
 /*
  * Reset registers to default values on exec.
  */
@@ -443,6 +452,7 @@ exec_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
 	regs->tf_flags = TF_HASSEGS;
 
 	x86_clear_dbregs(pcb);
+	exec_splitlock(td);
 
 	/*
 	 * Drop the FP state if we hold it, so that the process gets a
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index 1d823650a737..0b72a1043b40 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1929,6 +1929,42 @@ safe_read(vm_offset_t addr, char *valp)
 	return (uiomove_mem(UIO_MEM_KMEM, &uio));
 }
 
+void
+enable_splitlock_ac(void)
+{
+	MPASS(ia32_splitlock);
+	wrmsr(MSR_MEMORY_CTL, rdmsr(MSR_MEMORY_CTL) |
+	    MSR_MEMORY_CTL_SPLITLOCK);
+}
+
+void
+enable_splitlock(struct thread *td)
+{
+	MPASS(td == curthread);
+	td->td_md.md_td_flags |= TDF_MD_SPLITLOCK_AC;
+	critical_enter();
+	enable_splitlock_ac();
+	critical_exit();
+}
+
+void
+disable_splitlock_ac(void)
+{
+	MPASS(ia32_splitlock);
+	wrmsr(MSR_MEMORY_CTL, rdmsr(MSR_MEMORY_CTL) &
+	    ~MSR_MEMORY_CTL_SPLITLOCK);
+}
+
+void
+disable_splitlock(struct thread *td)
+{
+	MPASS(td == curthread);
+	td->td_md.md_td_flags &= ~TDF_MD_SPLITLOCK_AC;
+	critical_enter();
+	disable_splitlock_ac();
+	critical_exit();
+}
+
 #ifdef KDB
 
 /*
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 63ff6269119b..b3f8c2d60468 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -10235,8 +10235,22 @@ DEFINE_IFUNC(static, void, pmap_activate_sw_mode, (struct thread *, pmap_t,
 void
 pmap_activate_sw(struct thread *td)
 {
+	struct thread *oldtd;
 	pmap_t oldpmap, pmap;
 	u_int cpuid;
+	bool oldtd_sl, td_sl;
+
+	oldtd = curthread;
+	if (ia32_splitlock && oldtd != td) {
+		oldtd_sl = (atomic_load_int(&oldtd->td_md.md_td_flags) &
+		    TDF_MD_SPLITLOCK_AC) != 0;
+		td_sl = (atomic_load_int(&td->td_md.md_td_flags) &
+		    TDF_MD_SPLITLOCK_AC) != 0;
+		if (oldtd_sl && !td_sl)
+			disable_splitlock_ac();
+		else if (!oldtd_sl && td_sl)
+			enable_splitlock_ac();
+	}
 
 	oldpmap = PCPU_GET(curpmap);
 	pmap = vmspace_pmap(td->td_proc->p_vmspace);
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 200a63add3d8..2fd3c2443118 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -199,6 +199,8 @@ copy_thread(struct thread *td1, struct thread *td2)
 	/* Setup to release spin count in fork_exit(). */
 	td2->td_md.md_spinlock_count = 1;
 	td2->td_md.md_saved_flags = PSL_KERNEL | PSL_I;
+	td2->td_md.md_td_flags = td1->td_md.md_td_flags &
+	    TDF_MD_SPLITLOCK_AC;
 	pmap_thread_init_invl_gen(td2);
 
 	/*
diff --git a/sys/amd64/ia32/ia32_signal.c b/sys/amd64/ia32/ia32_signal.c
index 3b26244932b4..84912b292861 100644
--- a/sys/amd64/ia32/ia32_signal.c
+++ b/sys/amd64/ia32/ia32_signal.c
@@ -981,6 +981,7 @@ ia32_setregs(struct thread *td, struct image_params *imgp, uintptr_t stack)
 	regs->tf_flags = TF_HASSEGS;
 
 	x86_clear_dbregs(pcb);
+	exec_splitlock(td);
 
 	fpstate_drop(td);
 
diff --git a/sys/amd64/include/md_var.h b/sys/amd64/include/md_var.h
index ae5f0b3a5850..f73cb916d53a 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -106,6 +106,11 @@ void	get_fpcontext(struct thread *td, struct __mcontext *mcp,
 	    char **xfpusave, size_t *xfpusave_len);
 int	set_fpcontext(struct thread *td, struct __mcontext *mcp,
 	    char *xfpustate, size_t xfpustate_len);
+void	enable_splitlock_ac(void);
+void	enable_splitlock(struct thread *td);
+void	disable_splitlock_ac(void);
+void	disable_splitlock(struct thread *td);
+void	exec_splitlock(struct thread *td);
 
 void	wrmsr_early_safe_start(void);
 void	wrmsr_early_safe_end(void);
diff --git a/sys/amd64/include/proc.h b/sys/amd64/include/proc.h
index 10b79128b0f5..6c75c7c1c021 100644
--- a/sys/amd64/include/proc.h
+++ b/sys/amd64/include/proc.h
@@ -80,6 +80,8 @@ struct mdthread {
 	void *md_usr_fpu_save;
 };
 
+#define	TDF_MD_SPLITLOCK_AC	0x00000001	/* Disable split cache lines */
+
 struct mdproc {
 	struct proc_ldt *md_ldt;	/* (t) per-process ldt */
 	struct system_segment_descriptor md_ldt_sd;
diff --git a/sys/amd64/linux/linux_sysvec.c b/sys/amd64/linux/linux_sysvec.c
index 890cf01c46a0..210c3e127de3 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -265,6 +265,7 @@ linux_exec_setregs(struct thread *td, struct image_params *imgp,
 	regs->tf_flags = TF_HASSEGS;
 
 	x86_clear_dbregs(pcb);
+	exec_splitlock(td);
 
 	/*
 	 * Drop the FP state if we hold it, so that the process gets a
diff --git a/sys/amd64/linux32/linux32_sysvec.c b/sys/amd64/linux32/linux32_sysvec.c
index 735ebb151017..a61039a2dc16 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -607,6 +607,7 @@ linux_exec_setregs(struct thread *td, struct image_params *imgp,
 	regs->tf_rbx = (register_t)imgp->ps_strings;
 
 	x86_clear_dbregs(pcb);
+	exec_splitlock(td);
 
 	fpstate_drop(td);
 }