From: Eugen Hristev <eugen.hristev@linaro.org>
To: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-mm@kvack.org, tglx@linutronix.de, andersson@kernel.org,
pmladek@suse.com, rdunlap@infradead.org, corbet@lwn.net,
david@redhat.com, mhocko@suse.com
Cc: tudor.ambarus@linaro.org, mukesh.ojha@oss.qualcomm.com,
linux-arm-kernel@lists.infradead.org,
linux-hardening@vger.kernel.org, jonechou@google.com,
rostedt@goodmis.org, linux-doc@vger.kernel.org,
devicetree@vger.kernel.org,
Eugen Hristev <eugen.hristev@linaro.org>
Subject: [RFC][PATCH v3 15/16] kmemdump: Add Kinfo backend driver
Date: Fri, 12 Sep 2025 18:08:54 +0300 [thread overview]
Message-ID: <20250912150855.2901211-16-eugen.hristev@linaro.org> (raw)
In-Reply-To: <20250912150855.2901211-1-eugen.hristev@linaro.org>
Add Kinfo backend driver.
This backend driver will select only regions of interest for the firmware,
and it copy those into a shared memory area that is supplied via OF.
The firmware is only interested in addresses for some symbols.
The list format is kinfo-compatible, with devices like Google Pixel phone.
Signed-off-by: Eugen Hristev <eugen.hristev@linaro.org>
---
MAINTAINERS | 5 +
mm/kmemdump/Kconfig.debug | 13 ++
mm/kmemdump/Makefile | 1 +
mm/kmemdump/kinfo.c | 293 ++++++++++++++++++++++++++++++++++++++
4 files changed, 312 insertions(+)
create mode 100644 mm/kmemdump/kinfo.c
diff --git a/MAINTAINERS b/MAINTAINERS
index 8234acb24cbc..65d9e5db46a9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13818,6 +13818,11 @@ F: include/linux/kmemdump.h
F: mm/kmemdump/kmemdump.c
F: mm/kmemdump/kmemdump_coreimage.c
+KMEMDUMP KINFO BACKEND DRIVER
+M: Eugen Hristev <eugen.hristev@linaro.org>
+S: Maintained
+F: mm/kmemdump/kinfo.c
+
KMEMDUMP QCOM MINIDUMP BACKEND DRIVER
M: Eugen Hristev <eugen.hristev@linaro.org>
S: Maintained
diff --git a/mm/kmemdump/Kconfig.debug b/mm/kmemdump/Kconfig.debug
index 91cec45bc3ca..ff88bf8017ae 100644
--- a/mm/kmemdump/Kconfig.debug
+++ b/mm/kmemdump/Kconfig.debug
@@ -38,3 +38,16 @@ config KMEMDUMP_QCOM_MINIDUMP_BACKEND
into the minidump table of contents. Further on, the firmware
will be able to read the table of contents and extract the
memory regions on case-by-case basis.
+
+config KMEMDUMP_KINFO_BACKEND
+ tristate "Shared memory KInfo compatible backend"
+ depends on KMEMDUMP
+ select VMCORE_INFO
+ help
+ Say y here to enable the Shared memory KInfo compatible backend
+ driver.
+ With this backend, the registered regions are copied to a shared
+ memory zone at register time.
+ The shared memory zone is supplied via OF.
+ This backend will select only regions that are of interest,
+ and keep only addresses. The format of the list is Kinfo compatible.
diff --git a/mm/kmemdump/Makefile b/mm/kmemdump/Makefile
index 6ec3871203ef..1ec94ee6c008 100644
--- a/mm/kmemdump/Makefile
+++ b/mm/kmemdump/Makefile
@@ -3,3 +3,4 @@
obj-y += kmemdump.o
obj-$(CONFIG_KMEMDUMP_COREIMAGE) += kmemdump_coreimage.o
obj-$(CONFIG_KMEMDUMP_QCOM_MINIDUMP_BACKEND) += qcom_minidump.o
+obj-$(CONFIG_KMEMDUMP_KINFO_BACKEND) += kinfo.o
diff --git a/mm/kmemdump/kinfo.c b/mm/kmemdump/kinfo.c
new file mode 100644
index 000000000000..9f0ec8a1aaa2
--- /dev/null
+++ b/mm/kmemdump/kinfo.c
@@ -0,0 +1,293 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *
+ * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
+ * Copyright 2021 Google LLC
+ * Copyright 2025 Linaro Ltd. Eugen Hristev <eugen.hristev@linaro.org>
+ */
+#include <linux/platform_device.h>
+#include <linux/kallsyms.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_reserved_mem.h>
+#include <linux/kmemdump.h>
+#include <linux/module.h>
+#include <linux/utsname.h>
+
+#define BUILD_INFO_LEN 256
+#define DEBUG_KINFO_MAGIC 0xCCEEDDFF
+
+/*
+ * Header structure must be byte-packed, since the table is provided to
+ * bootloader.
+ */
+struct kernel_info {
+ /* For kallsyms */
+ __u8 enabled_all;
+ __u8 enabled_base_relative;
+ __u8 enabled_absolute_percpu;
+ __u8 enabled_cfi_clang;
+ __u32 num_syms;
+ __u16 name_len;
+ __u16 bit_per_long;
+ __u16 module_name_len;
+ __u16 symbol_len;
+ __u64 _relative_pa;
+ __u64 _text_pa;
+ __u64 _stext_pa;
+ __u64 _etext_pa;
+ __u64 _sinittext_pa;
+ __u64 _einittext_pa;
+ __u64 _end_pa;
+ __u64 _offsets_pa;
+ __u64 _names_pa;
+ __u64 _token_table_pa;
+ __u64 _token_index_pa;
+ __u64 _markers_pa;
+ __u64 _seqs_of_names_pa;
+
+ /* For frame pointer */
+ __u32 thread_size;
+
+ /* For virt_to_phys */
+ __u64 swapper_pg_dir_pa;
+
+ /* For linux banner */
+ __u8 last_uts_release[__NEW_UTS_LEN];
+
+ /* Info of running build */
+ __u8 build_info[BUILD_INFO_LEN];
+
+ /* For module kallsyms */
+ __u32 enabled_modules_tree_lookup;
+ __u32 mod_mem_offset;
+ __u32 mod_kallsyms_offset;
+} __packed;
+
+struct kernel_all_info {
+ __u32 magic_number;
+ __u32 combined_checksum;
+ struct kernel_info info;
+} __packed;
+
+struct debug_kinfo {
+ struct device *dev;
+ void *all_info_addr;
+ u32 all_info_size;
+ struct kmemdump_backend kinfo_be;
+};
+
+static struct debug_kinfo *kinfo;
+
+#define be_to_kinfo(be) container_of(be, struct debug_kinfo, kinfo_be)
+
+static void update_kernel_all_info(struct kernel_all_info *all_info)
+{
+ int index;
+ struct kernel_info *info;
+ u32 *checksum_info;
+
+ all_info->magic_number = DEBUG_KINFO_MAGIC;
+ all_info->combined_checksum = 0;
+
+ info = &all_info->info;
+ checksum_info = (u32 *)info;
+ for (index = 0; index < sizeof(*info) / sizeof(u32); index++)
+ all_info->combined_checksum ^= checksum_info[index];
+}
+
+static int build_info_set(const char *str, const struct kernel_param *kp)
+{
+ struct kernel_all_info *all_info = kinfo->all_info_addr;
+ size_t build_info_size;
+
+ if (kinfo->all_info_addr == 0 || kinfo->all_info_size == 0)
+ return -ENAVAIL;
+
+ all_info = (struct kernel_all_info *)kinfo->all_info_addr;
+ build_info_size = sizeof(all_info->info.build_info);
+
+ memcpy(&all_info->info.build_info, str, min(build_info_size - 1,
+ strlen(str)));
+ update_kernel_all_info(all_info);
+
+ if (strlen(str) > build_info_size) {
+ pr_warn("%s: Build info buffer (len: %zd) can't hold entire string '%s'\n",
+ __func__, build_info_size, str);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static const struct kernel_param_ops build_info_op = {
+ .set = build_info_set,
+};
+
+module_param_cb(build_info, &build_info_op, NULL, 0200);
+MODULE_PARM_DESC(build_info, "Write build info to field 'build_info' of debug kinfo.");
+
+static int register_kinfo_region(const struct kmemdump_backend *be,
+ enum kmemdump_uid id, void *vaddr, size_t size)
+{
+ struct debug_kinfo *kinfo = be_to_kinfo(be);
+ struct kernel_all_info *all_info = kinfo->all_info_addr;
+ struct kernel_info *info = &all_info->info;
+ struct uts_namespace *uts;
+
+ switch (id) {
+ case KMEMDUMP_ID_COREIMAGE__sinittext:
+ info->_sinittext_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE__einittext:
+ info->_einittext_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE__end:
+ info->_end_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE__text:
+ info->_text_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE__stext:
+ info->_stext_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE__etext:
+ info->_etext_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_num_syms:
+ info->num_syms = *(__u32 *)vaddr;
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_relative_base:
+ info->_relative_pa = (u64)__pa(*(u64 *)vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_offsets:
+ info->_offsets_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_names:
+ info->_names_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_token_table:
+ info->_token_table_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_token_index:
+ info->_token_index_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_markers:
+ info->_markers_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_kallsyms_seqs_of_names:
+ info->_seqs_of_names_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_swapper_pg_dir:
+ info->swapper_pg_dir_pa = (u64)__pa(vaddr);
+ break;
+ case KMEMDUMP_ID_COREIMAGE_init_uts_ns:
+ uts = vaddr;
+ strscpy(info->last_uts_release, uts->name.release, __NEW_UTS_LEN);
+ break;
+ default:
+ break;
+ };
+
+ update_kernel_all_info(all_info);
+ return 0;
+}
+
+static int unregister_kinfo_region(const struct kmemdump_backend *be,
+ enum kmemdump_uid id)
+{
+ return 0;
+}
+
+static int debug_kinfo_probe(struct platform_device *pdev)
+{
+ struct device_node *mem_region;
+ struct reserved_mem *rmem;
+ struct kernel_info *info;
+ struct kernel_all_info *all_info;
+
+ mem_region = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
+ if (!mem_region) {
+ dev_warn(&pdev->dev, "no such memory-region\n");
+ return -ENODEV;
+ }
+
+ rmem = of_reserved_mem_lookup(mem_region);
+ if (!rmem) {
+ dev_warn(&pdev->dev, "no such reserved mem of node name %s\n",
+ pdev->dev.of_node->name);
+ return -ENODEV;
+ }
+
+ /* Need to wait for reserved memory to be mapped */
+ if (!rmem->priv)
+ return -EPROBE_DEFER;
+
+ if (!rmem->base || !rmem->size) {
+ dev_warn(&pdev->dev, "unexpected reserved memory\n");
+ return -EINVAL;
+ }
+
+ if (rmem->size < sizeof(struct kernel_all_info)) {
+ dev_warn(&pdev->dev, "unexpected reserved memory size\n");
+ return -EINVAL;
+ }
+
+ kinfo = kzalloc(sizeof(*kinfo), GFP_KERNEL);
+ if (!kinfo)
+ return -ENOMEM;
+
+ kinfo->dev = &pdev->dev;
+
+ strscpy(kinfo->kinfo_be.name, "debug_kinfo");
+ kinfo->kinfo_be.register_region = register_kinfo_region;
+ kinfo->kinfo_be.unregister_region = unregister_kinfo_region;
+ kinfo->all_info_addr = rmem->priv;
+ kinfo->all_info_size = rmem->size;
+
+ all_info = kinfo->all_info_addr;
+
+ memset(all_info, 0, sizeof(struct kernel_all_info));
+ info = &all_info->info;
+ info->enabled_all = IS_ENABLED(CONFIG_KALLSYMS_ALL);
+ info->enabled_absolute_percpu = IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU);
+ info->enabled_base_relative = IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE);
+ info->enabled_cfi_clang = IS_ENABLED(CONFIG_CFI_CLANG);
+ info->name_len = KSYM_NAME_LEN;
+ info->bit_per_long = BITS_PER_LONG;
+ info->module_name_len = MODULE_NAME_LEN;
+ info->symbol_len = KSYM_SYMBOL_LEN;
+ info->thread_size = THREAD_SIZE;
+ info->enabled_modules_tree_lookup = IS_ENABLED(CONFIG_MODULES_TREE_LOOKUP);
+ info->mod_mem_offset = offsetof(struct module, mem);
+ info->mod_kallsyms_offset = offsetof(struct module, kallsyms);
+
+ return kmemdump_register_backend(&kinfo->kinfo_be);
+}
+
+static void debug_kinfo_remove(struct platform_device *pdev)
+{
+ kfree(kinfo);
+ kmemdump_unregister_backend(&kinfo->kinfo_be);
+}
+
+static const struct of_device_id debug_kinfo_of_match[] = {
+ { .compatible = "google,debug-kinfo" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, debug_kinfo_of_match);
+
+static struct platform_driver debug_kinfo_driver = {
+ .probe = debug_kinfo_probe,
+ .remove = debug_kinfo_remove,
+ .driver = {
+ .name = "debug-kinfo",
+ .of_match_table = of_match_ptr(debug_kinfo_of_match),
+ },
+};
+module_platform_driver(debug_kinfo_driver);
+
+MODULE_AUTHOR("Eugen Hristev <eugen.hristev@linaro.org>");
+MODULE_AUTHOR("Jone Chou <jonechou@google.com>");
+MODULE_DESCRIPTION("kmemdump Kinfo Driver");
+MODULE_LICENSE("GPL");
--
2.43.0
next prev parent reply other threads:[~2025-09-12 15:11 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-12 15:08 [RFC][PATCH v3 00/16] Introduce kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 01/16] kmemdump: " Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 02/16] Documentation: Add kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 03/16] kmemdump: Add coreimage ELF layer Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 04/16] Documentation: kmemdump: Add section for coreimage ELF Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 05/16] kernel/vmcore_info: Register dynamic information into Kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 06/16] kmemdump: Introduce qcom-minidump backend driver Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 07/16] soc: qcom: smem: Add minidump device Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 08/16] init/version: Add banner_len to save banner length Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 09/16] genirq/irqdesc: Have nr_irqs as non-static Eugen Hristev
2025-09-16 21:10 ` Thomas Gleixner
2025-09-16 21:16 ` Thomas Gleixner
2025-09-17 5:43 ` Eugen Hristev
2025-09-17 7:16 ` David Hildenbrand
2025-09-17 14:10 ` Thomas Gleixner
2025-09-17 14:26 ` Eugen Hristev
2025-09-17 14:46 ` David Hildenbrand
2025-09-17 15:02 ` Eugen Hristev
2025-09-17 15:18 ` David Hildenbrand
2025-09-17 15:32 ` Eugen Hristev
2025-09-17 15:44 ` David Hildenbrand
2025-09-17 18:42 ` Thomas Gleixner
2025-09-17 19:03 ` David Hildenbrand
2025-09-18 8:23 ` Thomas Gleixner
2025-09-18 13:53 ` Eugen Hristev
2025-09-18 18:43 ` Randy Dunlap
2025-09-25 20:11 ` David Hildenbrand
2025-09-12 15:08 ` [RFC][PATCH v3 10/16] panic: Have tainted_mask " Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 11/16] mm/swapfile: Have nr_swapfiles " Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 12/16] printk: Register information into Kmemdump Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 13/16] sched: Add sched_get_runqueues_area Eugen Hristev
2025-09-12 15:08 ` [RFC][PATCH v3 14/16] kernel/vmcoreinfo: Register kmemdump core image information Eugen Hristev
2025-09-12 15:08 ` Eugen Hristev [this message]
2025-09-16 5:48 ` [RFC][PATCH v3 15/16] kmemdump: Add Kinfo backend driver Alexey Klimov
2025-09-22 10:01 ` Tudor Ambarus
2025-09-12 15:08 ` [RFC][PATCH v3 16/16] dt-bindings: Add Google Kinfo Eugen Hristev
2025-09-14 11:56 ` Krzysztof Kozlowski
2025-09-12 15:56 ` [RFC][PATCH v3 00/16] Introduce kmemdump David Hildenbrand
2025-09-12 18:35 ` Eugen Hristev
2025-09-16 7:49 ` Mukesh Ojha
2025-09-16 15:25 ` Luck, Tony
2025-09-16 15:27 ` Eugen Hristev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250912150855.2901211-16-eugen.hristev@linaro.org \
--to=eugen.hristev@linaro.org \
--cc=andersson@kernel.org \
--cc=corbet@lwn.net \
--cc=david@redhat.com \
--cc=devicetree@vger.kernel.org \
--cc=jonechou@google.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-doc@vger.kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=mukesh.ojha@oss.qualcomm.com \
--cc=pmladek@suse.com \
--cc=rdunlap@infradead.org \
--cc=rostedt@goodmis.org \
--cc=tglx@linutronix.de \
--cc=tudor.ambarus@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox