diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 5f72d048f58f47..f2a4136f6cd5b2 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig @@ -1367,6 +1367,12 @@ config BUILTIN_DTB_NAME DTS file path (without suffix, relative to arch/riscv/boot/dts) for the DTS file that will be used to produce the DTB linked into the kernel. + +config JUMP_LABEL_PATCH_LOG_SNAPSHOT + bool "Snapshot jump labels" + depends on JUMP_LABEL + help + Snapshot jump labels for debugging purposes. endmenu # "Boot options" diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c index 743d53415572e0..5a48306a8d6e83 100644 --- a/arch/riscv/kernel/cpufeature.c +++ b/arch/riscv/kernel/cpufeature.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -1221,6 +1222,14 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin, mutex_lock(&text_mutex); patch_text_nosync(oldptr, altptr, alt->alt_len); riscv_alternative_fix_offsets(oldptr, alt->alt_len, oldptr - altptr); + for (int i = 0; i < alt->alt_len; i += sizeof(u32)) { + u32 insn; + memcpy(&insn, oldptr + i, sizeof(insn)); + jl_snap_append(&(struct jl_entry){ + .addr = (u64)(oldptr + i), + .new_insn = insn, + }); + } mutex_unlock(&text_mutex); } } diff --git a/arch/riscv/kernel/jump_label.c b/arch/riscv/kernel/jump_label.c index b4c1a6a3fbd285..a6744a5b1fa39a 100644 --- a/arch/riscv/kernel/jump_label.c +++ b/arch/riscv/kernel/jump_label.c @@ -5,6 +5,7 @@ * Based on arch/arm64/kernel/jump_label.c */ #include +#include #include #include #include @@ -39,11 +40,13 @@ bool arch_jump_label_transform_queue(struct jump_entry *entry, if (early_boot_irqs_disabled) { riscv_patch_in_stop_machine = 1; patch_insn_write(addr, &insn, sizeof(insn)); + jl_snap_append(&(struct jl_entry){.addr = (u64)addr, .new_insn = insn}); riscv_patch_in_stop_machine = 0; } else { mutex_lock(&text_mutex); patch_insn_write(addr, &insn, sizeof(insn)); mutex_unlock(&text_mutex); + jl_snap_append(&(struct jl_entry){.addr = (u64)addr, .new_insn = insn}); } return true; diff --git a/include/linux/jump_label_patch_log.h b/include/linux/jump_label_patch_log.h new file mode 100644 index 00000000000000..9711e2c4a35e41 --- /dev/null +++ b/include/linux/jump_label_patch_log.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _LINUX_JUMP_LABEL_PATCH_LOG_H +#define _LINUX_JUMP_LABEL_PATCH_LOG_H + +#include +#include + +struct jl_entry { + u64 addr; // site address + u32 new_insn; +}; + +#ifdef CONFIG_JUMP_LABEL_PATCH_LOG_SNAPSHOT +void jl_snap_append(const struct jl_entry *e); +void jl_snap_publish_debugfs(void); // call later (late init) +#else +static inline void jl_snap_append(const struct jl_entry *e) { } +static inline void jl_snap_publish_debugfs(void) { } +#endif + +#endif \ No newline at end of file diff --git a/kernel/Makefile b/kernel/Makefile index 32e80dd626af07..e0c3b91c4408b4 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_PERF_EVENTS) += events/ obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o obj-$(CONFIG_PADATA) += padata.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +obj-$(CONFIG_JUMP_LABEL_PATCH_LOG_SNAPSHOT) += jump_label_patch_log.o obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o obj-$(CONFIG_TORTURE_TEST) += torture.o diff --git a/kernel/jump_label.c b/kernel/jump_label.c index 7cb19e6014266a..5ab87e268fcb65 100644 --- a/kernel/jump_label.c +++ b/kernel/jump_label.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include diff --git a/kernel/jump_label_patch_log.c b/kernel/jump_label_patch_log.c new file mode 100644 index 00000000000000..ffa9c7479398c7 --- /dev/null +++ b/kernel/jump_label_patch_log.c @@ -0,0 +1,63 @@ +#include +#include + +#define JL_MAX 8192 // tune or make it cmdline-configurable +static struct jl_entry jl_buf[JL_MAX]; +static atomic_t jl_widx = ATOMIC_INIT(0); + +#ifdef CONFIG_JUMP_LABEL_PATCH_LOG_SNAPSHOT +void jl_snap_append(const struct jl_entry *e) +{ + int i = atomic_fetch_add_unless(&jl_widx, 1, JL_MAX); + if (i >= JL_MAX) return; // drop if full + jl_buf[i] = *e; +} +#endif + +#ifdef CONFIG_DEBUG_FS +#include +#include + +static int jl_dbg_show(struct seq_file *m, void *v) +{ + int i, n = min(atomic_read(&jl_widx), JL_MAX); + for (i = 0; i < n; i++) { + const struct jl_entry *e = &jl_buf[i]; + seq_printf(m, "%llx,%08x\n", + (unsigned long long)e->addr, + e->new_insn); + } + return 0; +} +static int jl_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, jl_dbg_show, NULL); +} +static const struct file_operations jl_dbg_fops = { + .owner = THIS_MODULE, + .open = jl_dbg_open, + .read = seq_read, + .llseek= seq_lseek, + .release= single_release, +}; + +#ifdef CONFIG_JUMP_LABEL_PATCH_LOG_SNAPSHOT +static struct dentry *jl_dent; +void jl_snap_publish_debugfs(void) +{ + if (!jl_dent) + jl_dent = debugfs_create_file("jump_label_snapshot", 0444, + NULL, NULL, &jl_dbg_fops); +} + +static int __init jl_snap_publish_debugfs_init(void) +{ + jl_snap_publish_debugfs(); + return 0; +} +late_initcall(jl_snap_publish_debugfs_init); + +#endif // CONFIG_JUMP_LABEL_PATCH_LOG_SNAPSHOT +#else // CONFIG_DEBUG_FS +void jl_snap_publish_debugfs(void) { } +#endif // CONFIG_DEBUG_FS \ No newline at end of file diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 81c6df746df17b..566fd4582a654f 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -117,6 +117,10 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(sched_util_est_se_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_update_nr_running_tp); EXPORT_TRACEPOINT_SYMBOL_GPL(sched_compute_energy_tp); +EXPORT_SYMBOL(__tracepoint_sched_process_exec); +EXPORT_SYMBOL(__tracepoint_sched_process_fork); +EXPORT_SYMBOL(__tracepoint_sched_switch); + DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); /*