未验证 提交 c6897937 编写于 作者: O openeuler-ci-bot 提交者: Gitee

!53 Help to merge the bus lock detection and ratelimit feature for OpenEuler

Merge Pull Request from: @etzhao 
 
Hi,

Bus lock detection and ratelimit feature for OpenEuler backporting was tested Okay, help to review and merge

Title: bus lock detection and ratelimit feature for OpenEuler.

Content:
Bus locks degrade performance for the whole system, not just for the CPU
that requested the bus lock. Two CPU features "#AC for split lock" and
"#DB for bus lock" provide hooks so that the operating system may choose
one of several mitigation strategies.

bus lock feature to cover additional situations with new options to
mitigate.

This patch set enables the bus lock detection functions and will limite 
the warning message output rate to desired number.
Intel-kernel issue:
#I5G10C:SPR:Bus lock detection and ratelimit support

Test:
Bus lock detection/split lock disable test for OpenEuler

Check If the CPU has the bus lock detection or split lock feature
#cat /proc/cpuinfo |grep bus_lock_detect
bus_lock_detect

#cat /proc/cpuinfo |grep split_lock_detect
split_lock_detect

The result shows the "bus_lock_detect" or "split_lock_detect" pass

warn mode, default is warn mode without any parameters to kernel command line.
split lock detection is enabled by kernel

dmesg |grep '#AC'
[ 0.000000] x86/split lock detection: #AC: crashing the kernel on kernel split_locks and warning on user-space split_locks

(seeing above, pass, or fail)

Note the under default "warn" mode, bus lock detect handler is disabled, handled by split lock handler.

#wget http://linux-os.sc.intel.com/~fyu/projects/split_lock/tests/split_lock_test_user.c
#gcc -o split_lock_test_user split_lock_test_user.c

#./split_lock_test_user
This test both split lock(cross cache line) and bus lock (explict lock instruction)
[67152.780022] x86/split lock detection: #AC: split_lock_test/284139 took a split_lock trap at address: 0x4011ab
(seeing this, pass, or fail)

Modify the split_lock_test_user.c to only trigger bus lock with 64 bytes aligned WB cached memory

+ /* iptr = (int *)(cptr + 61); */

 test_sigbus(iptr);

 free(cptr);

 return 0;
}

gcc -o split_lock_test_user split_lock_test_user.c
#./split_lock_test_user
#see dmesg, no warning message.

Under your kernel source git repo directory.
#git am 0001-x86-split-lock-vmdos-Test-split-lock-and-vmdos.patch
#make
#cd arch/x86/kernel/cpu/
#insmod ./test_split_lock_drv.ko

Got following panic message and panic pass or fail.

[ 327.415019] split lock test: split lock address=0xff722131cce07bbd
[ 327.415025] Split lock detected
: 0000 [#1] SMP NOPTI
[ 327.415048] CPU: 46 PID: 4952 Comm: insmod Tainted: G S
[ 327.415069] Hardware name: Intel Corporation EAGLESTREAM/EAGLESTREAM,
[ 327.415093] RIP: 0010:init_module+0x40/0x85 [test_split_lock_drv]
[ 327.415107] Code: ec c0 00 00 00 65 48 8b 04 25 28 00 00 00 48 89 84 24 b8 00 00 00 31 c0 48 8d 74 24 3d c7 44 24 3d 00 00 00 00 e8 22 41 b2 d8 0f ba 6c 24 3d 00 83 7c 24 3d 01 75 0e 48 c7 c7 70 50 42 c0 e8
[ 327.415156] RSP: 0018:ff722131cce07b80 EFLAGS: 00010246
[ 327.415801] RAX: 0000000000000036 RBX: ffffffffc0424000 RCX: 0000000000000000
[ 327.416431] RDX: 0000000000000000 RSI: ff1928e73ef98860 RDI: ff1928e73ef98860
[ 327.417052] RBP: ff722131cce07c68 R08: 0000000000000000 R09: c0000000fffeffff
[ 327.417674] R10: 0000000000000001 R11: ff722131cce07950 R12: 0000000000000000
[ 327.418293] R13: ff722131cce07d68 R14: ff722131cce07e70 R15: ffffffffc0426000
[ 327.418907] FS: 00007fdb99824740(0000) GS:ff1928e73ef80000(0000) knlGS:0000000000000000
[ 327.419535] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 327.420169] CR2: 000055e9f3d8a068 CR3: 000000017cbbc003 CR4: 0000000000771ee0
[ 327.420808] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 327.421441] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400

Verify ratelimit (raltelimit implies the warn mode of bus lock detect with ratelimit feature)
Append "split_lock_detect=ratelimit:2" to kernel command line
See dmesg

[ 0.000000] x86/split lock detection: #DB: setting system wide bus lock rate limit to 2/sec
modify the split_lock_test_user.c to add while(1) loop, trigger bus lock forever without interval.

void test_sigbus(int *iptr)
{
pid_t pid;

    pid = fork();
    if (pid)
            return;

    /*
     * The locked instruction will trigger #AC and kernel will deliver
     * SIGBUS to this process. The SIGBUS handler in this process will
     * verify that the signal is delivered and the process is killed then.
     */
  +  while(1)
       do_split_locked_inst(iptr);
}

Re-run the ./split_lock_test
see dmesg to know the warning message is limited to 2 times per second or fail.

[ 1274.605344] x86/split lock detection: #DB: split_lock_test/23868 took a bus_lock trap at address: 0x4011af
[ 1275.617334] x86/split lock detection: #DB: split_lock_test/23868 took a bus_lock trap at address: 0x4011af

Fatal mode
Append split_lock_detect=fatal to kernel command line
see dmesg
[ 0.000000] x86/split lock detection: #AC: crashing the kernel on kernel split_locks and sending SIGBUS on user-space split_locks
Run
#./split_lock_test

./split_lock_test_user
Caught SIGBUS/#AC due to split locked access
(seeing above message pass, or fail)

#cd arch/x86/kernel/cpu/
#insmod ./test_split_lock_drv.ko
Got following panic message and panic pass or fail.

[ 327.415019] split lock test: split lock address=0xff722131cce07bbd
[ 327.415025] Split lock detected
: 0000 [#1] SMP NOPTI
[ 327.415048] CPU: 46 PID: 4952 Comm: insmod Tainted: G S
[ 327.415069] Hardware name: Intel Corporation EAGLESTREAM
[ 327.415093] RIP: 0010:init_module+0x40/0x85 [test_split_lock_drv]
[ 327.415107] Code: ec c0 00 00 00 65 48 8b 04 25 28 00 00 00 48 89 84 24 b8 00 00 00 31 c0 48 8d 74 24 3d c7 44 24 3d 00 00 00 00 e8 22 41 b2 d8 0f ba 6c 24 3d 00 83 7c 24 3d 01 75 0e 48 c7 c7 70 50 42 c0 e8
[ 327.415156] RSP: 0018:ff722131cce07b80 EFLAGS: 00010246
[ 327.415801] RAX: 0000000000000036 RBX: ffffffffc0424000 RCX: 0000000000000000
[ 327.416431] RDX: 0000000000000000 RSI: ff1928e73ef98860 RDI: ff1928e73ef98860
[ 327.417052] RBP: ff722131cce07c68 R08: 0000000000000000 R09: c0000000fffeffff
[ 327.417674] R10: 0000000000000001 R11: ff722131cce07950 R12: 0000000000000000
[ 327.418293] R13: ff722131cce07d68 R14: ff722131cce07e70 R15: ffffffffc0426000
[ 327.418907] FS: 00007fdb99824740(0000) GS:ff1928e73ef80000(0000) knlGS:0000000000000000
[ 327.419535] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 327.420169] CR2: 000055e9f3d8a068 CR3: 000000017cbbc003 CR4: 0000000000771ee0
[ 327.420808] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 327.421441] DR3: 0000000000000000 DR6: 00000000fffe07f0 DR7: 0000000000000400

Known issue:
No

Default config change:
No

Thanks,
Ethan 
 
