git: e318f24c0f53 - main - amd64: support for tracking per-thread 'disable splitlocks' state
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 22 Sep 2026 15:41:50 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=e318f24c0f53b52bd280b827509ad752db0497bf
commit e318f24c0f53b52bd280b827509ad752db0497bf
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-09-18 14:33:54 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-09-22 15:40:40 +0000
amd64: support for tracking per-thread 'disable splitlocks' state
If hw supports it, on atomic operation that requires exclusive ownership
of more than one cache line, #AC is generated.
The state is maintained as the arch-private TDF_MD_SPLITLOCK_AC flag.
The state is inherited on thread creation from the thread spawning the
new one. It is cleared on exec.
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D59815
---
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 d5d3342b7dff..19b087c783d3 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 c34dd7818b8c..b10c58955ce0 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -1928,6 +1928,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 8f8d91c768b7..74c1fc0d755e 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -10236,8 +10236,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 58af1cb8665c..49d46b31233d 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -182,6 +182,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 a46ae8dfe794..b85e442e559a 100644
--- a/sys/amd64/include/md_var.h
+++ b/sys/amd64/include/md_var.h
@@ -105,6 +105,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 9ecc5da15749..ce96fa0fedff 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 ecb497c61a1a..1134efd1c726 100644
--- a/sys/amd64/linux/linux_sysvec.c
+++ b/sys/amd64/linux/linux_sysvec.c
@@ -266,6 +266,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 c4de547b2bf5..f42654967e8f 100644
--- a/sys/amd64/linux32/linux32_sysvec.c
+++ b/sys/amd64/linux32/linux32_sysvec.c
@@ -608,6 +608,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);