Skip to content

Commit 0ab9716

Browse files
Baoquan Heakpm00
authored andcommitted
crash_core: add generic function to do reservation
In architecture like x86_64, arm64 and riscv, they have vast virtual address space and usually have huge physical memory RAM. Their crashkernel reservation doesn't have to be limited under 4G RAM, but can be extended to the whole physical memory via crashkernel=,high support. Now add function reserve_crashkernel_generic() to reserve crashkernel memory if users specify any case of kernel pamameters, like crashkernel=xM[@offset] or crashkernel=,high|low. This is preparation to simplify code of crashkernel=,high support in architecutures. Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Baoquan He <[email protected]> Reviewed-by: Zhen Lei <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Chen Jiahao <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 70916e9 commit 0ab9716

File tree

2 files changed

+134
-1
lines changed

2 files changed

+134
-1
lines changed

include/linux/crash_core.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,34 @@ int parse_crashkernel_high(char *cmdline, unsigned long long system_ram,
9393
int parse_crashkernel_low(char *cmdline, unsigned long long system_ram,
9494
unsigned long long *crash_size, unsigned long long *crash_base);
9595

96+
#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
97+
#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
98+
#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
99+
#endif
100+
#ifndef CRASH_ALIGN
101+
#define CRASH_ALIGN SZ_2M
102+
#endif
103+
#ifndef CRASH_ADDR_LOW_MAX
104+
#define CRASH_ADDR_LOW_MAX SZ_4G
105+
#endif
106+
#ifndef CRASH_ADDR_HIGH_MAX
107+
#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM()
108+
#endif
109+
110+
void __init reserve_crashkernel_generic(char *cmdline,
111+
unsigned long long crash_size,
112+
unsigned long long crash_base,
113+
unsigned long long crash_low_size,
114+
bool high);
115+
#else
116+
static inline void __init reserve_crashkernel_generic(char *cmdline,
117+
unsigned long long crash_size,
118+
unsigned long long crash_base,
119+
unsigned long long crash_low_size,
120+
bool high)
121+
{}
122+
#endif
123+
96124
/* Alignment required for elf header segment */
97125
#define ELF_CORE_HEADER_ALIGN 4096
98126

kernel/crash_core.c

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55
*/
66

77
#include <linux/buildid.h>
8-
#include <linux/crash_core.h>
98
#include <linux/init.h>
109
#include <linux/utsname.h>
1110
#include <linux/vmalloc.h>
1211
#include <linux/sizes.h>
1312
#include <linux/kexec.h>
1413
#include <linux/memory.h>
1514
#include <linux/cpuhotplug.h>
15+
#include <linux/memblock.h>
16+
#include <linux/kexec.h>
17+
#include <linux/kmemleak.h>
1618

1719
#include <asm/page.h>
1820
#include <asm/sections.h>
@@ -360,6 +362,109 @@ static int __init parse_crashkernel_dummy(char *arg)
360362
}
361363
early_param("crashkernel", parse_crashkernel_dummy);
362364

365+
#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
366+
static int __init reserve_crashkernel_low(unsigned long long low_size)
367+
{
368+
#ifdef CONFIG_64BIT
369+
unsigned long long low_base;
370+
371+
low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
372+
if (!low_base) {
373+
pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
374+
return -ENOMEM;
375+
}
376+
377+
pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
378+
low_base, low_base + low_size, low_size >> 20);
379+
380+
crashk_low_res.start = low_base;
381+
crashk_low_res.end = low_base + low_size - 1;
382+
insert_resource(&iomem_resource, &crashk_low_res);
383+
#endif
384+
return 0;
385+
}
386+
387+
void __init reserve_crashkernel_generic(char *cmdline,
388+
unsigned long long crash_size,
389+
unsigned long long crash_base,
390+
unsigned long long crash_low_size,
391+
bool high)
392+
{
393+
unsigned long long search_end = CRASH_ADDR_LOW_MAX, search_base = 0;
394+
bool fixed_base = false;
395+
396+
/* User specifies base address explicitly. */
397+
if (crash_base) {
398+
fixed_base = true;
399+
search_base = crash_base;
400+
search_end = crash_base + crash_size;
401+
} else if (high) {
402+
search_base = CRASH_ADDR_LOW_MAX;
403+
search_end = CRASH_ADDR_HIGH_MAX;
404+
}
405+
406+
retry:
407+
crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
408+
search_base, search_end);
409+
if (!crash_base) {
410+
/*
411+
* For crashkernel=size[KMG]@offset[KMG], print out failure
412+
* message if can't reserve the specified region.
413+
*/
414+
if (fixed_base) {
415+
pr_warn("crashkernel reservation failed - memory is in use.\n");
416+
return;
417+
}
418+
419+
/*
420+
* For crashkernel=size[KMG], if the first attempt was for
421+
* low memory, fall back to high memory, the minimum required
422+
* low memory will be reserved later.
423+
*/
424+
if (!high && search_end == CRASH_ADDR_LOW_MAX) {
425+
search_end = CRASH_ADDR_HIGH_MAX;
426+
search_base = CRASH_ADDR_LOW_MAX;
427+
crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
428+
goto retry;
429+
}
430+
431+
/*
432+
* For crashkernel=size[KMG],high, if the first attempt was
433+
* for high memory, fall back to low memory.
434+
*/
435+
if (high && search_end == CRASH_ADDR_HIGH_MAX) {
436+
search_end = CRASH_ADDR_LOW_MAX;
437+
search_base = 0;
438+
goto retry;
439+
}
440+
pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
441+
crash_size);
442+
return;
443+
}
444+
445+
if ((crash_base > CRASH_ADDR_LOW_MAX) &&
446+
crash_low_size && reserve_crashkernel_low(crash_low_size)) {
447+
memblock_phys_free(crash_base, crash_size);
448+
return;
449+
}
450+
451+
pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
452+
crash_base, crash_base + crash_size, crash_size >> 20);
453+
454+
/*
455+
* The crashkernel memory will be removed from the kernel linear
456+
* map. Inform kmemleak so that it won't try to access it.
457+
*/
458+
kmemleak_ignore_phys(crash_base);
459+
if (crashk_low_res.end)
460+
kmemleak_ignore_phys(crashk_low_res.start);
461+
462+
crashk_res.start = crash_base;
463+
crashk_res.end = crash_base + crash_size - 1;
464+
insert_resource(&iomem_resource, &crashk_res);
465+
}
466+
#endif
467+
363468
int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
364469
void **addr, unsigned long *sz)
365470
{

0 commit comments

Comments
 (0)