Skip to content

Commit 59e464c

Browse files
author
AKASHI Takahiro
committed
arm64: kdump: provide /proc/vmcore file
Arch-specific functions are added to allow for implementing a crash dump file interface, /proc/vmcore, which can be viewed as a ELF file. A user space tool, like kexec-tools, is responsible for allocating a separate region for the core's ELF header within crash kdump kernel memory and filling it in when executing kexec_load(). Then, its location will be advertised to crash dump kernel via a new device-tree property, "linux,elfcorehdr", and crash dump kernel preserves the region for later use with reserve_elfcorehdr() at boot time. On crash dump kernel, /proc/vmcore will access the primary kernel's memory with copy_oldmem_page(), which feeds the data page-by-page by ioremap'ing it since it does not reside in linear mapping on crash dump kernel. Meanwhile, elfcorehdr_read() is simple as the region is always mapped. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> Reviewed-by: James Morse <james.morse@arm.com> Acked-by: Catalin Marinas <catalin.marinas@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com> Conflicts: arch/arm64/kernel/Makefile due to missing commit 214fad550772 ("arm64: relocation testing module")
1 parent 8c6fadd commit 59e464c

4 files changed

Lines changed: 136 additions & 1 deletion

File tree

arch/arm64/Kconfig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,17 @@ config KEXEC
608608
but it is independent of the system firmware. And like a reboot
609609
you can start any kernel with it, not just Linux.
610610

611+
config CRASH_DUMP
612+
bool "Build kdump crash kernel"
613+
help
614+
Generate crash dump after being started by kexec. This should
615+
be normally only set in special crash dump kernels which are
616+
loaded in the main kernel with kexec-tools into a specially
617+
reserved region and then later executed after a crash by
618+
kdump/kexec.
619+
620+
For more details see Documentation/kdump/kdump.txt
621+
611622
config XEN_DOM0
612623
def_bool y
613624
depends on XEN

arch/arm64/kernel/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ arm64-obj-$(CONFIG_HIBERNATION) += hibernate.o hibernate-asm.o
4646
arm64-obj-$(CONFIG_ARM64_ACPI_PARKING_PROTOCOL) += acpi_parking_protocol.o
4747
arm64-obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o \
4848
cpu-reset.o
49-
>>>>>>> d28f6df1305a... arm64/kexec: Add core kexec support
49+
arm64-obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
5050

5151
obj-y += $(arm64-obj-y) vdso/ probes/
5252
obj-m += $(arm64-obj-m)

arch/arm64/kernel/crash_dump.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Routines for doing kexec-based kdump
3+
*
4+
* Copyright (C) 2017 Linaro Limited
5+
* Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
6+
*
7+
* This program is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License version 2 as
9+
* published by the Free Software Foundation.
10+
*/
11+
12+
#include <linux/crash_dump.h>
13+
#include <linux/errno.h>
14+
#include <linux/io.h>
15+
#include <linux/memblock.h>
16+
#include <linux/uaccess.h>
17+
#include <asm/memory.h>
18+
19+
/**
20+
* copy_oldmem_page() - copy one page from old kernel memory
21+
* @pfn: page frame number to be copied
22+
* @buf: buffer where the copied page is placed
23+
* @csize: number of bytes to copy
24+
* @offset: offset in bytes into the page
25+
* @userbuf: if set, @buf is in a user address space
26+
*
27+
* This function copies one page from old kernel memory into buffer pointed by
28+
* @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes
29+
* copied or negative error in case of failure.
30+
*/
31+
ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
32+
size_t csize, unsigned long offset,
33+
int userbuf)
34+
{
35+
void *vaddr;
36+
37+
if (!csize)
38+
return 0;
39+
40+
vaddr = memremap(__pfn_to_phys(pfn), PAGE_SIZE, MEMREMAP_WB);
41+
if (!vaddr)
42+
return -ENOMEM;
43+
44+
if (userbuf) {
45+
if (copy_to_user((char __user *)buf, vaddr + offset, csize)) {
46+
memunmap(vaddr);
47+
return -EFAULT;
48+
}
49+
} else {
50+
memcpy(buf, vaddr + offset, csize);
51+
}
52+
53+
memunmap(vaddr);
54+
55+
return csize;
56+
}
57+
58+
/**
59+
* elfcorehdr_read - read from ELF core header
60+
* @buf: buffer where the data is placed
61+
* @csize: number of bytes to read
62+
* @ppos: address in the memory
63+
*
64+
* This function reads @count bytes from elf core header which exists
65+
* on crash dump kernel's memory.
66+
*/
67+
ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
68+
{
69+
memcpy(buf, phys_to_virt((phys_addr_t)*ppos), count);
70+
return count;
71+
}

arch/arm64/mm/init.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <linux/efi.h>
3737
#include <linux/swiotlb.h>
3838
#include <linux/kexec.h>
39+
#include <linux/crash_dump.h>
3940

4041
#include <asm/boot.h>
4142
#include <asm/fixmap.h>
@@ -163,6 +164,56 @@ static void __init kexec_reserve_crashkres_pages(void)
163164
}
164165
#endif /* CONFIG_KEXEC_CORE */
165166

167+
#ifdef CONFIG_CRASH_DUMP
168+
static int __init early_init_dt_scan_elfcorehdr(unsigned long node,
169+
const char *uname, int depth, void *data)
170+
{
171+
const __be32 *reg;
172+
int len;
173+
174+
if (depth != 1 || strcmp(uname, "chosen") != 0)
175+
return 0;
176+
177+
reg = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len);
178+
if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells)))
179+
return 1;
180+
181+
elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &reg);
182+
elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &reg);
183+
184+
return 1;
185+
}
186+
187+
/*
188+
* reserve_elfcorehdr() - reserves memory for elf core header
189+
*
190+
* This function reserves the memory occupied by an elf core header
191+
* described in the device tree. This region contains all the
192+
* information about primary kernel's core image and is used by a dump
193+
* capture kernel to access the system memory on primary kernel.
194+
*/
195+
static void __init reserve_elfcorehdr(void)
196+
{
197+
of_scan_flat_dt(early_init_dt_scan_elfcorehdr, NULL);
198+
199+
if (!elfcorehdr_size)
200+
return;
201+
202+
if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
203+
pr_warn("elfcorehdr is overlapped\n");
204+
return;
205+
}
206+
207+
memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
208+
209+
pr_info("Reserving %lldKB of memory at 0x%llx for elfcorehdr\n",
210+
elfcorehdr_size >> 10, elfcorehdr_addr);
211+
}
212+
#else
213+
static void __init reserve_elfcorehdr(void)
214+
{
215+
}
216+
#endif /* CONFIG_CRASH_DUMP */
166217
/*
167218
* Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It
168219
* currently assumes that for memory starting above 4G, 32-bit devices will
@@ -368,6 +419,8 @@ void __init arm64_memblock_init(void)
368419

369420
reserve_crashkernel();
370421

422+
reserve_elfcorehdr();
423+
371424
dma_contiguous_reserve(arm64_dma_phys_limit);
372425

373426
memblock_allow_resize();

0 commit comments

Comments
 (0)