Commit 477d81a1 authored by Dmitry Vyukov's avatar Dmitry Vyukov Committed by Thomas Gleixner

x86/entry: Remove unwanted instrumentation in common_interrupt()

common_interrupt() and related variants call kvm_set_cpu_l1tf_flush_l1d(),
which is neither marked noinstr nor __always_inline.

So compiler puts it out of line and adds instrumentation to it.  Since the
call is inside of instrumentation_begin/end(), objtool does not warn about
it.

The manifestation is that KCOV produces spurious coverage in
kvm_set_cpu_l1tf_flush_l1d() in random places because the call happens when
preempt count is not yet updated to say that the kernel is in an interrupt.

Mark kvm_set_cpu_l1tf_flush_l1d() as __always_inline and move it out of the
instrumentation_begin/end() section.  It only calls __this_cpu_write()
which is already safe to call in noinstr contexts.

Fixes: 6368558c ("x86/entry: Provide IDTENTRY_SYSVEC")
Signed-off-by: default avatarDmitry Vyukov <dvyukov@google.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarAlexander Potapenko <glider@google.com>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/all/3f9a1de9e415fcb53d07dc9e19fa8481bb021b1b.1718092070.git.dvyukov@google.com
parent de9c2c66
...@@ -69,7 +69,11 @@ extern u64 arch_irq_stat(void); ...@@ -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) ...@@ -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, \ ...@@ -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); \ ...@@ -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) \ ...@@ -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); \ ...@@ -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) \ ...@@ -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(); \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment