Skip to content

Commit 3e2cbc0

Browse files
committed
Merge tag 'x86_splitlock_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 splitlock updates from Borislav Petkov: - Add Raptor Lake to the set of CPU models which support splitlock - Make life miserable for apps using split locks by slowing them down considerably while the rest of the system remains responsive. The hope is it will hurt more and people will really fix their misaligned locks apps. As a result, free a TIF bit. * tag 'x86_splitlock_for_v5.19_rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/split_lock: Enable the split lock feature on Raptor Lake x86/split-lock: Remove unused TIF_SLD bit x86/split_lock: Make life miserable for split lockers
2 parents 9166542 + 0180a1e commit 3e2cbc0

File tree

6 files changed

+63
-30
lines changed

6 files changed

+63
-30
lines changed

arch/x86/include/asm/cpu.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,12 @@ unsigned int x86_model(unsigned int sig);
4545
unsigned int x86_stepping(unsigned int sig);
4646
#ifdef CONFIG_CPU_SUP_INTEL
4747
extern void __init sld_setup(struct cpuinfo_x86 *c);
48-
extern void switch_to_sld(unsigned long tifn);
4948
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
5049
extern bool handle_guest_split_lock(unsigned long ip);
5150
extern void handle_bus_lock(struct pt_regs *regs);
5251
u8 get_this_hybrid_cpu_type(void);
5352
#else
5453
static inline void __init sld_setup(struct cpuinfo_x86 *c) {}
55-
static inline void switch_to_sld(unsigned long tifn) {}
5654
static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
5755
{
5856
return false;

arch/x86/include/asm/thread_info.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ struct thread_info {
9292
#define TIF_NOCPUID 15 /* CPUID is not accessible in userland */
9393
#define TIF_NOTSC 16 /* TSC is not accessible in userland */
9494
#define TIF_NOTIFY_SIGNAL 17 /* signal notifications exist */
95-
#define TIF_SLD 18 /* Restore split lock detection on context switch */
9695
#define TIF_MEMDIE 20 /* is terminating due to OOM killer */
9796
#define TIF_POLLING_NRFLAG 21 /* idle is polling for TIF_NEED_RESCHED */
9897
#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
@@ -116,7 +115,6 @@ struct thread_info {
116115
#define _TIF_NOCPUID (1 << TIF_NOCPUID)
117116
#define _TIF_NOTSC (1 << TIF_NOTSC)
118117
#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
119-
#define _TIF_SLD (1 << TIF_SLD)
120118
#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
121119
#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP)
122120
#define _TIF_SPEC_FORCE_UPDATE (1 << TIF_SPEC_FORCE_UPDATE)
@@ -128,7 +126,7 @@ struct thread_info {
128126
/* flags to check in __switch_to() */
129127
#define _TIF_WORK_CTXSW_BASE \
130128
(_TIF_NOCPUID | _TIF_NOTSC | _TIF_BLOCKSTEP | \
131-
_TIF_SSBD | _TIF_SPEC_FORCE_UPDATE | _TIF_SLD)
129+
_TIF_SSBD | _TIF_SPEC_FORCE_UPDATE)
132130

133131
/*
134132
* Avoid calls to __switch_to_xtra() on UP as STIBP is not evaluated.

arch/x86/kernel/cpu/intel.c

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
#include <linux/smp.h>
88
#include <linux/sched.h>
99
#include <linux/sched/clock.h>
10+
#include <linux/semaphore.h>
1011
#include <linux/thread_info.h>
1112
#include <linux/init.h>
1213
#include <linux/uaccess.h>
14+
#include <linux/workqueue.h>
1315
#include <linux/delay.h>
16+
#include <linux/cpuhotplug.h>
1417

1518
#include <asm/cpufeature.h>
1619
#include <asm/msr.h>
@@ -999,6 +1002,8 @@ static const struct {
9991002

10001003
static struct ratelimit_state bld_ratelimit;
10011004

1005+
static DEFINE_SEMAPHORE(buslock_sem);
1006+
10021007
static inline bool match_option(const char *arg, int arglen, const char *opt)
10031008
{
10041009
int len = strlen(opt), ratelimit;
@@ -1109,18 +1114,52 @@ static void split_lock_init(void)
11091114
split_lock_verify_msr(sld_state != sld_off);
11101115
}
11111116

1117+
static void __split_lock_reenable(struct work_struct *work)
1118+
{
1119+
sld_update_msr(true);
1120+
up(&buslock_sem);
1121+
}
1122+
1123+
/*
1124+
* If a CPU goes offline with pending delayed work to re-enable split lock
1125+
* detection then the delayed work will be executed on some other CPU. That
1126+
* handles releasing the buslock_sem, but because it executes on a
1127+
* different CPU probably won't re-enable split lock detection. This is a
1128+
* problem on HT systems since the sibling CPU on the same core may then be
1129+
* left running with split lock detection disabled.
1130+
*
1131+
* Unconditionally re-enable detection here.
1132+
*/
1133+
static int splitlock_cpu_offline(unsigned int cpu)
1134+
{
1135+
sld_update_msr(true);
1136+
1137+
return 0;
1138+
}
1139+
1140+
static DECLARE_DELAYED_WORK(split_lock_reenable, __split_lock_reenable);
1141+
11121142
static void split_lock_warn(unsigned long ip)
11131143
{
1114-
pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
1115-
current->comm, current->pid, ip);
1144+
int cpu;
11161145

1117-
/*
1118-
* Disable the split lock detection for this task so it can make
1119-
* progress and set TIF_SLD so the detection is re-enabled via
1120-
* switch_to_sld() when the task is scheduled out.
1121-
*/
1146+
if (!current->reported_split_lock)
1147+
pr_warn_ratelimited("#AC: %s/%d took a split_lock trap at address: 0x%lx\n",
1148+
current->comm, current->pid, ip);
1149+
current->reported_split_lock = 1;
1150+
1151+
/* misery factor #1, sleep 10ms before trying to execute split lock */
1152+
if (msleep_interruptible(10) > 0)
1153+
return;
1154+
/* Misery factor #2, only allow one buslocked disabled core at a time */
1155+
if (down_interruptible(&buslock_sem) == -EINTR)
1156+
return;
1157+
cpu = get_cpu();
1158+
schedule_delayed_work_on(cpu, &split_lock_reenable, 2);
1159+
1160+
/* Disable split lock detection on this CPU to make progress */
11221161
sld_update_msr(false);
1123-
set_tsk_thread_flag(current, TIF_SLD);
1162+
put_cpu();
11241163
}
11251164

11261165
bool handle_guest_split_lock(unsigned long ip)
@@ -1193,18 +1232,6 @@ void handle_bus_lock(struct pt_regs *regs)
11931232
}
11941233
}
11951234

1196-
/*
1197-
* This function is called only when switching between tasks with
1198-
* different split-lock detection modes. It sets the MSR for the
1199-
* mode of the new task. This is right most of the time, but since
1200-
* the MSR is shared by hyperthreads on a physical core there can
1201-
* be glitches when the two threads need different modes.
1202-
*/
1203-
void switch_to_sld(unsigned long tifn)
1204-
{
1205-
sld_update_msr(!(tifn & _TIF_SLD));
1206-
}
1207-
12081235
/*
12091236
* Bits in the IA32_CORE_CAPABILITIES are not architectural, so they should
12101237
* only be trusted if it is confirmed that a CPU model implements a
@@ -1230,6 +1257,7 @@ static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = {
12301257
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, 1),
12311258
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, 1),
12321259
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, 1),
1260+
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, 1),
12331261
{}
12341262
};
12351263

@@ -1274,10 +1302,14 @@ static void sld_state_show(void)
12741302
pr_info("disabled\n");
12751303
break;
12761304
case sld_warn:
1277-
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
1305+
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) {
12781306
pr_info("#AC: crashing the kernel on kernel split_locks and warning on user-space split_locks\n");
1279-
else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
1307+
if (cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
1308+
"x86/splitlock", NULL, splitlock_cpu_offline) < 0)
1309+
pr_warn("No splitlock CPU offline handler\n");
1310+
} else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) {
12801311
pr_info("#DB: warning on user-space bus_locks\n");
1312+
}
12811313
break;
12821314
case sld_fatal:
12831315
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) {

arch/x86/kernel/process.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -684,9 +684,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p)
684684
/* Enforce MSR update to ensure consistent state */
685685
__speculation_ctrl_update(~tifn, tifn);
686686
}
687-
688-
if ((tifp ^ tifn) & _TIF_SLD)
689-
switch_to_sld(tifn);
690687
}
691688

692689
/*

include/linux/sched.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,9 @@ struct task_struct {
941941
#ifdef CONFIG_IOMMU_SVA
942942
unsigned pasid_activated:1;
943943
#endif
944+
#ifdef CONFIG_CPU_SUP_INTEL
945+
unsigned reported_split_lock:1;
946+
#endif
944947

945948
unsigned long atomic_flags; /* Flags requiring atomic access. */
946949

kernel/fork.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,11 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
10461046
#ifdef CONFIG_MEMCG
10471047
tsk->active_memcg = NULL;
10481048
#endif
1049+
1050+
#ifdef CONFIG_CPU_SUP_INTEL
1051+
tsk->reported_split_lock = 0;
1052+
#endif
1053+
10491054
return tsk;
10501055

10511056
free_stack:

0 commit comments

Comments
 (0)