--- /dev/null
+/* SPDX-License-Identifier: (GPL-2.0-only)
+ *
+ * wrapper/ibt.h
+ *
+ * Copyright (C) 2024 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ */
+
+#ifndef _LTTNG_WRAPPER_IBT_H
+#define _LTTNG_WRAPPER_IBT_H
+
+struct irq_ibt_state {
+ u64 msr;
+ unsigned long flags;
+};
+
+/*
+ * Save (disable) and restore interrupts around MSR bit change and indirect
+ * function call to make sure this thread is not migrated to another CPU which
+ * would not have the MSR bit cleared.
+ */
+
+#ifdef CONFIG_X86_KERNEL_IBT
+# include <asm/cpufeature.h>
+# include <asm/msr.h>
+static inline __attribute__((always_inline))
+struct irq_ibt_state wrapper_irq_ibt_save(void)
+{
+ struct irq_ibt_state state = { 0, 0 };
+ u64 msr;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ goto end;
+ local_irq_save(state.flags);
+ rdmsrl(MSR_IA32_S_CET, msr);
+ wrmsrl(MSR_IA32_S_CET, msr & ~CET_ENDBR_EN);
+ state.msr = msr;
+end:
+ return state;
+}
+
+static inline __attribute__((always_inline))
+void wrapper_irq_ibt_restore(struct irq_ibt_state state)
+{
+ u64 msr;
+
+ if (!cpu_feature_enabled(X86_FEATURE_IBT))
+ return;
+ rdmsrl(MSR_IA32_S_CET, msr);
+ msr &= ~CET_ENDBR_EN;
+ msr |= (state.msr & CET_ENDBR_EN);
+ wrmsrl(MSR_IA32_S_CET, msr);
+ local_irq_restore(state.flags);
+}
+#else
+static inline struct irq_ibt_state wrapper_irq_ibt_save(void) { struct irq_ibt_state state = { 0, 0 }; return state; }
+static inline void wrapper_irq_ibt_restore(struct irq_ibt_state state) { }
+#endif
+
+#endif /* _LTTNG_WRAPPER_IBT_H */
#include <linux/kallsyms.h>
#include <lttng/kernel-version.h>
+#include <wrapper/ibt.h>
+
/* CONFIG_PPC64_ELF_ABI_V1/V2 were introduced in v5.19 */
#if defined(CONFIG_PPC64_ELF_ABI_V2) || (defined(CONFIG_PPC64) && defined(CONFIG_CPU_LITTLE_ENDIAN))
#define LTTNG_CONFIG_PPC64_ELF_ABI_V2
struct field_data *fdata = (struct field_data *) priv;
size_t orig_offset = offset;
int cpu = smp_processor_id();
+ struct irq_ibt_state irq_ibt_state;
/* do not write data if no space is available */
trace = stack_trace_context(fdata, cpu);
++per_cpu(callstack_user_nesting, cpu);
/* do the real work and reserve space */
+ irq_ibt_state = wrapper_irq_ibt_save();
cs_types[fdata->mode].save_func(trace);
+ wrapper_irq_ibt_restore(irq_ibt_state);
if (fdata->mode == CALLSTACK_USER)
per_cpu(callstack_user_nesting, cpu)--;
struct field_data *fdata = (struct field_data *) priv;
size_t orig_offset = offset;
int cpu = smp_processor_id();
+ struct irq_ibt_state irq_ibt_state;
/* do not write data if no space is available */
trace = stack_trace_context(fdata, cpu);
switch (fdata->mode) {
case CALLSTACK_KERNEL:
/* do the real work and reserve space */
+ irq_ibt_state = wrapper_irq_ibt_save();
trace->nr_entries = save_func_kernel(trace->entries,
MAX_ENTRIES, 0);
+ wrapper_irq_ibt_restore(irq_ibt_state);
break;
case CALLSTACK_USER:
++per_cpu(callstack_user_nesting, cpu);
/* do the real work and reserve space */
+ irq_ibt_state = wrapper_irq_ibt_save();
trace->nr_entries = save_func_user(trace->entries,
MAX_ENTRIES);
+ wrapper_irq_ibt_restore(irq_ibt_state);
per_cpu(callstack_user_nesting, cpu)--;
break;
default:
if (!irq_to_desc_sym)
irq_to_desc_sym = (void *) kallsyms_lookup_funcptr("irq_to_desc");
if (irq_to_desc_sym) {
- return irq_to_desc_sym(irq);
+ struct irq_ibt_state irq_ibt_state;
+ struct irq_desc *ret;
+
+ irq_ibt_state = wrapper_irq_ibt_save();
+ ret = irq_to_desc_sym(irq);
+ wrapper_irq_ibt_restore(irq_ibt_state);
+ return ret;
} else {
printk_once(KERN_WARNING "LTTng: irq_to_desc symbol lookup failed.\n");
return NULL;
if (!kallsyms_lookup_name_sym) {
kallsyms_lookup_name_sym = (void *)do_get_kallsyms();
}
- if (kallsyms_lookup_name_sym)
- return kallsyms_lookup_name_sym(name);
- else {
+ if (kallsyms_lookup_name_sym) {
+ struct irq_ibt_state irq_ibt_state;
+ unsigned long ret;
+
+ irq_ibt_state = wrapper_irq_ibt_save();
+ ret = kallsyms_lookup_name_sym(name);
+ wrapper_irq_ibt_restore(irq_ibt_state);
+ return ret;
+ } else {
printk_once(KERN_WARNING "LTTng: requires kallsyms_lookup_name\n");
return 0;
}
{
WARN_ON_ONCE(!get_pfnblock_flags_mask_sym);
if (get_pfnblock_flags_mask_sym) {
- return get_pfnblock_flags_mask_sym(page, pfn, end_bitidx, mask);
+ struct irq_ibt_state irq_ibt_state;
+ unsigned long ret;
+
+ irq_ibt_state = wrapper_irq_ibt_save();
+ ret = get_pfnblock_flags_mask_sym(page, pfn, end_bitidx, mask);
+ wrapper_irq_ibt_restore(irq_ibt_state);
+ return ret;
} else {
return -ENOSYS;
}