]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
arm64: kdump: provide /proc/vmcore file
authorAKASHI Takahiro <takahiro.akashi@linaro.org>
Mon, 3 Apr 2017 02:24:38 +0000 (11:24 +0900)
committerThadeu Lima de Souza Cascardo <cascardo@canonical.com>
Wed, 28 Jun 2017 14:24:13 +0000 (11:24 -0300)
BugLink: https://bugs.launchpad.net/bugs/1694859
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>
(backported from commit e62aaeac426ab1ddbdde524797b2a7835f606d91)
Signed-off-by: dann frazier <dann.frazier@canonical.com>
Acked-by: Stefan Bader <stefan.bader@canonical.com>
Acked-by: Colin King <colin.king@canonical.com>
Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
arch/arm64/Kconfig
arch/arm64/kernel/Makefile
arch/arm64/kernel/crash_dump.c [new file with mode: 0644]
arch/arm64/mm/init.c

index cae4e677a1818b9c223182a9d11a2b11398a84ac..b84e696a5c1b595bdc51a54d376c2bef4f840289 100644 (file)
@@ -732,6 +732,17 @@ config KEXEC
          but it is independent of the system firmware.   And like a reboot
          you can start any kernel with it, not just Linux.
 
+config CRASH_DUMP
+       bool "Build kdump crash kernel"
+       help
+         Generate crash dump after being started by kexec. This should
+         be normally only set in special crash dump kernels which are
+         loaded in the main kernel with kexec-tools into a specially
+         reserved region and then later executed after a crash by
+         kdump/kexec.
+
+         For more details see Documentation/kdump/kdump.txt
+
 config XEN_DOM0
        def_bool y
        depends on XEN
index 7d66bbaafc0c1c299cbf9ab109dedc1dbfdf9f7e..6a7384eee08d7421f8a5379a6ecc0929537af27b 100644 (file)
@@ -50,6 +50,7 @@ arm64-obj-$(CONFIG_RANDOMIZE_BASE)    += kaslr.o
 arm64-obj-$(CONFIG_HIBERNATION)                += hibernate.o hibernate-asm.o
 arm64-obj-$(CONFIG_KEXEC)              += machine_kexec.o relocate_kernel.o    \
                                           cpu-reset.o
+arm64-obj-$(CONFIG_CRASH_DUMP)         += crash_dump.o
 
 obj-y                                  += $(arm64-obj-y) vdso/ probes/
 obj-m                                  += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/crash_dump.c b/arch/arm64/kernel/crash_dump.c
new file mode 100644 (file)
index 0000000..f46d57c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Routines for doing kexec-based kdump
+ *
+ * Copyright (C) 2017 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/crash_dump.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/memblock.h>
+#include <linux/uaccess.h>
+#include <asm/memory.h>
+
+/**
+ * copy_oldmem_page() - copy one page from old kernel memory
+ * @pfn: page frame number to be copied
+ * @buf: buffer where the copied page is placed
+ * @csize: number of bytes to copy
+ * @offset: offset in bytes into the page
+ * @userbuf: if set, @buf is in a user address space
+ *
+ * This function copies one page from old kernel memory into buffer pointed by
+ * @buf. If @buf is in userspace, set @userbuf to %1. Returns number of bytes
+ * copied or negative error in case of failure.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+                        size_t csize, unsigned long offset,
+                        int userbuf)
+{
+       void *vaddr;
+
+       if (!csize)
+               return 0;
+
+       vaddr = memremap(__pfn_to_phys(pfn), PAGE_SIZE, MEMREMAP_WB);
+       if (!vaddr)
+               return -ENOMEM;
+
+       if (userbuf) {
+               if (copy_to_user((char __user *)buf, vaddr + offset, csize)) {
+                       memunmap(vaddr);
+                       return -EFAULT;
+               }
+       } else {
+               memcpy(buf, vaddr + offset, csize);
+       }
+
+       memunmap(vaddr);
+
+       return csize;
+}
+
+/**
+ * elfcorehdr_read - read from ELF core header
+ * @buf: buffer where the data is placed
+ * @csize: number of bytes to read
+ * @ppos: address in the memory
+ *
+ * This function reads @count bytes from elf core header which exists
+ * on crash dump kernel's memory.
+ */
+ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos)
+{
+       memcpy(buf, phys_to_virt((phys_addr_t)*ppos), count);
+       return count;
+}
index e4b422729a8a9e4829a0f4b599c29ffb8a68c63e..4036d30975dd62264d850fb5a8cb4a1495362e13 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/swiotlb.h>
 #include <linux/vmalloc.h>
 #include <linux/kexec.h>
+#include <linux/crash_dump.h>
 
 #include <asm/boot.h>
 #include <asm/fixmap.h>
@@ -164,6 +165,56 @@ static void __init kexec_reserve_crashkres_pages(void)
 }
 #endif /* CONFIG_KEXEC_CORE */
 
+#ifdef CONFIG_CRASH_DUMP
+static int __init early_init_dt_scan_elfcorehdr(unsigned long node,
+               const char *uname, int depth, void *data)
+{
+       const __be32 *reg;
+       int len;
+
+       if (depth != 1 || strcmp(uname, "chosen") != 0)
+               return 0;
+
+       reg = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len);
+       if (!reg || (len < (dt_root_addr_cells + dt_root_size_cells)))
+               return 1;
+
+       elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &reg);
+       elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &reg);
+
+       return 1;
+}
+
+/*
+ * reserve_elfcorehdr() - reserves memory for elf core header
+ *
+ * This function reserves the memory occupied by an elf core header
+ * described in the device tree. This region contains all the
+ * information about primary kernel's core image and is used by a dump
+ * capture kernel to access the system memory on primary kernel.
+ */
+static void __init reserve_elfcorehdr(void)
+{
+       of_scan_flat_dt(early_init_dt_scan_elfcorehdr, NULL);
+
+       if (!elfcorehdr_size)
+               return;
+
+       if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
+               pr_warn("elfcorehdr is overlapped\n");
+               return;
+       }
+
+       memblock_reserve(elfcorehdr_addr, elfcorehdr_size);
+
+       pr_info("Reserving %lldKB of memory at 0x%llx for elfcorehdr\n",
+               elfcorehdr_size >> 10, elfcorehdr_addr);
+}
+#else
+static void __init reserve_elfcorehdr(void)
+{
+}
+#endif /* CONFIG_CRASH_DUMP */
 /*
  * Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It
  * currently assumes that for memory starting above 4G, 32-bit devices will
@@ -422,6 +473,8 @@ void __init arm64_memblock_init(void)
 
        reserve_crashkernel();
 
+       reserve_elfcorehdr();
+
        dma_contiguous_reserve(arm64_dma_phys_limit);
 
        memblock_allow_resize();