[PATCH 2/2] powerpc/crash: Update backup region offset in elfcorehdr on memory hotplug
Sourabh Jain
sourabhjain at linux.ibm.com
Wed Mar 4 00:47:16 AEDT 2026
When elfcorehdr is prepared for kdump, the program header representing
the first 64 KB of memory is expected to have its offset point to the
backup region. This is required because purgatory copies the first 64 KB
of the crashed kernel memory to this backup region following a kernel
crash. This allows the capture kernel to use the first 64 KB of memory
to place the exception vectors and other required data.
When elfcorehdr is recreated due to memory hotplug, the offset of
the program header representing the first 64 KB is not updated.
As a result, the capture kernel exports the first 64 KB at offset
0, even though the data actually resides in the backup region.
Fix this by calling sync_backup_region_phdr() to update the program
header offset in the elfcorehdr created during memory hotplug.
sync_backup_region_phdr() works for images loaded via the
kexec_file_load syscall. However, it does not work for kexec_load,
because image->arch.backup_start is not initialized in that case.
So introduce machine_kexec_post_load() to process the elfcorehdr
prepared by kexec-tools and initialize image->arch.backup_start for
kdump images loaded via kexec_load syscall.
Rename update_backup_region_phdr() to sync_backup_region_phdr() and
extend it to synchronize the backup region offset between the kdump
image and the ELF core header. The helper now supports updating either
the kdump image from the ELF program header or updating the ELF program
header from the kdump image, avoiding code duplication.
This patch depends on the patch titled
"powerpc/crash: fix backup region offset update to elfcorehdr".
Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support")
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
Signed-off-by: Sourabh Jain <sourabhjain at linux.ibm.com>
---
arch/powerpc/include/asm/kexec.h | 6 ++++
arch/powerpc/kexec/crash.c | 60 +++++++++++++++++++++++++++++++
arch/powerpc/kexec/file_load_64.c | 29 +--------------
3 files changed, 67 insertions(+), 28 deletions(-)
diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h
index bd4a6c42a5f3..2adcc5ed9269 100644
--- a/arch/powerpc/include/asm/kexec.h
+++ b/arch/powerpc/include/asm/kexec.h
@@ -145,6 +145,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
unsigned int arch_crash_get_elfcorehdr_size(void);
#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
+
+int machine_kexec_post_load(struct kimage *image);
+#define machine_kexec_post_load machine_kexec_post_load
+
#endif /* CONFIG_CRASH_HOTPLUG */
extern int crashing_cpu;
@@ -159,6 +163,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs);
extern void crash_kexec_prepare(void);
extern void crash_kexec_secondary(struct pt_regs *regs);
+extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr,
+ bool phdr_to_kimage);
static inline bool kdump_in_progress(void)
{
return crashing_cpu >= 0;
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index a325c1c02f96..e8dd941e2159 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -27,6 +27,7 @@
#include <asm/debug.h>
#include <asm/interrupt.h>
#include <asm/kexec_ranges.h>
+#include <asm/crashdump-ppc64.h>
/*
* The primary CPU waits a while for all secondary CPUs to enter. This is to
@@ -399,7 +400,64 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
ppc_md.kexec_cpu_down(1, 0);
}
+#ifdef CONFIG_CRASH_DUMP
+/**
+ * sync_backup_region_phdr - synchronize backup region offset between
+ * kexec image and ELF core header.
+ * @image: Kexec image.
+ * @ehdr: ELF core header.
+ * @phdr_to_kimage: If true, read the offset from the ELF program header
+ * and update the kimage backup region. If false, update
+ * the ELF program header offset from the kimage backup
+ * region.
+ *
+ * Returns nothing.
+ */
+void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage)
+{
+ Elf64_Phdr *phdr;
+ unsigned int i;
+
+ phdr = (Elf64_Phdr *)(ehdr + 1);
+ for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
+ if (phdr->p_paddr == BACKUP_SRC_START) {
+ if (phdr_to_kimage)
+ image->arch.backup_start = phdr->p_offset;
+ else
+ phdr->p_offset = image->arch.backup_start;
+
+ kexec_dprintk("Backup region offset updated to 0x%lx\n",
+ image->arch.backup_start);
+ return;
+ }
+ }
+}
+#endif /* CONFIG_CRASH_DUMP */
+
#ifdef CONFIG_CRASH_HOTPLUG
+
+int machine_kexec_post_load(struct kimage *image)
+{
+ int i;
+ unsigned long mem;
+ unsigned char *ptr;
+
+ if (image->type != KEXEC_TYPE_CRASH)
+ return 0;
+
+ if (image->file_mode)
+ return 0;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ mem = image->segment[i].mem;
+ ptr = (char *)__va(mem);
+
+ if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0)
+ sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true);
+ }
+ return 0;
+}
+
#undef pr_fmt
#define pr_fmt(fmt) "crash hp: " fmt
@@ -474,6 +532,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
goto out;
}
+ sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false);
+
ptr = __va(mem);
if (ptr) {
/* Temporarily invalidate the crash image while it is replaced */
diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index e631cf2eda2c..502976a1823d 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -374,33 +374,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf)
return 0;
}
-/**
- * update_backup_region_phdr - Update backup region's offset for the core to
- * export the region appropriately.
- * @image: Kexec image.
- * @ehdr: ELF core header.
- *
- * Assumes an exclusive program header is setup for the backup region
- * in the ELF headers
- *
- * Returns nothing.
- */
-static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr)
-{
- Elf64_Phdr *phdr;
- unsigned int i;
-
- phdr = (Elf64_Phdr *)(ehdr + 1);
- for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
- if (phdr->p_paddr == BACKUP_SRC_START) {
- phdr->p_offset = image->arch.backup_start;
- kexec_dprintk("Backup region offset updated to 0x%lx\n",
- image->arch.backup_start);
- return;
- }
- }
-}
-
static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
{
#if defined(CONFIG_CRASH_HOTPLUG) && defined(CONFIG_MEMORY_HOTPLUG)
@@ -445,7 +418,7 @@ static int load_elfcorehdr_segment(struct kimage *image, struct kexec_buf *kbuf)
}
/* Fix the offset for backup region in the ELF header */
- update_backup_region_phdr(image, headers);
+ sync_backup_region_phdr(image, headers, false);
kbuf->buffer = headers;
kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;
--
2.52.0
More information about the Linuxppc-dev
mailing list