[RFC Patch 7/7] kexec: Add /proc/multikernel interface for kimage tracking

Cong Wang
2025-09-18T22:26:33Z

From: Cong Wang <cwang@multikernel.io>

Add a dedicated /proc/multikernel file to provide read-only access to
all loaded kernel images in the system.

The interface displays kernel images in a tabular format showing:
- Type: kexec type (default, crash, multikernel)
- Start Address: entry point in hexadecimal format
- Segments: number of memory segments

A lot more information needs to be added here, for example a unique kernel
ID allocated for each kimage. For now, let's focus on the design first.

This interface is particularly useful for debugging multikernel setups,
system monitoring, and verifying that kernel images are loaded correctly.

Signed-off-by: Cong Wang <cwang@multikernel.io>
---
kernel/kexec_core.c | 63 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 63 insertions(+)

diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index 4e489a7031e6..8306c10fc337 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -13,6 +13,8 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/kexec.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/highmem.h>
@@ -1224,6 +1226,52 @@ struct kimage *kexec_image;
struct kimage *kexec_crash_image;
static int kexec_load_disabled;

+/*
+ * Proc interface for /proc/multikernel
+ */
+static int multikernel_proc_show(struct seq_file *m, void *v)
+{
+ struct kimage *image;
+ const char *type_names[] = {
+ [KEXEC_TYPE_DEFAULT] = "default",
+ [KEXEC_TYPE_CRASH] = "crash",
+ [KEXEC_TYPE_MULTIKERNEL] = "multikernel"
+ };
+
+ seq_printf(m, "Type Start Address Segments\n");
+ seq_printf(m, "---------- -------------- --------\n");
+
+ kimage_list_lock();
+ if (list_empty(&kexec_image_list)) {
+ seq_printf(m, "No kimages loaded\n");
+ } else {
+ list_for_each_entry(image, &kexec_image_list, list) {
+ const char *type_name = "unknown";
+
+ if (image->type < ARRAY_SIZE(type_names) && type_names[image->type])
+ type_name = type_names[image->type];
+
+ seq_printf(m, "%-10s 0x%012lx %8lu\n",
+ type_name, image->start, image->nr_segments);
+ }
+ }
+ kimage_list_unlock();
+
+ return 0;
+}
+
+static int multikernel_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, multikernel_proc_show, NULL);
+}
+
+static const struct proc_ops multikernel_proc_ops = {
+ .proc_open = multikernel_proc_open,
+ .proc_read = seq_read,
+ .proc_lseek = seq_lseek,
+ .proc_release = single_release,
+};
+
#ifdef CONFIG_SYSCTL
static int kexec_limit_handler(const struct ctl_table *table, int write,
void *buffer, size_t *lenp, loff_t *ppos)
@@ -1295,6 +1343,21 @@ static int __init kexec_core_sysctl_init(void)
late_initcall(kexec_core_sysctl_init);
#endif

+static int __init multikernel_proc_init(void)
+{
+ struct proc_dir_entry *entry;
+
+ entry = proc_create("multikernel", 0444, NULL, &multikernel_proc_ops);
+ if (!entry) {
+ pr_err("Failed to create /proc/multikernel\n");
+ return -ENOMEM;
+ }
+
+ pr_debug("Created /proc/multikernel interface\n");
+ return 0;
+}
+late_initcall(multikernel_proc_init);
+
bool kexec_load_permitted(int kexec_image_type)
{
struct kexec_load_limit *limit;
--
2.34.1