mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 13:03:25 +01:00
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. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAmbpMeITHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYoaOeD/4oO3g0soK0LIcDIwzaG0ap0hx0nucw aVSAESuY+ZaSbRbV0fNoYdHORvLdErs67SeyeJRSxTzSNqGH2dGoFrfbkRSXq951 RdCSPP60T7xgqAme1YLDiChfXt/gkbWk/8V5Q7sG3oq3GaVcPUyZgPo4M4HQMdfg Mla3VPikW5Np3fvs0IZYWQ5VdY0fFOHY5JGMhKJznJxf+Ud+VAtxsbJUcO4MEYWW A9CVJNHGEXssGA6vm5kgtLu6n2QFuoSj6En/WqLEaJb8f/V332e04Xj2ZHUaOOjV 2abVeDovv+dwUYb4SgrGVg9gfEwwcLPDnmOuuQJmQBB5kU4mJsCqI5TTS6c1fgU4 x8tQsGSOKHFQAI14ZWtitrL4rS2uFcBkAFXo0dF8J5o4989RA8cpfeWVSVUb/UXd u38BWpc9iHiihHKMmMQgsa1bUMwdSUTvN5XFHkeP4oqUdMiEiWn8iM5+zXd/lfTs 9mrTv+kcLA7mjFOmn4JyE2b+NuiPdgS2FCBGLycHvGwvJoJlO2UmSpF89AJ5vdKs F8vWLkV+gno/HtwS5o949cAwjYiCodfc7u1W0xj2VDAbx0RbaBw1SDhXMQcLxLgn BTt4yHKKIeLX++WH3fpeyL91+UJWubUzNzY4rAmLkz5DedWAkpES+45fatp1buIz Lp/hGiIsG9p5xw== =tiXT -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
5ba202a7c9
6 changed files with 57 additions and 6 deletions
|
@ -69,7 +69,11 @@ extern u64 arch_irq_stat(void);
|
||||||
#define local_softirq_pending_ref pcpu_hot.softirq_pending
|
#define local_softirq_pending_ref pcpu_hot.softirq_pending
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
#if IS_ENABLED(CONFIG_KVM_INTEL)
|
||||||
static inline void kvm_set_cpu_l1tf_flush_l1d(void)
|
/*
|
||||||
|
* This function is called from noinstr interrupt contexts
|
||||||
|
* and must be inlined to not get instrumentation.
|
||||||
|
*/
|
||||||
|
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void)
|
||||||
{
|
{
|
||||||
__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
|
__this_cpu_write(irq_stat.kvm_cpu_l1tf_flush_l1d, 1);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +88,7 @@ static __always_inline bool kvm_get_cpu_l1tf_flush_l1d(void)
|
||||||
return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
|
return __this_cpu_read(irq_stat.kvm_cpu_l1tf_flush_l1d);
|
||||||
}
|
}
|
||||||
#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
|
#else /* !IS_ENABLED(CONFIG_KVM_INTEL) */
|
||||||
static inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
|
static __always_inline void kvm_set_cpu_l1tf_flush_l1d(void) { }
|
||||||
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
|
#endif /* IS_ENABLED(CONFIG_KVM_INTEL) */
|
||||||
|
|
||||||
#endif /* _ASM_X86_HARDIRQ_H */
|
#endif /* _ASM_X86_HARDIRQ_H */
|
||||||
|
|
|
@ -212,8 +212,8 @@ __visible noinstr void func(struct pt_regs *regs, \
|
||||||
irqentry_state_t state = irqentry_enter(regs); \
|
irqentry_state_t state = irqentry_enter(regs); \
|
||||||
u32 vector = (u32)(u8)error_code; \
|
u32 vector = (u32)(u8)error_code; \
|
||||||
\
|
\
|
||||||
|
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
|
||||||
run_irq_on_irqstack_cond(__##func, regs, vector); \
|
run_irq_on_irqstack_cond(__##func, regs, vector); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
irqentry_exit(regs, state); \
|
irqentry_exit(regs, state); \
|
||||||
|
@ -250,7 +250,6 @@ static void __##func(struct pt_regs *regs); \
|
||||||
\
|
\
|
||||||
static __always_inline void instr_##func(struct pt_regs *regs) \
|
static __always_inline void instr_##func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
|
||||||
run_sysvec_on_irqstack_cond(__##func, regs); \
|
run_sysvec_on_irqstack_cond(__##func, regs); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
@ -258,6 +257,7 @@ __visible noinstr void func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
irqentry_state_t state = irqentry_enter(regs); \
|
irqentry_state_t state = irqentry_enter(regs); \
|
||||||
\
|
\
|
||||||
|
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
instr_##func (regs); \
|
instr_##func (regs); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
|
@ -288,7 +288,6 @@ static __always_inline void __##func(struct pt_regs *regs); \
|
||||||
static __always_inline void instr_##func(struct pt_regs *regs) \
|
static __always_inline void instr_##func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
__irq_enter_raw(); \
|
__irq_enter_raw(); \
|
||||||
kvm_set_cpu_l1tf_flush_l1d(); \
|
|
||||||
__##func (regs); \
|
__##func (regs); \
|
||||||
__irq_exit_raw(); \
|
__irq_exit_raw(); \
|
||||||
} \
|
} \
|
||||||
|
@ -297,6 +296,7 @@ __visible noinstr void func(struct pt_regs *regs) \
|
||||||
{ \
|
{ \
|
||||||
irqentry_state_t state = irqentry_enter(regs); \
|
irqentry_state_t state = irqentry_enter(regs); \
|
||||||
\
|
\
|
||||||
|
kvm_set_cpu_l1tf_flush_l1d(); \
|
||||||
instrumentation_begin(); \
|
instrumentation_begin(); \
|
||||||
instr_##func (regs); \
|
instr_##func (regs); \
|
||||||
instrumentation_end(); \
|
instrumentation_end(); \
|
||||||
|
|
|
@ -35,6 +35,14 @@ KMSAN_SANITIZE_nmi.o := n
|
||||||
# If instrumentation of the following files is enabled, boot hangs during
|
# If instrumentation of the following files is enabled, boot hangs during
|
||||||
# first second.
|
# first second.
|
||||||
KCOV_INSTRUMENT_head$(BITS).o := n
|
KCOV_INSTRUMENT_head$(BITS).o := n
|
||||||
|
# These are called from save_stack_trace() on debug paths,
|
||||||
|
# and produce large amounts of uninteresting coverage.
|
||||||
|
KCOV_INSTRUMENT_stacktrace.o := n
|
||||||
|
KCOV_INSTRUMENT_dumpstack.o := n
|
||||||
|
KCOV_INSTRUMENT_dumpstack_$(BITS).o := n
|
||||||
|
KCOV_INSTRUMENT_unwind_orc.o := n
|
||||||
|
KCOV_INSTRUMENT_unwind_frame.o := n
|
||||||
|
KCOV_INSTRUMENT_unwind_guess.o := n
|
||||||
|
|
||||||
CFLAGS_irq.o := -I $(src)/../include/asm/trace
|
CFLAGS_irq.o := -I $(src)/../include/asm/trace
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <linux/hashtable.h>
|
#include <linux/hashtable.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/jiffies.h>
|
||||||
#include <linux/kmsan-checks.h>
|
#include <linux/kmsan-checks.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/preempt.h>
|
#include <linux/preempt.h>
|
||||||
|
@ -1067,6 +1068,32 @@ u64 kcov_common_handle(void)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(kcov_common_handle);
|
EXPORT_SYMBOL(kcov_common_handle);
|
||||||
|
|
||||||
|
#ifdef CONFIG_KCOV_SELFTEST
|
||||||
|
static void __init selftest(void)
|
||||||
|
{
|
||||||
|
unsigned long start;
|
||||||
|
|
||||||
|
pr_err("running self test\n");
|
||||||
|
/*
|
||||||
|
* Test that interrupts don't produce spurious coverage.
|
||||||
|
* The coverage callback filters out interrupt code, but only
|
||||||
|
* after the handler updates preempt count. Some code periodically
|
||||||
|
* leaks out of that section and leads to spurious coverage.
|
||||||
|
* It's hard to call the actual interrupt handler directly,
|
||||||
|
* so we just loop here for a bit waiting for a timer interrupt.
|
||||||
|
* We set kcov_mode to enable tracing, but don't setup the area,
|
||||||
|
* so any attempt to trace will crash. Note: we must not call any
|
||||||
|
* potentially traced functions in this region.
|
||||||
|
*/
|
||||||
|
start = jiffies;
|
||||||
|
current->kcov_mode = KCOV_MODE_TRACE_PC;
|
||||||
|
while ((jiffies - start) * MSEC_PER_SEC / HZ < 300)
|
||||||
|
;
|
||||||
|
current->kcov_mode = 0;
|
||||||
|
pr_err("done running self test\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int __init kcov_init(void)
|
static int __init kcov_init(void)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
@ -1086,6 +1113,10 @@ static int __init kcov_init(void)
|
||||||
*/
|
*/
|
||||||
debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
|
debugfs_create_file_unsafe("kcov", 0600, NULL, NULL, &kcov_fops);
|
||||||
|
|
||||||
|
#ifdef CONFIG_KCOV_SELFTEST
|
||||||
|
selftest();
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
# These are called from save_stack_trace() on slub debug path,
|
# These are called from save_stack_trace() on slub debug path,
|
||||||
# and produce insane amounts of uninteresting coverage.
|
# and produce insane amounts of uninteresting coverage.
|
||||||
KCOV_INSTRUMENT_module.o := n
|
KCOV_INSTRUMENT_main.o := n
|
||||||
|
|
||||||
obj-y += main.o
|
obj-y += main.o
|
||||||
obj-y += strict_rwx.o
|
obj-y += strict_rwx.o
|
||||||
|
|
|
@ -2173,6 +2173,14 @@ config KCOV_IRQ_AREA_SIZE
|
||||||
soft interrupts. This specifies the size of those areas in the
|
soft interrupts. This specifies the size of those areas in the
|
||||||
number of unsigned long words.
|
number of unsigned long words.
|
||||||
|
|
||||||
|
config KCOV_SELFTEST
|
||||||
|
bool "Perform short selftests on boot"
|
||||||
|
depends on KCOV
|
||||||
|
help
|
||||||
|
Run short KCOV coverage collection selftests on boot.
|
||||||
|
On test failure, causes the kernel to panic. Recommended to be
|
||||||
|
enabled, ensuring critical functionality works as intended.
|
||||||
|
|
||||||
menuconfig RUNTIME_TESTING_MENU
|
menuconfig RUNTIME_TESTING_MENU
|
||||||
bool "Runtime Testing"
|
bool "Runtime Testing"
|
||||||
default y
|
default y
|
||||||
|
|
Loading…
Reference in a new issue