Skip to content

Commit 5ba202a

Browse files
committed
Merge tag 'x86-build-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 build updates from Thomas Gleixner: "Updates for KCOV instrumentation on x86: - Prevent spurious KCOV coverage in common_interrupt() - Fixup the KCOV Makefile directive which got stale due to a source file rename - Exclude stack unwinding from KCOV as it creates large amounts of uninteresting coverage - Provide a self test to validate that KCOV coverage of the interrupt handling code starts not before preempt count got updated" * tag 'x86-build-2024-09-17' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86: Ignore stack unwinding in KCOV module: Fix KCOV-ignored file name kcov: Add interrupt handling self test x86/entry: Remove unwanted instrumentation in common_interrupt()
2 parents a940d9a + ae94b26 commit 5ba202a

File tree

6 files changed

+57
-6
lines changed

6 files changed

+57
-6
lines changed

arch/x86/include/asm/hardirq.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,11 @@ extern u64 arch_irq_stat(void);
6969
#define local_softirq_pending_ref pcpu_hot.softirq_pending
7070

7171
#if IS_ENABLED(CONFIG_KVM_INTEL)
72-
static inline void kvm_set_cpu_l1tf_flush_l1d(void)
72+
/*
73+
* This function is called from noinstr interrupt contexts
74+
* and must be inlined to not get instrumentation.
75+
*/
76+
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
7377
{
7478
__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
7579
}
@@ -84,7 +88,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
8488
return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
8589
}
8690
#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
87-
static inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
91+
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
8892
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
8993

9094
#endif /* _ASM_X86_HARDIRQ_H */

arch/x86/include/asm/idtentry.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \
212212
irqentry_state_t state = irqentry_enter(regs); \
213213
u32 vector = (u32)(u8)error_code; \
214214
\
215+
kvm_set_cpu_l1tf_flush_l1d(); \
215216
instrumentation_begin(); \
216-
kvm_set_cpu_l1tf_flush_l1d(); \
217217
run_irq_on_irqstack_cond(__##func, regs, vector); \
218218
instrumentation_end(); \
219219
irqentry_exit(regs, state); \
@@ -250,14 +250,14 @@ static void __##func(struct pt_regs *regs); \
250250
\
251251
static __always_inline void instr_##func(struct pt_regs *regs) \
252252
{ \
253-
kvm_set_cpu_l1tf_flush_l1d(); \
254253
run_sysvec_on_irqstack_cond(__##func, regs); \
255254
} \
256255
\
257256
__visible noinstr void func(struct pt_regs *regs) \
258257
{ \
259258
irqentry_state_t state = irqentry_enter(regs); \
260259
\
260+
kvm_set_cpu_l1tf_flush_l1d(); \
261261
instrumentation_begin(); \
262262
instr_##func (regs); \
263263
instrumentation_end(); \
@@ -288,7 +288,6 @@ static __always_inline void __##func(struct pt_regs *regs); \
288288
static __always_inline void instr_##func(struct pt_regs *regs) \
289289
{ \
290290
__irq_enter_raw(); \
291-
kvm_set_cpu_l1tf_flush_l1d(); \
292291
__##func (regs); \
293292
__irq_exit_raw(); \
294293
} \
@@ -297,6 +296,7 @@ __visible noinstr void func(struct pt_regs *regs) \
297296
{ \
298297
irqentry_state_t state = irqentry_enter(regs); \
299298
\
299+
kvm_set_cpu_l1tf_flush_l1d(); \
300300
instrumentation_begin(); \
301301
instr_##func (regs); \
302302
instrumentation_end(); \

arch/x86/kernel/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,14 @@ KMSAN_SANITIZE_nmi.o := n
3535
# If instrumentation of the following files is enabled, boot hangs during
3636
# first second.
3737
KCOV_INSTRUMENT_head$(BITS).o := n
38+
# These are called from save_stack_trace() on debug paths,
39+
# and produce large amounts of uninteresting coverage.
40+
KCOV_INSTRUMENT_stacktrace.o := n
41+
KCOV_INSTRUMENT_dumpstack.o := n
42+
KCOV_INSTRUMENT_dumpstack_$(BITS).o := n
43+
KCOV_INSTRUMENT_unwind_orc.o := n
44+
KCOV_INSTRUMENT_unwind_frame.o := n
45+
KCOV_INSTRUMENT_unwind_guess.o := n
3846

3947
CFLAGS_irq.o := -I $(src)/../include/asm/trace
4048

kernel/kcov.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/fs.h>
1212
#include <linux/hashtable.h>
1313
#include <linux/init.h>
14+
#include <linux/jiffies.h>
1415
#include <linux/kmsan-checks.h>
1516
#include <linux/mm.h>
1617
#include <linux/preempt.h>
@@ -1067,6 +1068,32 @@ u64 kcov_common_handle(void)
10671068
}
10681069
EXPORT_SYMBOL(kcov_common_handle);
10691070

1071+
#ifdef CONFIG_KCOV_SELFTEST
1072+
static void __init selftest(void)
1073+
{
1074+
unsigned long start;
1075+
1076+
pr_err("running self test\n");
1077+
/*
1078+
* Test that interrupts don't produce spurious coverage.
1079+
* The coverage callback filters out interrupt code, but only
1080+
* after the handler updates preempt count. Some code periodically
1081+
* leaks out of that section and leads to spurious coverage.
1082+
* It's hard to call the actual interrupt handler directly,
1083+
* so we just loop here for a bit waiting for a timer interrupt.
1084+
* We set kcov_mode to enable tracing, but don't setup the area,
1085+
* so any attempt to trace will crash. Note: we must not call any
1086+
* potentially traced functions in this region.
1087+
*/
1088+
start = jiffies;
1089+
current->kcov_mode = KCOV_MODE_TRACE_PC;
1090+
while ((jiffies - start) * MSEC_PER_SEC / HZ < 300)
1091+
;
1092+
current->kcov_mode = 0;
1093+
pr_err("done running self test\n");
1094+
}
1095+
#endif
1096+
10701097
static int __init kcov_init(void)
10711098
{
10721099
int cpu;
@@ -1086,6 +1113,10 @@ static int __init kcov_init(void)
10861113
*/
10871114
debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
10881115

1116+
#ifdef CONFIG_KCOV_SELFTEST
1117+
selftest();
1118+
#endif
1119+
10891120
return 0;
10901121
}
10911122

kernel/module/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
# These are called from save_stack_trace() on slub debug path,
77
# and produce insane amounts of uninteresting coverage.
8-
KCOV_INSTRUMENT_module.o := n
8+
KCOV_INSTRUMENT_main.o := n
99

1010
obj-y += main.o
1111
obj-y += strict_rwx.o

lib/Kconfig.debug

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2173,6 +2173,14 @@ config KCOV_IRQ_AREA_SIZE
21732173
soft interrupts. This specifies the size of those areas in the
21742174
number of unsigned long words.
21752175

2176+
config KCOV_SELFTEST
2177+
bool "Perform short selftests on boot"
2178+
depends on KCOV
2179+
help
2180+
Run short KCOV coverage collection selftests on boot.
2181+
On test failure, causes the kernel to panic. Recommended to be
2182+
enabled, ensuring critical functionality works as intended.
2183+
21762184
menuconfig RUNTIME_TESTING_MENU
21772185
bool "Runtime Testing"
21782186
default y

0 commit comments

Comments
 (0)