Skip to content

Commit 2c381ad

Browse files
sourabhjainsgregkh
authored andcommitted
powerpc/crash: Update backup region offset in elfcorehdr on memory hotplug
[ Upstream commit f53b24d ] 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. Define ARCH_HAS_KIMAGE_ARCH and struct kimage_arch when CONFIG_KEXEC_FILE or CONFIG_CRASH_DUMP is enabled so that kimage->arch.backup_start is available with the kexec_load system call. This patch depends on the patch titled "powerpc/crash: fix backup region offset update to elfcorehdr". Fixes: 849599b ("powerpc/crash: add crash memory hotplug support") Reviewed-by: Aditya Gupta <adityag@linux.ibm.com> Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com> Signed-off-by: Madhavan Srinivasan <maddy@linux.ibm.com> Link: https://patch.msgid.link/20260312083051.1935737-3-sourabhjain@linux.ibm.com Signed-off-by: Sasha Levin <sashal@kernel.org>
1 parent ba84b18 commit 2c381ad

3 files changed

Lines changed: 76 additions & 31 deletions

File tree

arch/powerpc/include/asm/kexec.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,18 +66,20 @@ void relocate_new_kernel(unsigned long indirection_page, unsigned long reboot_co
6666
unsigned long start_address) __noreturn;
6767
void kexec_copy_flush(struct kimage *image);
6868

69-
#ifdef CONFIG_KEXEC_FILE
70-
extern const struct kexec_file_ops kexec_elf64_ops;
7169

70+
#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP)
7271
#define ARCH_HAS_KIMAGE_ARCH
73-
7472
struct kimage_arch {
7573
struct crash_mem *exclude_ranges;
7674

7775
unsigned long backup_start;
7876
void *backup_buf;
7977
void *fdt;
8078
};
79+
#endif
80+
81+
#ifdef CONFIG_KEXEC_FILE
82+
extern const struct kexec_file_ops kexec_elf64_ops;
8183

8284
char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
8385
unsigned long cmdline_len);
@@ -145,6 +147,10 @@ int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
145147

146148
unsigned int arch_crash_get_elfcorehdr_size(void);
147149
#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
150+
151+
int machine_kexec_post_load(struct kimage *image);
152+
#define machine_kexec_post_load machine_kexec_post_load
153+
148154
#endif /* CONFIG_CRASH_HOTPLUG */
149155

150156
extern int crashing_cpu;
@@ -159,6 +165,8 @@ extern void default_machine_crash_shutdown(struct pt_regs *regs);
159165
extern void crash_kexec_prepare(void);
160166
extern void crash_kexec_secondary(struct pt_regs *regs);
161167

168+
extern void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr,
169+
bool phdr_to_kimage);
162170
static inline bool kdump_in_progress(void)
163171
{
164172
return crashing_cpu >= 0;

arch/powerpc/kexec/crash.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <asm/debug.h>
2828
#include <asm/interrupt.h>
2929
#include <asm/kexec_ranges.h>
30+
#include <asm/crashdump-ppc64.h>
3031

3132
/*
3233
* The primary CPU waits a while for all secondary CPUs to enter. This is to
@@ -399,7 +400,68 @@ void default_machine_crash_shutdown(struct pt_regs *regs)
399400
ppc_md.kexec_cpu_down(1, 0);
400401
}
401402

403+
#ifdef CONFIG_CRASH_DUMP
404+
/**
405+
* sync_backup_region_phdr - synchronize backup region offset between
406+
* kexec image and ELF core header.
407+
* @image: Kexec image.
408+
* @ehdr: ELF core header.
409+
* @phdr_to_kimage: If true, read the offset from the ELF program header
410+
* and update the kimage backup region. If false, update
411+
* the ELF program header offset from the kimage backup
412+
* region.
413+
*
414+
* Note: During kexec_load, this is called with phdr_to_kimage = true. For
415+
* kexec_file_load and ELF core header recreation during memory hotplug
416+
* events, it is called with phdr_to_kimage = false.
417+
*
418+
* Returns nothing.
419+
*/
420+
void sync_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr, bool phdr_to_kimage)
421+
{
422+
Elf64_Phdr *phdr;
423+
unsigned int i;
424+
425+
phdr = (Elf64_Phdr *)(ehdr + 1);
426+
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
427+
if (phdr->p_paddr == BACKUP_SRC_START) {
428+
if (phdr_to_kimage)
429+
image->arch.backup_start = phdr->p_offset;
430+
else
431+
phdr->p_offset = image->arch.backup_start;
432+
433+
kexec_dprintk("Backup region offset updated to 0x%lx\n",
434+
image->arch.backup_start);
435+
return;
436+
}
437+
}
438+
}
439+
#endif /* CONFIG_CRASH_DUMP */
440+
402441
#ifdef CONFIG_CRASH_HOTPLUG
442+
443+
int machine_kexec_post_load(struct kimage *image)
444+
{
445+
int i;
446+
unsigned long mem;
447+
unsigned char *ptr;
448+
449+
if (image->type != KEXEC_TYPE_CRASH)
450+
return 0;
451+
452+
if (image->file_mode)
453+
return 0;
454+
455+
for (i = 0; i < image->nr_segments; i++) {
456+
mem = image->segment[i].mem;
457+
ptr = (char *)__va(mem);
458+
459+
if (ptr && memcmp(ptr, ELFMAG, SELFMAG) == 0)
460+
sync_backup_region_phdr(image, (Elf64_Ehdr *) ptr, true);
461+
}
462+
return 0;
463+
}
464+
403465
#undef pr_fmt
404466
#define pr_fmt(fmt) "crash hp: " fmt
405467

@@ -474,6 +536,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
474536
goto out;
475537
}
476538

539+
sync_backup_region_phdr(image, (Elf64_Ehdr *) elfbuf, false);
540+
477541
ptr = __va(mem);
478542
if (ptr) {
479543
/* Temporarily invalidate the crash image while it is replaced */

arch/powerpc/kexec/file_load_64.c

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -374,33 +374,6 @@ static int load_backup_segment(struct kimage *image, struct kexec_buf *kbuf)
374374
return 0;
375375
}
376376

377-
/**
378-
* update_backup_region_phdr - Update backup region's offset for the core to
379-
* export the region appropriately.
380-
* @image: Kexec image.
381-
* @ehdr: ELF core header.
382-
*
383-
* Assumes an exclusive program header is setup for the backup region
384-
* in the ELF headers
385-
*
386-
* Returns nothing.
387-
*/
388-
static void update_backup_region_phdr(struct kimage *image, Elf64_Ehdr *ehdr)
389-
{
390-
Elf64_Phdr *phdr;
391-
unsigned int i;
392-
393-
phdr = (Elf64_Phdr *)(ehdr + 1);
394-
for (i = 0; i < ehdr->e_phnum; i++, phdr++) {
395-
if (phdr->p_paddr == BACKUP_SRC_START) {
396-
phdr->p_offset = image->arch.backup_start;
397-
kexec_dprintk("Backup region offset updated to 0x%lx\n",
398-
image->arch.backup_start);
399-
return;
400-
}
401-
}
402-
}
403-
404377
static unsigned int kdump_extra_elfcorehdr_size(struct crash_mem *cmem)
405378
{
406379
#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)
445418
}
446419

447420
/* Fix the offset for backup region in the ELF header */
448-
update_backup_region_phdr(image, headers);
421+
sync_backup_region_phdr(image, headers, false);
449422

450423
kbuf->buffer = headers;
451424
kbuf->mem = KEXEC_BUF_MEM_UNKNOWN;

0 commit comments

Comments
 (0)