Skip to content

Commit 3751e72

Browse files
AKASHI Takahirowilldeacon
authored andcommitted
arm64: kexec_file: add crash dump support
Enabling crash dump (kdump) includes * prepare contents of ELF header of a core dump file, /proc/vmcore, using crash_prepare_elf64_headers(), and * add two device tree properties, "linux,usable-memory-range" and "linux,elfcorehdr", which represent respectively a memory range to be used by crash dump kernel and the header's location Signed-off-by: AKASHI Takahiro <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Reviewed-by: James Morse <[email protected]> Tested-and-reviewed-by: Bhupesh Sharma <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent c273a2b commit 3751e72

File tree

3 files changed

+106
-8
lines changed

3 files changed

+106
-8
lines changed

arch/arm64/include/asm/kexec.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,10 @@ static inline void crash_post_resume(void) {}
9696
struct kimage_arch {
9797
void *dtb;
9898
unsigned long dtb_mem;
99+
/* Core ELF header buffer */
100+
void *elf_headers;
101+
unsigned long elf_headers_mem;
102+
unsigned long elf_headers_sz;
99103
};
100104

101105
extern const struct kexec_file_ops kexec_image_ops;

arch/arm64/kernel/kexec_image.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,6 @@ static void *image_load(struct kimage *image,
4747
struct kexec_segment *kernel_segment;
4848
int ret;
4949

50-
/* We don't support crash kernels yet. */
51-
if (image->type == KEXEC_TYPE_CRASH)
52-
return ERR_PTR(-EOPNOTSUPP);
53-
5450
/*
5551
* We require a kernel with an unambiguous Image header. Per
5652
* Documentation/arm64/booting.rst, this is the case when image_size

arch/arm64/kernel/machine_kexec_file.c

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@
1717
#include <linux/memblock.h>
1818
#include <linux/of_fdt.h>
1919
#include <linux/random.h>
20+
#include <linux/slab.h>
2021
#include <linux/string.h>
2122
#include <linux/types.h>
2223
#include <linux/vmalloc.h>
2324
#include <asm/byteorder.h>
2425

2526
/* relevant device tree properties */
27+
#define FDT_PROP_KEXEC_ELFHDR "linux,elfcorehdr"
28+
#define FDT_PROP_MEM_RANGE "linux,usable-memory-range"
2629
#define FDT_PROP_INITRD_START "linux,initrd-start"
2730
#define FDT_PROP_INITRD_END "linux,initrd-end"
2831
#define FDT_PROP_BOOTARGS "bootargs"
@@ -40,6 +43,10 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
4043
vfree(image->arch.dtb);
4144
image->arch.dtb = NULL;
4245

46+
vfree(image->arch.elf_headers);
47+
image->arch.elf_headers = NULL;
48+
image->arch.elf_headers_sz = 0;
49+
4350
return kexec_image_post_load_cleanup_default(image);
4451
}
4552

@@ -55,6 +62,31 @@ static int setup_dtb(struct kimage *image,
5562

5663
off = ret;
5764

65+
ret = fdt_delprop(dtb, off, FDT_PROP_KEXEC_ELFHDR);
66+
if (ret && ret != -FDT_ERR_NOTFOUND)
67+
goto out;
68+
ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE);
69+
if (ret && ret != -FDT_ERR_NOTFOUND)
70+
goto out;
71+
72+
if (image->type == KEXEC_TYPE_CRASH) {
73+
/* add linux,elfcorehdr */
74+
ret = fdt_appendprop_addrrange(dtb, 0, off,
75+
FDT_PROP_KEXEC_ELFHDR,
76+
image->arch.elf_headers_mem,
77+
image->arch.elf_headers_sz);
78+
if (ret)
79+
return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
80+
81+
/* add linux,usable-memory-range */
82+
ret = fdt_appendprop_addrrange(dtb, 0, off,
83+
FDT_PROP_MEM_RANGE,
84+
crashk_res.start,
85+
crashk_res.end - crashk_res.start + 1);
86+
if (ret)
87+
return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
88+
}
89+
5890
/* add bootargs */
5991
if (cmdline) {
6092
ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
@@ -125,8 +157,8 @@ static int setup_dtb(struct kimage *image,
125157
}
126158

127159
/*
128-
* More space needed so that we can add initrd, bootargs, kaslr-seed, and
129-
* rng-seed.
160+
* More space needed so that we can add initrd, bootargs, kaslr-seed,
161+
* rng-seed, userable-memory-range and elfcorehdr.
130162
*/
131163
#define DTB_EXTRA_SPACE 0x1000
132164

@@ -174,21 +206,87 @@ static int create_dtb(struct kimage *image,
174206
}
175207
}
176208

