Store and display the kernel version from the previous kexec boot. The current kernel's release string is saved to the "previous-release" property in the KHO FDT before kexec. On the next boot, if this property exists, the previous kernel version is retrieved and printed during early boot. This helps diagnose bugs that only manifest when kexecing from specific kernel versions, making it easier to correlate crashes with the kernel that initiated the kexec. Signed-off-by: Breno Leitao --- include/linux/kho/abi/kexec_handover.h | 3 +++ kernel/liveupdate/kexec_handover.c | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h index 285eda8a36e4..f4f31e8f575b 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -84,6 +84,9 @@ /* The FDT property for sub-FDTs. */ #define KHO_FDT_SUB_TREE_PROP_NAME "fdt" +/* The FDT property to track previous kernel (kexec caller) */ +#define KHO_PROP_PREVIOUS_RELEASE "previous-release" + /** * DOC: Kexec Handover ABI for vmalloc Preservation * diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index 3cf2dc6840c9..b2d57868d22f 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -1246,6 +1247,7 @@ struct kho_in { phys_addr_t fdt_phys; phys_addr_t scratch_phys; phys_addr_t mem_map_phys; + char previous_release[__NEW_UTS_LEN + 1]; struct kho_debugfs dbg; }; @@ -1325,6 +1327,8 @@ static __init int kho_out_fdt_setup(void) err |= fdt_property_string(root, "compatible", KHO_FDT_COMPATIBLE); err |= fdt_property(root, KHO_FDT_MEMORY_MAP_PROP_NAME, &empty_mem_map, sizeof(empty_mem_map)); + err |= fdt_property_string(root, KHO_PROP_PREVIOUS_RELEASE, + init_uts_ns.name.release); err |= fdt_end_node(root); err |= fdt_finish(root); @@ -1436,6 +1440,22 @@ void __init kho_memory_init(void) } } +static int __init kho_print_previous_kernel(const void *fdt) +{ + const char *prev_release; + int len; + + prev_release = fdt_getprop(fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len); + if (!prev_release || len <= 0) + return -ENOENT; + + strscpy(kho_in.previous_release, prev_release, + sizeof(kho_in.previous_release)); + pr_info("exec from: %s\n", kho_in.previous_release); + + return 0; +} + void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, phys_addr_t scratch_phys, u64 scratch_len) { @@ -1513,7 +1533,10 @@ void __init kho_populate(phys_addr_t fdt_phys, u64 fdt_len, kho_in.scratch_phys = scratch_phys; kho_in.mem_map_phys = mem_map_phys; kho_scratch_cnt = scratch_cnt; - pr_info("found kexec handover data.\n"); + + if (kho_print_previous_kernel(fdt)) + /* Fallback message when previous kernel info unavailable */ + pr_info("found kexec handover data.\n"); out: if (fdt) -- 2.47.3 Track and display the number of kexec boots since the last cold reboot. This extends the previous kernel release tracking by adding a counter that increments with each kexec boot. The counter provides visibility into the kexec chain depth, which is useful for understanding boot history in production environments. Add a new property "kexec-count" in KHO FDT alongside the existing "previous-release" property. The counter is: - Initialized to 0 on cold boot (when kho_in is first instantiated) - Incremented by 1 on each subsequent kexec - Printed alongside the previous kernel release version The counter is stored as a 32-bit unsigned integer in FDT format. This is different than counter for LUO, given KHO can be used independently from LUO. Also WARN() if KHO_PROP_PREVIOUS_RELEASE doesn't exist, because it must exist if KHO_PROP_PREVIOUS_RELEASE exists. Signed-off-by: Breno Leitao Suggested-by: Pasha Tatashin --- include/linux/kho/abi/kexec_handover.h | 3 +++ kernel/liveupdate/kexec_handover.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/linux/kho/abi/kexec_handover.h b/include/linux/kho/abi/kexec_handover.h index f4f31e8f575b..9c4fc4c6a212 100644 --- a/include/linux/kho/abi/kexec_handover.h +++ b/include/linux/kho/abi/kexec_handover.h @@ -87,6 +87,9 @@ /* The FDT property to track previous kernel (kexec caller) */ #define KHO_PROP_PREVIOUS_RELEASE "previous-release" +/* The FDT property to track number of kexec counts so far */ +#define KHO_PROP_KEXEC_COUNT "kexec-count" + /** * DOC: Kexec Handover ABI for vmalloc Preservation * diff --git a/kernel/liveupdate/kexec_handover.c b/kernel/liveupdate/kexec_handover.c index b2d57868d22f..34cfc98076b8 100644 --- a/kernel/liveupdate/kexec_handover.c +++ b/kernel/liveupdate/kexec_handover.c @@ -1248,6 +1248,7 @@ struct kho_in { phys_addr_t scratch_phys; phys_addr_t mem_map_phys; char previous_release[__NEW_UTS_LEN + 1]; + u32 kexec_count; struct kho_debugfs dbg; }; @@ -1319,6 +1320,7 @@ static __init int kho_out_fdt_setup(void) { void *root = kho_out.fdt; u64 empty_mem_map = 0; + u32 kexec_count; int err; err = fdt_create(root, PAGE_SIZE); @@ -1329,6 +1331,10 @@ static __init int kho_out_fdt_setup(void) sizeof(empty_mem_map)); err |= fdt_property_string(root, KHO_PROP_PREVIOUS_RELEASE, init_uts_ns.name.release); + /* kho_in.kexec_count is set to 0 on cold boot */ + kexec_count = kho_in.kexec_count + 1; + err |= fdt_property(root, KHO_PROP_KEXEC_COUNT, &kexec_count, + sizeof(kexec_count)); err |= fdt_end_node(root); err |= fdt_finish(root); @@ -1443,15 +1449,23 @@ void __init kho_memory_init(void) static int __init kho_print_previous_kernel(const void *fdt) { const char *prev_release; + const u32 *count_ptr; int len; prev_release = fdt_getprop(fdt, 0, KHO_PROP_PREVIOUS_RELEASE, &len); if (!prev_release || len <= 0) return -ENOENT; + /* Read the kexec count from the previous kernel */ + count_ptr = fdt_getprop(fdt, 0, KHO_PROP_KEXEC_COUNT, &len); + if (WARN_ON(!count_ptr || len != sizeof(u32))) + return -ENOENT; + kho_in.kexec_count = *count_ptr; + strscpy(kho_in.previous_release, prev_release, sizeof(kho_in.previous_release)); - pr_info("exec from: %s\n", kho_in.previous_release); + pr_info("exec from: %s (count %u)\n", kho_in.previous_release, + kho_in.kexec_count); return 0; } -- 2.47.3