Link:https://gitee.com/openeuler/kernel/pulls/53 
Reviewed-by: Zheng Zengkai <zhengzengkai@huawei.com> 
Reviewed-by: Liu Chao <liuchao173@huawei.com> 
Signed-off-by: Xie XiuQi <xiexiuqi@huawei.com> 
...@@ -5278,27 +5278,45 @@ ...@@ -5278,27 +5278,45 @@
spia_peddr= spia_peddr=
split_lock_detect= split_lock_detect=
[X86] Enable split lock detection [X86] Enable split lock detection or bus lock detection
When enabled (and if hardware support is present), atomic When enabled (and if hardware support is present), atomic
instructions that access data across cache line instructions that access data across cache line
boundaries will result in an alignment check exception. boundaries will result in an alignment check exception
for split lock detection or a debug exception for
bus lock detection.
off - not enabled off - not enabled
warn - the kernel will emit rate limited warnings warn - the kernel will emit rate-limited warnings
about applications triggering the #AC about applications triggering the #AC
exception. This mode is the default on CPUs exception or the #DB exception. This mode is
that supports split lock detection. the default on CPUs that support split lock
detection or bus lock detection. Default
behavior is by #AC if both features are
enabled in hardware.
fatal - the kernel will send SIGBUS to applications fatal - the kernel will send SIGBUS to applications
that trigger the #AC exception. that trigger the #AC exception or the #DB
exception. Default behavior is by #AC if
both features are enabled in hardware.
ratelimit:N -
Set system wide rate limit to N bus locks
per second for bus lock detection.
0 < N <= 1000.
N/A for split lock detection.
If an #AC exception is hit in the kernel or in If an #AC exception is hit in the kernel or in
firmware (i.e. not while executing in user mode) firmware (i.e. not while executing in user mode)
the kernel will oops in either "warn" or "fatal" the kernel will oops in either "warn" or "fatal"
mode. mode.
#DB exception for bus lock is triggered only when
CPL > 0.
srbds= [X86,INTEL] srbds= [X86,INTEL]
Control the Special Register Buffer Data Sampling Control the Special Register Buffer Data Sampling
(SRBDS) mitigation. (SRBDS) mitigation.
......
.. SPDX-License-Identifier: GPL-2.0
.. include:: <isonum.txt>
===============================
Bus lock detection and handling
===============================
:Copyright: |copy| 2021 Intel Corporation
:Authors: - Fenghua Yu <fenghua.yu@intel.com>
- Tony Luck <tony.luck@intel.com>
Problem
=======
A split lock is any atomic operation whose operand crosses two cache lines.
Since the operand spans two cache lines and the operation must be atomic,
the system locks the bus while the CPU accesses the two cache lines.
A bus lock is acquired through either split locked access to writeback (WB)
memory or any locked access to non-WB memory. This is typically thousands of
cycles slower than an atomic operation within a cache line. It also disrupts
performance on other cores and brings the whole system to its knees.
Detection
=========
Intel processors may support either or both of the following hardware
mechanisms to detect split locks and bus locks.
#AC exception for split lock detection
--------------------------------------
Beginning with the Tremont Atom CPU split lock operations may raise an
Alignment Check (#AC) exception when a split lock operation is attemped.
#DB exception for bus lock detection
------------------------------------
Some CPUs have the ability to notify the kernel by an #DB trap after a user
instruction acquires a bus lock and is executed. This allows the kernel to
terminate the application or to enforce throttling.
Software handling
=================
The kernel #AC and #DB handlers handle bus lock based on the kernel
parameter "split_lock_detect". Here is a summary of different options:
+------------------+----------------------------+-----------------------+
|split_lock_detect=|#AC for split lock |#DB for bus lock |
+------------------+----------------------------+-----------------------+
|off |Do nothing |Do nothing |
+------------------+----------------------------+-----------------------+
|warn |Kernel OOPs |Warn once per task and |
|(default) |Warn once per task and |and continues to run. |
| |disable future checking | |
| |When both features are | |
| |supported, warn in #AC | |
+------------------+----------------------------+-----------------------+
|fatal |Kernel OOPs |Send SIGBUS to user. |
| |Send SIGBUS to user | |
| |When both features are | |
| |supported, fatal in #AC | |
+------------------+----------------------------+-----------------------+
Usages
======
Detecting and handling bus lock may find usages in various areas:
It is critical for real time system designers who build consolidated real
time systems. These systems run hard real time code on some cores and run
"untrusted" user processes on other cores. The hard real time cannot afford
to have any bus lock from the untrusted processes to hurt real time
performance. To date the designers have been unable to deploy these
solutions as they have no way to prevent the "untrusted" user code from
generating split lock and bus lock to block the hard real time code to
access memory during bus locking.
It's also useful for general computing to prevent guests or user
applications from slowing down the overall system by executing instructions
with bus lock.
Guidance
========
off
---
Disable checking for split lock and bus lock. This option can be useful if
there are legacy applications that trigger these events at a low rate so
that mitigation is not needed.
warn
----
A warning is emitted when a bus lock is detected which allows to identify
the offending application. This is the default behavior.
fatal
-----
In this case, the bus lock is not tolerated and the process is killed.
...@@ -30,6 +30,7 @@ x86-specific Documentation ...@@ -30,6 +30,7 @@ x86-specific Documentation
microcode microcode
resctrl_ui resctrl_ui
tsx_async_abort tsx_async_abort
buslock
usb-legacy-support usb-legacy-support
i386/index i386/index
x86_64/index x86_64/index
......
...@@ -41,12 +41,13 @@ unsigned int x86_family(unsigned int sig); ...@@ -41,12 +41,13 @@ unsigned int x86_family(unsigned int sig);
unsigned int x86_model(unsigned int sig); unsigned int x86_model(unsigned int sig);
unsigned int x86_stepping(unsigned int sig); unsigned int x86_stepping(unsigned int sig);
#ifdef CONFIG_CPU_SUP_INTEL #ifdef CONFIG_CPU_SUP_INTEL
extern void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c); extern void __init sld_setup(struct cpuinfo_x86 *c);
extern void switch_to_sld(unsigned long tifn); extern void switch_to_sld(unsigned long tifn);
extern bool handle_user_split_lock(struct pt_regs *regs, long error_code); extern bool handle_user_split_lock(struct pt_regs *regs, long error_code);
extern bool handle_guest_split_lock(unsigned long ip); extern bool handle_guest_split_lock(unsigned long ip);
extern void handle_bus_lock(struct pt_regs *regs);
#else #else
static inline void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) {} static inline void __init sld_setup(struct cpuinfo_x86 *c) {}
static inline void switch_to_sld(unsigned long tifn) {} static inline void switch_to_sld(unsigned long tifn) {}
static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code) static inline bool handle_user_split_lock(struct pt_regs *regs, long error_code)
{ {
...@@ -57,6 +58,8 @@ static inline bool handle_guest_split_lock(unsigned long ip) ...@@ -57,6 +58,8 @@ static inline bool handle_guest_split_lock(unsigned long ip)
{ {
return false; return false;
} }
static inline void handle_bus_lock(struct pt_regs *regs) {}
#endif #endif
#ifdef CONFIG_IA32_FEAT_CTL #ifdef CONFIG_IA32_FEAT_CTL
void init_ia32_feat_ctl(struct cpuinfo_x86 *c); void init_ia32_feat_ctl(struct cpuinfo_x86 *c);
......
...@@ -357,6 +357,7 @@ ...@@ -357,6 +357,7 @@
#define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */ #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
#define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */ #define X86_FEATURE_LA57 (16*32+16) /* 5-level page tables */
#define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */ #define X86_FEATURE_RDPID (16*32+22) /* RDPID instruction */
#define X86_FEATURE_BUS_LOCK_DETECT (16*32+24) /* Bus Lock detect */
#define X86_FEATURE_CLDEMOTE (16*32+25) /* CLDEMOTE instruction */ #define X86_FEATURE_CLDEMOTE (16*32+25) /* CLDEMOTE instruction */
#define X86_FEATURE_MOVDIRI (16*32+27) /* MOVDIRI instruction */ #define X86_FEATURE_MOVDIRI (16*32+27) /* MOVDIRI instruction */
#define X86_FEATURE_MOVDIR64B (16*32+28) /* MOVDIR64B instruction */ #define X86_FEATURE_MOVDIR64B (16*32+28) /* MOVDIR64B instruction */
......
...@@ -289,6 +289,7 @@ ...@@ -289,6 +289,7 @@
#define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ #define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */
#define DEBUGCTLMSR_BTF_SHIFT 1 #define DEBUGCTLMSR_BTF_SHIFT 1
#define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ #define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */
#define DEBUGCTLMSR_BUS_LOCK_DETECT (1UL << 2)
#define DEBUGCTLMSR_TR (1UL << 6) #define DEBUGCTLMSR_TR (1UL << 6)
#define DEBUGCTLMSR_BTS (1UL << 7) #define DEBUGCTLMSR_BTS (1UL << 7)
#define DEBUGCTLMSR_BTINT (1UL << 8) #define DEBUGCTLMSR_BTINT (1UL << 8)
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#define DR_TRAP3 (0x8) /* db3 */ #define DR_TRAP3 (0x8) /* db3 */
#define DR_TRAP_BITS (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3) #define DR_TRAP_BITS (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)
#define DR_BUS_LOCK (0x800) /* bus_lock */
#define DR_STEP (0x4000) /* single-step */ #define DR_STEP (0x4000) /* single-step */
#define DR_SWITCH (0x8000) /* task switch */ #define DR_SWITCH (0x8000) /* task switch */
......
...@@ -1374,7 +1374,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c) ...@@ -1374,7 +1374,7 @@ static void __init early_identify_cpu(struct cpuinfo_x86 *c)
cpu_set_bug_bits(c); cpu_set_bug_bits(c);
cpu_set_core_cap_bits(c); sld_setup(c);
fpu__init_system(c); fpu__init_system(c);
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/thread_info.h> #include <linux/thread_info.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/delay.h>
#include <asm/cpufeature.h> #include <asm/cpufeature.h>
#include <asm/msr.h> #include <asm/msr.h>
...@@ -41,12 +42,13 @@ enum split_lock_detect_state { ...@@ -41,12 +42,13 @@ enum split_lock_detect_state {
sld_off = 0, sld_off = 0,
sld_warn, sld_warn,
sld_fatal, sld_fatal,
sld_ratelimit,
}; };
/* /*
* Default to sld_off because most systems do not support split lock detection * Default to sld_off because most systems do not support split lock detection.
* split_lock_setup() will switch this to sld_warn on systems that support * sld_state_setup() will switch this to sld_warn on systems that support
* split lock detect, unless there is a command line override. * split lock/bus lock detect, unless there is a command line override.
*/ */
static enum split_lock_detect_state sld_state __ro_after_init = sld_off; static enum split_lock_detect_state sld_state __ro_after_init = sld_off;
static u64 msr_test_ctrl_cache __ro_after_init; static u64 msr_test_ctrl_cache __ro_after_init;
...@@ -603,6 +605,7 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c) ...@@ -603,6 +605,7 @@ static void init_intel_misc_features(struct cpuinfo_x86 *c)
} }
static void split_lock_init(void); static void split_lock_init(void);
static void bus_lock_init(void);
static void init_intel(struct cpuinfo_x86 *c) static void init_intel(struct cpuinfo_x86 *c)
{ {
...@@ -720,6 +723,7 @@ static void init_intel(struct cpuinfo_x86 *c) ...@@ -720,6 +723,7 @@ static void init_intel(struct cpuinfo_x86 *c)
tsx_disable(); tsx_disable();
split_lock_init(); split_lock_init();
bus_lock_init();
intel_init_thermal(c); intel_init_thermal(c);
} }
...@@ -995,13 +999,30 @@ static const struct { ...@@ -995,13 +999,30 @@ static const struct {
{ "off", sld_off }, { "off", sld_off },
{ "warn", sld_warn }, { "warn", sld_warn },
{ "fatal", sld_fatal }, { "fatal", sld_fatal },
{ "ratelimit:", sld_ratelimit },
}; };
static struct ratelimit_state bld_ratelimit;
static inline bool match_option(const char *arg, int arglen, const char *opt) static inline bool match_option(const char *arg, int arglen, const char *opt)
{ {
int len = strlen(opt); int len = strlen(opt), ratelimit;
if (strncmp(arg, opt, len))
return false;
return len == arglen && !strncmp(arg, opt, len); /*
* Min ratelimit is 1 bus lock/sec.
* Max ratelimit is 1000 bus locks/sec.
*/
if (sscanf(arg, "ratelimit:%d", &ratelimit) == 1 &&
ratelimit > 0 && ratelimit <= 1000) {
ratelimit_state_init(&bld_ratelimit, HZ, ratelimit);
ratelimit_set_flags(&bld_ratelimit, RATELIMIT_MSG_ON_RELEASE);
return true;
}
return len == arglen;
} }
static bool split_lock_verify_msr(bool on) static bool split_lock_verify_msr(bool on)
...@@ -1020,16 +1041,15 @@ static bool split_lock_verify_msr(bool on) ...@@ -1020,16 +1041,15 @@ static bool split_lock_verify_msr(bool on)
return ctrl == tmp; return ctrl == tmp;
} }
static void __init split_lock_setup(void) static void __init sld_state_setup(void)
{ {
enum split_lock_detect_state state = sld_warn; enum split_lock_detect_state state = sld_warn;
char arg[20]; char arg[20];
int i, ret; int i, ret;
if (!split_lock_verify_msr(false)) { if (!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) &&
pr_info("MSR access failed: Disabled\n"); !boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
return; return;
}
ret = cmdline_find_option(boot_command_line, "split_lock_detect", ret = cmdline_find_option(boot_command_line, "split_lock_detect",
arg, sizeof(arg)); arg, sizeof(arg));
...@@ -1041,17 +1061,14 @@ static void __init split_lock_setup(void) ...@@ -1041,17 +1061,14 @@ static void __init split_lock_setup(void)
} }
} }
} }
sld_state = state;
}
switch (state) { static void __init __split_lock_setup(void)
case sld_off: {
pr_info("disabled\n"); if (!split_lock_verify_msr(false)) {
pr_info("MSR access failed: Disabled\n");
return; return;
case sld_warn:
pr_info("warning about user-space split_locks\n");
break;
case sld_fatal:
pr_info("sending SIGBUS on user-space split_locks\n");
break;
} }
rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache); rdmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache);
...@@ -1061,7 +1078,9 @@ static void __init split_lock_setup(void) ...@@ -1061,7 +1078,9 @@ static void __init split_lock_setup(void)
return; return;
} }
sld_state = state; /* Restore the MSR to its cached value. */
wrmsrl(MSR_TEST_CTRL, msr_test_ctrl_cache);
setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT); setup_force_cpu_cap(X86_FEATURE_SPLIT_LOCK_DETECT);
} }
...@@ -1082,6 +1101,15 @@ static void sld_update_msr(bool on) ...@@ -1082,6 +1101,15 @@ static void sld_update_msr(bool on)
static void split_lock_init(void) static void split_lock_init(void)
{ {
/*
* #DB for bus lock handles ratelimit and #AC for split lock is
* disabled.
*/
if (sld_state == sld_ratelimit) {
split_lock_verify_msr(false);
return;
}
if (cpu_model_supports_sld) if (cpu_model_supports_sld)
split_lock_verify_msr(sld_state != sld_off); split_lock_verify_msr(sld_state != sld_off);
} }
...@@ -1118,6 +1146,29 @@ bool handle_guest_split_lock(unsigned long ip) ...@@ -1118,6 +1146,29 @@ bool handle_guest_split_lock(unsigned long ip)
} }
EXPORT_SYMBOL_GPL(handle_guest_split_lock); EXPORT_SYMBOL_GPL(handle_guest_split_lock);
static void bus_lock_init(void)
{
u64 val;
/*
* Warn and fatal are handled by #AC for split lock if #AC for
* split lock is supported.
*/
if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT) ||
(boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) &&
(sld_state == sld_warn || sld_state == sld_fatal)) ||
sld_state == sld_off)
return;
/*
* Enable #DB for bus lock. All bus locks are handled in #DB except
* split locks are handled in #AC in the fatal case.
*/
rdmsrl(MSR_IA32_DEBUGCTLMSR, val);
val |= DEBUGCTLMSR_BUS_LOCK_DETECT;
wrmsrl(MSR_IA32_DEBUGCTLMSR, val);
}
bool handle_user_split_lock(struct pt_regs *regs, long error_code) bool handle_user_split_lock(struct pt_regs *regs, long error_code)
{ {
if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal) if ((regs->flags & X86_EFLAGS_AC) || sld_state == sld_fatal)
...@@ -1126,6 +1177,27 @@ bool handle_user_split_lock(struct pt_regs *regs, long error_code) ...@@ -1126,6 +1177,27 @@ bool handle_user_split_lock(struct pt_regs *regs, long error_code)
return true; return true;
} }
void handle_bus_lock(struct pt_regs *regs)
{
switch (sld_state) {
case sld_off:
break;
case sld_ratelimit:
/* Enforce no more than bld_ratelimit bus locks/sec. */
while (!__ratelimit(&bld_ratelimit))
msleep(20);
/* Warn on the bus lock. */
fallthrough;
case sld_warn:
pr_warn_ratelimited("#DB: %s/%d took a bus_lock trap at address: 0x%lx\n",
current->comm, current->pid, regs->ip);
break;
case sld_fatal:
force_sig_fault(SIGBUS, BUS_ADRALN, NULL);
break;
}
}
/* /*
* This function is called only when switching between tasks with * This function is called only when switching between tasks with
* different split-lock detection modes. It sets the MSR for the * different split-lock detection modes. It sets the MSR for the
...@@ -1166,7 +1238,7 @@ static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = { ...@@ -1166,7 +1238,7 @@ static const struct x86_cpu_id split_lock_cpu_ids[] __initconst = {
{} {}
}; };
void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) static void __init split_lock_setup(struct cpuinfo_x86 *c)
{ {
const struct x86_cpu_id *m; const struct x86_cpu_id *m;
u64 ia32_core_caps; u64 ia32_core_caps;
...@@ -1193,5 +1265,44 @@ void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c) ...@@ -1193,5 +1265,44 @@ void __init cpu_set_core_cap_bits(struct cpuinfo_x86 *c)
} }
cpu_model_supports_sld = true; cpu_model_supports_sld = true;
split_lock_setup(); __split_lock_setup();
}
static void sld_state_show(void)
{
if (!boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT) &&
!boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
return;
switch (sld_state) {
case sld_off:
pr_info("disabled\n");
break;
case sld_warn:
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT))
pr_info("#AC: crashing the kernel on kernel split_locks and warning on user-space split_locks\n");
else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
pr_info("#DB: warning on user-space bus_locks\n");
break;
case sld_fatal:
if (boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT)) {
pr_info("#AC: crashing the kernel on kernel split_locks and sending SIGBUS on user-space split_locks\n");
} else if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT)) {
pr_info("#DB: sending SIGBUS on user-space bus_locks%s\n",
boot_cpu_has(X86_FEATURE_SPLIT_LOCK_DETECT) ?
" from non-WB" : "");
}
break;
case sld_ratelimit:
if (boot_cpu_has(X86_FEATURE_BUS_LOCK_DETECT))
pr_info("#DB: setting system wide bus lock rate limit to %u/sec\n", bld_ratelimit.burst);
break;
}
}
void __init sld_setup(struct cpuinfo_x86 *c)
{
split_lock_setup(c);
sld_state_setup();
sld_state_show();
} }
...@@ -1023,6 +1023,10 @@ static __always_inline void exc_debug_user(struct pt_regs *regs, ...@@ -1023,6 +1023,10 @@ static __always_inline void exc_debug_user(struct pt_regs *regs,
goto out_irq; goto out_irq;
} }
/* #DB for bus lock can only be triggered from userspace. */
if (dr6 & DR_BUS_LOCK)
handle_bus_lock(regs);
/* Add the virtual_dr6 bits for signals. */ /* Add the virtual_dr6 bits for signals. */
dr6 |= current->thread.virtual_dr6; dr6 |= current->thread.virtual_dr6;
if (dr6 & (DR_STEP | DR_TRAP_BITS) || icebp) if (dr6 & (DR_STEP | DR_TRAP_BITS) || icebp)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册