0/63 已展开

LLM 分析

meminspect 系列:把"想看的内存"提前登记给固件

系列概况

  • 标题: [PATCH v3 00/26] Introduce meminspect
  • 作者: Mukesh Ojha (Qualcomm);Co-developed by Eugen Hristev (Linaro)
  • 版本: v3(沿革:RFC v2 → RFC v3 → v1 → v2 → v3),2026-07-08
  • 规模: 26 个补丁,覆盖 core meminspect、~20 个子系统静态/动态注解、Qualcomm Minidump backend、Google Pixel debug-kinfo backend
  • 修改文件: kernel/meminspect/*include/linux/meminspect.hinclude/asm-generic/vmlinux.lds.h、各子系统(init/version、mm/init-mm、mm/percpu、mm/page_alloc、mm/show_mem、mm/swapfile、mm/sparse、mm/numa、mm/mm_init、kernel/cpu、kernel/irq、kernel/fork、kernel/time/timer、kernel/time/timekeeping、kernel/sched/core、kernel/panic、kernel/kallsyms、kernel/configs、kernel/vmcore_info、kernel/printk/printk.c)、drivers/soc/qcom/{minidump.c,smem.c,Kconfig,Makefile}drivers/remoteproc/qcom_common.cinclude/linux/soc/qcom/minidump.hdrivers/of/platform.c、DT binding、文档、MAINTAINERS
  • 代码统计: 01/26 单 patch +934 行(核心 ~474 + 头 ~270 + 文档 ~144);22/26 -54/+68;23/26 +271;26/26 +257
  • Message-ID: 20260708-meminspect-v3-v3-0-7aa5a0a74d5c@oss.qualcomm.com
  • 完整性: 完整;thread 共 63 封邮件(27 个 patch + 22 个 Sashiko 自动评审 + Lorenzo Stoakes/Petr Mladek/Christoph Hellwig/Liam Howlett/Petr Pavlu/Krzysztof Kozlowski 等人的多轮回复)

补丁目的

  • 核心动机: 提供"系统还活着时就把感兴趣的内存区域登记进一张表"的机制,崩溃/冻结后上层 firmware 或 bootloader 不依赖 pstore、kdump、panic handler 也能读到这些变量。
  • 为什么需要: pstore 依赖常驻 RAM/Flash(部分设备 reboot 后 RAM 内容丢失);kdump 依赖 kexec 二次启动(部分平台禁止);本机制只预先登记最小必要信息,适合生产环境对内存/连接受限的设备。
  • 目标场景: 触发 watchdog 后由 firmware 进入 download mode,通过 QDL 抓出 minidump.elf(Qualcomm);或写到 reserved-memory 给 bootloader 解析(Pixel Kinfo)。
  • API 形态: 静态注解宏 MEMINSPECT_SIMPLE_ENTRY / _NAMED_ENTRY / _AREA_ENTRY 进入 .inspect_table section;运行期 meminspect_register_* / meminspect_lock_traverse / meminspect_notifier_register
  • 配置: 依赖 CONFIG_MEMINSPECT;当 CONFIG_CRASH_DUMP=y 时附加生成 ELF 头与 vmcoreinfo note,可拼接为可被 crash 工具加载的 core image。
  • 测试: 已在 Qualcomm SA8775P (Lemans EVK) + next-20260707 + qcom_scm.download_mode=mini 上验证 firmware 正确抓取 minidump region。

关键实现

  • 核心层 (01/26): vmlinux.lds.h 新增 MEMINSPECT_TABLE.inspect_table 放进 vmlinux;include/linux/meminspect.h 暴露宏与 enum meminspect_uidkernel/meminspect/meminspect.cDEFINE_MUTEX(meminspect_lock) 保护 inspect_entries[MEMINSPECT_ID_MAX](MAX=201)、ATOMIC_NOTIFIER_HEAD(meminspect_notifier_list)init_elfheader()(从 CMA 分配永不释放的 buffer,构造 ELF 头 + PT_LOAD phdr)、meminspect_unregister_id()meminspect_prepare_table()
  • 静态全局注解 (02-10, 14-17, 20, 21): 在 linux_banner / init_uts_ns / __per_cpu_offset / __cpu_*_mask / total_nr_irqs / jiffies_64 / tk_data / nr_threads / node_states / _totalram_pages / nr_swapfiles / _sinittext.._end,init_mm,swapper_pg_dir / tainted_*,taint_flags / kallsyms_* / mem_section / high_memory / printk_rb_* 后面插入 MEMINSPECT_*_ENTRY
  • timekeeping (07/26): 用 MEMINSPECT_NAMED_ENTRY(tk_data, timekeeper_data) 显式给数组打名字。
  • 运行期注册 (12, 13, 18, 19, 21): crash_save_vmcoreinfo_init()meminspect_lock_register_id_va(MEMINSPECT_ID_VMCOREINFO, vmcoreinfo_data, vmcoreinfo_size)ikconfig_init() 抓 IKCFG_ST/ED marker;sched_init() 给每个 per-CPU rqmeminspect_lock_register_va(rq, sizeof(*rq))alloc_node_data()meminspect_lock_register_pa(nd_pa, nd_size)setup_log_buf() 注册 new_log_buf / new_descs / new_infos
  • Qcom Minidump backend (22-24): 把 struct minidump_*qcom_common.c 抽到 include/linux/soc/qcom/minidump.hdrivers/soc/qcom/minidump.cqcom_smem_get(SBL_MINIDUMP_SMEM_ID) 拿 TOC,注册 qcom_md_notifier_cb,traverse 全表生成 minidump_regiondrivers/soc/qcom/smem.c 通过 platform_device_register_data() 创建 qcom-minidump 子设备。
  • Google Kinfo (25-26): 新增 google,debug-kinfo.yaml reserved-memory binding;kernel/meminspect/kinfo.c 在 probe 拿到 reserved-mem 后把登记区的物理地址写进 struct kernel_all_info(带 DEBUG_KINFO_MAGIC + XOR checksum)供 bootloader/firmware 读取。
       kernel sources                .inspect_table section
  +----------------------+        +----------------------------+
  | init/version.c       |------->| linux_banner/init_uts_ns   |
  | mm/init-mm.c         |------->| init_mm/_text/_stext/...   |
  | kernel/cpu.c         |------->| __cpu_*_mask               |
  | kernel/irq/irqdesc.c |------->| total_nr_irqs              |
  | kernel/sched/core.c  |--run-->| rq (per-cpu, runtime)      |
  | kernel/printk/*.c    |--run-->| prb/static/dynamic buf     |
  | mm/{sparse,numa,...} |--run-->| mem_section/NODE_DATA      |
  | ... (~20 sites)      |        +----------------------------+
  +----------------------+                    |
                                              v
                                  +------------------------+
                                  | inspect_entries[201]   |  fixed-size
                                  |  (id,va,pa,size,type)  |  array
                                  +------------------------+
                                              |
                            traverse() + atomic_notifier_call()
                                              |
                +-----------------------------+-----------------------------+
                v                                                           v
     +-------------------------+                              +-------------------------+
     | drivers/soc/qcom/       |                              | kernel/meminspect/      |
     |   minidump.c            |                              |   kinfo.c               |
     |  notifier + traverse    |                              |  reserved-mem writer    |
     |  -> SMEM TOC (Qualcomm) |                              |  -> Kinfo header (Pixel)|
     +-------------------------+                              +-------------------------+
                |                                                           |
                +------------- ELF core image (CRASH_DUMP=y) ----------------+

类比

  • meminspect = 黑匣子预登记清单:起飞前把所有你想在事故后看懂的仪表(cpumask、runqueue、vmcoreinfo、banner…)编号登记在一张共享清单上,飞机失事时黑匣子不再依赖电气系统也能逐项抄录。崩溃后 Linux 已经"失能",但固件照样能从清单里把仪表读出来。
  • .inspect_table = 行李托运标签:编译期就把 linux_banner 等静态变量的"目的地标签"贴好,runtime 注册相当于后到的行李补打标签,最后统一由"行李分拣员"(minidump/kinfo backend)按标签打包送上飞机(SMEM TOC / reserved-mem)。

Highlight:风险与注意点

  • 导出语义争议(Lorenzo Stoakes): 把 total_nr_irqsnr_swapfilesmem_sectionhigh_memory 等原本"未导出"的内部变量塞进 meminspect 表,等于事实上的 EXPORT_SYMBOL,driver 可写。Lorenzo 直接称之为 "backdoor EXPORT_SYMBOLS",并对 mm/swapfile 暗示"global GPL"。
  • virt_to_phys 误用: Sashiko 自动评审在 02/05/08/14/16/18/19/26 都标出 virt_to_phys() 用于非线性地址会失败。sched/core 把 per-CPU vmalloc 区 runqueue 直接传进去会 panic;meminspect_prepare_table()virt_to_phys() 路径需要先做 is_linear 判断。
  • 固定表容量: MEMINSPECT_ID_MAX=201 仅留约 157 个动态槽,alloc_node_data 在大型 NUMA、printk 在大 log buffer、sched_init 在多核系统会无声丢弃。
  • 大小/对齐错误: mm/init-mmsizeof(void*)_text/_stext/_einittext 的 area size;kallsymssizeof(void*) 截断 kallsyms_offsets/names/...printknew_log_buf_len 已被清零后才注册;vmcore_info size 未对齐会让 ELF 拼接错位;mem_sectionCONFIG_SPARSEMEM_EXTREME 下漏掉 sparse_index_alloc() 的 leaf。
  • Section 布局脆弱: MEMINSPECT_ENTRY__aligned,编译器可能在 .inspect_table 插入 padding(Sashiko 标 Critical);linux_banner 同时被 init/version.cinit/version-timestamp.c 注册两份。
  • 维护路径分歧: 作者建议整条走 mm 树,22-24 可延后到 Bjorn 的 qcom 树;其他子系统 maintainer 期望拿到 Acked-by;25 的 DT binding 走独立 review 流程(Krzysztof Kozlowski 在 v3 后已介入)。
  • 后续观察点: patch 07 commit msg 声称更新 "minidump backend string table" 但 diff 里没有;patch 23 qcom_md_probe v3 修了三个错误返回路径,Lorenzo 仍要再 review;Kinfo 头与现有 Android debug_kinfo.c 字段是否完全对齐需要 Pixel 设备实测。

Patch 概览

范围作用
01核心框架 + 文档 + MAINTAINERS
02-10, 14-17各子系统静态全局注解
07, 11-13, 18-21运行期动态注册
22-24Qualcomm Minidump backend
25-26Google Pixel Kinfo backend + DT binding

版本变化

  • v1 → v2: 修文档告警、修 0-day 报告、采纳 Mike 建议删 dynamic mark inspect flag、给 printk 加 Reviewed-by、按 Rob Herring 改 debug-kinfo binding。
  • v2 → v3: 补 binding/DT 文档、timekeeping 注册 tk_data、修 qcom_md_probe 三个 dev_err_probe 失败返回路径、修 meminspect_traverse() kernel-doc、把 meminspect.rstMEMINSPECT_ITERATOR_CB 改为实际 typedef meminspect_iter_cb_t、补 kinfo 结构 kernel-doc、清理代码风格。

一句话总结

meminspect 想用"系统活着时登记好的内存表"替代 pstore/kdump,让 firmware/bootloader 在内核失能后仍能读取核心调试变量;但 v3 同时被人工评审(Sashiko/Lorenzo)指出 EXPORT 语义、virt_to_phys 误用、固定表容量与 section 对齐等关键问题,能否合入仍取决于后续答复。