diff options
author | AKASHI Takahiro <takahiro.akashi@linaro.org> | 2017-04-02 22:24:32 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2017-04-05 13:26:57 -0400 |
commit | 764b51ead10d5f428cb5f167bf98e336bdc23f8c (patch) | |
tree | 1f1d07162a5403a4b5d5d0305a167362d9e45d04 /arch/arm64/mm/init.c | |
parent | 8f579b1c4e347b23bfa747bc2cc0a55dd1b7e5fa (diff) |
arm64: kdump: reserve memory for crash dump kernel
"crashkernel=" kernel parameter specifies the size (and optionally
the start address) of the system ram to be used by crash dump kernel.
reserve_crashkernel() will allocate and reserve that memory at boot time
of primary kernel.
The memory range will be exposed to userspace as a resource named
"Crash kernel" in /proc/iomem.
Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Signed-off-by: Mark Salter <msalter@redhat.com>
Signed-off-by: Pratyush Anand <panand@redhat.com>
Reviewed-by: James Morse <james.morse@arm.com>
Acked-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'arch/arm64/mm/init.c')
-rw-r--r-- | arch/arm64/mm/init.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 290794b1a0f1..09d19207362d 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/gfp.h> | 30 | #include <linux/gfp.h> |
31 | #include <linux/memblock.h> | 31 | #include <linux/memblock.h> |
32 | #include <linux/sort.h> | 32 | #include <linux/sort.h> |
33 | #include <linux/of.h> | ||
33 | #include <linux/of_fdt.h> | 34 | #include <linux/of_fdt.h> |
34 | #include <linux/dma-mapping.h> | 35 | #include <linux/dma-mapping.h> |
35 | #include <linux/dma-contiguous.h> | 36 | #include <linux/dma-contiguous.h> |
@@ -37,6 +38,7 @@ | |||
37 | #include <linux/swiotlb.h> | 38 | #include <linux/swiotlb.h> |
38 | #include <linux/vmalloc.h> | 39 | #include <linux/vmalloc.h> |
39 | #include <linux/mm.h> | 40 | #include <linux/mm.h> |
41 | #include <linux/kexec.h> | ||
40 | 42 | ||
41 | #include <asm/boot.h> | 43 | #include <asm/boot.h> |
42 | #include <asm/fixmap.h> | 44 | #include <asm/fixmap.h> |
@@ -77,6 +79,67 @@ static int __init early_initrd(char *p) | |||
77 | early_param("initrd", early_initrd); | 79 | early_param("initrd", early_initrd); |
78 | #endif | 80 | #endif |
79 | 81 | ||
82 | #ifdef CONFIG_KEXEC_CORE | ||
83 | /* | ||
84 | * reserve_crashkernel() - reserves memory for crash kernel | ||
85 | * | ||
86 | * This function reserves memory area given in "crashkernel=" kernel command | ||
87 | * line parameter. The memory reserved is used by dump capture kernel when | ||
88 | * primary kernel is crashing. | ||
89 | */ | ||
90 | static void __init reserve_crashkernel(void) | ||
91 | { | ||
92 | unsigned long long crash_base, crash_size; | ||
93 | int ret; | ||
94 | |||
95 | ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(), | ||
96 | &crash_size, &crash_base); | ||
97 | /* no crashkernel= or invalid value specified */ | ||
98 | if (ret || !crash_size) | ||
99 | return; | ||
100 | |||
101 | crash_size = PAGE_ALIGN(crash_size); | ||
102 | |||
103 | if (crash_base == 0) { | ||
104 | /* Current arm64 boot protocol requires 2MB alignment */ | ||
105 | crash_base = memblock_find_in_range(0, ARCH_LOW_ADDRESS_LIMIT, | ||
106 | crash_size, SZ_2M); | ||
107 | if (crash_base == 0) { | ||
108 | pr_warn("cannot allocate crashkernel (size:0x%llx)\n", | ||
109 | crash_size); | ||
110 | return; | ||
111 | } | ||
112 | } else { | ||
113 | /* User specifies base address explicitly. */ | ||
114 | if (!memblock_is_region_memory(crash_base, crash_size)) { | ||
115 | pr_warn("cannot reserve crashkernel: region is not memory\n"); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | if (memblock_is_region_reserved(crash_base, crash_size)) { | ||
120 | pr_warn("cannot reserve crashkernel: region overlaps reserved memory\n"); | ||
121 | return; | ||
122 | } | ||
123 | |||
124 | if (!IS_ALIGNED(crash_base, SZ_2M)) { | ||
125 | pr_warn("cannot reserve crashkernel: base address is not 2MB aligned\n"); | ||
126 | return; | ||
127 | } | ||
128 | } | ||
129 | memblock_reserve(crash_base, crash_size); | ||
130 | |||
131 | pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n", | ||
132 | crash_base, crash_base + crash_size, crash_size >> 20); | ||
133 | |||
134 | crashk_res.start = crash_base; | ||
135 | crashk_res.end = crash_base + crash_size - 1; | ||
136 | } | ||
137 | #else | ||
138 | static void __init reserve_crashkernel(void) | ||
139 | { | ||
140 | } | ||
141 | #endif /* CONFIG_KEXEC_CORE */ | ||
142 | |||
80 | /* | 143 | /* |
81 | * Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It | 144 | * Return the maximum physical address for ZONE_DMA (DMA_BIT_MASK(32)). It |
82 | * currently assumes that for memory starting above 4G, 32-bit devices will | 145 | * currently assumes that for memory starting above 4G, 32-bit devices will |
@@ -332,6 +395,9 @@ void __init arm64_memblock_init(void) | |||
332 | arm64_dma_phys_limit = max_zone_dma_phys(); | 395 | arm64_dma_phys_limit = max_zone_dma_phys(); |
333 | else | 396 | else |
334 | arm64_dma_phys_limit = PHYS_MASK + 1; | 397 | arm64_dma_phys_limit = PHYS_MASK + 1; |
398 | |||
399 | reserve_crashkernel(); | ||
400 | |||
335 | dma_contiguous_reserve(arm64_dma_phys_limit); | 401 | dma_contiguous_reserve(arm64_dma_phys_limit); |
336 | 402 | ||
337 | memblock_allow_resize(); | 403 | memblock_allow_resize(); |