209+
static int prepare_elf_headers(void **addr, unsigned long *sz)
210+
{
211+
struct crash_mem *cmem;
212+
unsigned int nr_ranges;
213+
int ret;
214+
u64 i;
215+
phys_addr_t start, end;
216+
217+
nr_ranges = 1; /* for exclusion of crashkernel region */
218+
for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
219+
MEMBLOCK_NONE, &start, &end, NULL)
220+
nr_ranges++;
221+
222+
cmem = kmalloc(sizeof(struct crash_mem) +
223+
sizeof(struct crash_mem_range) * nr_ranges, GFP_KERNEL);
224+
if (!cmem)
225+
return -ENOMEM;
226+
227+
cmem->max_nr_ranges = nr_ranges;
228+
cmem->nr_ranges = 0;
229+
for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
230+
MEMBLOCK_NONE, &start, &end, NULL) {
231+
cmem->ranges[cmem->nr_ranges].start = start;
232+
cmem->ranges[cmem->nr_ranges].end = end - 1;
233+
cmem->nr_ranges++;
234+
}
235+
236+
/* Exclude crashkernel region */
237+
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
238+
239+
if (!ret)
240+
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
241+
242+
kfree(cmem);
243+
return ret;
244+
}
245+
177246
int load_other_segments(struct kimage *image,
178247
unsigned long kernel_load_addr,
179248
unsigned long kernel_size,
180249
char *initrd, unsigned long initrd_len,
181250
char *cmdline)
182251
{
183252
struct kexec_buf kbuf;
184-
void *dtb = NULL;
185-
unsigned long initrd_load_addr = 0, dtb_len;
253+
void *headers, *dtb = NULL;
254+
unsigned long headers_sz, initrd_load_addr = 0, dtb_len;
186255
int ret = 0;
187256

188257
kbuf.image = image;
189258
/* not allocate anything below the kernel */
190259
kbuf.buf_min = kernel_load_addr + kernel_size;
191260

261+
/* load elf core header */
262+
if (image->type == KEXEC_TYPE_CRASH) {
263+
ret = prepare_elf_headers(&headers, &headers_sz);
264+
if (ret) {
265+
pr_err("Preparing elf core header failed\n");
266+
goto out_err;
267+
}
268+
269+
kbuf.buffer = headers;
270+
kbuf.bufsz = headers_sz;
271+
kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
272+
kbuf.memsz = headers_sz;
273+
kbuf.buf_align = SZ_64K; /* largest supported page size */
274+
kbuf.buf_max = ULONG_MAX;
275+
kbuf.top_down = true;
276+
277+
ret = kexec_add_buffer(&kbuf);
278+
if (ret) {
279+
vfree(headers);
280+
goto out_err;
281+
}
282+
image->arch.elf_headers = headers;
283+
image->arch.elf_headers_mem = kbuf.mem;
284+
image->arch.elf_headers_sz = headers_sz;
285+
286+
pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
287+
image->arch.elf_headers_mem, headers_sz, headers_sz);
288+
}
289+
192290
/* load initrd */
193291
if (initrd) {
194292
kbuf.buffer = initrd;

0 commit comments

Comments
 (0)