Skip to content

Commit 944a45a

Browse files
Chen Zhouctmarinas
authored andcommitted
arm64: kdump: Reimplement crashkernel=X
There are following issues in arm64 kdump: 1. We use crashkernel=X to reserve crashkernel in DMA zone, which will fail when there is not enough low memory. 2. If reserving crashkernel above DMA zone, in this case, crash dump kernel will fail to boot because there is no low memory available for allocation. To solve these issues, introduce crashkernel=X,[high,low]. The "crashkernel=X,high" is used to select a region above DMA zone, and the "crashkernel=Y,low" is used to allocate specified size low memory. Signed-off-by: Chen Zhou <[email protected]> Co-developed-by: Zhen Lei <[email protected]> Signed-off-by: Zhen Lei <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent e6b3944 commit 944a45a

File tree

3 files changed

+74
-10
lines changed

3 files changed

+74
-10
lines changed

arch/arm64/kernel/machine_kexec.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,13 @@ bool crash_is_nosave(unsigned long pfn)
329329

330330
/* in reserved memory? */
331331
addr = __pfn_to_phys(pfn);
332-
if ((addr < crashk_res.start) || (crashk_res.end < addr))
333-
return false;
332+
if ((addr < crashk_res.start) || (crashk_res.end < addr)) {
333+
if (!crashk_low_res.end)
334+
return false;
335+
336+
if ((addr < crashk_low_res.start) || (crashk_low_res.end < addr))
337+
return false;
338+
}
334339

335340
if (!kexec_crash_image)
336341
return true;

arch/arm64/kernel/machine_kexec_file.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,18 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
6565

6666
/* Exclude crashkernel region */
6767
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
68+
if (ret)
69+
goto out;
70+
71+
if (crashk_low_res.end) {
72+
ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
73+
if (ret)
74+
goto out;
75+
}
6876

69-
if (!ret)
70-
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
77+
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
7178

79+
out:
7280
kfree(cmem);
7381
return ret;
7482
}

arch/arm64/mm/init.c

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,32 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
9090
phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
9191
#endif
9292

93+
/* Current arm64 boot protocol requires 2MB alignment */
94+
#define CRASH_ALIGN SZ_2M
95+
96+
#define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit
97+
#define CRASH_ADDR_HIGH_MAX (PHYS_MASK + 1)
98+
99+
static int __init reserve_crashkernel_low(unsigned long long low_size)
100+
{
101+
unsigned long long low_base;
102+
103+
low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
104+
if (!low_base) {
105+
pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
106+
return -ENOMEM;
107+
}
108+
109+
pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
110+
low_base, low_base + low_size, low_size >> 20);
111+
112+
crashk_low_res.start = low_base;
113+
crashk_low_res.end = low_base + low_size - 1;
114+
insert_resource(&iomem_resource, &crashk_low_res);
115+
116+
return 0;
117+
}
118+
93119
/*
94120
* reserve_crashkernel() - reserves memory for crash kernel
95121
*
@@ -100,33 +126,55 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit = PHYS_MASK + 1;
100126
static void __init reserve_crashkernel(void)
101127
{
102128
unsigned long long crash_base, crash_size;
103-
unsigned long long crash_max = arm64_dma_phys_limit;
129+
unsigned long long crash_low_size = 0;
130+
unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
131+
char *cmdline = boot_command_line;
104132
int ret;
105133

106134
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
107135
return;
108136

109-
ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
137+
/* crashkernel=X[@offset] */
138+
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
110139
&crash_size, &crash_base);
111-
/* no crashkernel= or invalid value specified */
112-
if (ret || !crash_size)
140+
if (ret == -ENOENT) {
141+
ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
142+
if (ret || !crash_size)
143+
return;
144+
145+
/*
146+
* crashkernel=Y,low can be specified or not, but invalid value
147+
* is not allowed.
148+
*/
149+
ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
150+
if (ret && (ret != -ENOENT))
151+
return;
152+
153+
crash_max = CRASH_ADDR_HIGH_MAX;
154+
} else if (ret || !crash_size) {
155+
/* The specified value is invalid */
113156
return;
157+
}
114158

115159
crash_size = PAGE_ALIGN(crash_size);
116160

117161
/* User specifies base address explicitly. */
118162
if (crash_base)
119163
crash_max = crash_base + crash_size;
120164

121-
/* Current arm64 boot protocol requires 2MB alignment */
122-
crash_base = memblock_phys_alloc_range(crash_size, SZ_2M,
165+
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
123166
crash_base, crash_max);
124167
if (!crash_base) {
125168
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
126169
crash_size);
127170
return;
128171
}
129172

173+
if (crash_low_size && reserve_crashkernel_low(crash_low_size)) {
174+
memblock_phys_free(crash_base, crash_size);
175+
return;
176+
}
177+
130178
pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
131179
crash_base, crash_base + crash_size, crash_size >> 20);
132180

@@ -135,6 +183,9 @@ static void __init reserve_crashkernel(void)
135183
* map. Inform kmemleak so that it won't try to access it.
136184
*/
137185
kmemleak_ignore_phys(crash_base);
186+
if (crashk_low_res.end)
187+
kmemleak_ignore_phys(crashk_low_res.start);
188+
138189
crashk_res.start = crash_base;
139190
crashk_res.end = crash_base + crash_size - 1;
140191
insert_resource(&iomem_resource, &crashk_res);

0 commit comments

Comments
 (0)