In the current arm64, crashkernel=,high support has been finished after
several rounds of posting and careful reviewing. The code in arm64 which
parses crashkernel kernel parameters firstly, then reserve memory can be
a good example for other ARCH to refer to.
Whereas in x86_64, the code mixing crashkernel parameter parsing and
memory reserving is twisted, and looks messy. Refactoring the code to
make it more readable maintainable is necessary.
Here, firstly abstract the crashkernel parameter parsing code into
parse_crashkernel() to make it be able to parse crashkernel=,high|low.
Then abstract the crashkernel memory reserving code into a generic
function reserve_crashkernel_generic(). Finally, in ARCH which
crashkernel=,high support is needed, a simple arch_reserve_crashkernel()
can be added to call above two functions. This can remove the duplicated
implmentation code in each ARCH, like arm64, x86_64 and riscv.
I only did testing on x86_64 and arm64 for below cases, haven't tested
riscv. If riscv people can help apply the patchset and give it a shot,
it would be great.
crashkernel=512M,high
crashkernel=512M,high crashkernel=256M,low
crashkernel=512M,high crashkernel=0M,low
crashkernel=0M,high crashkernel=256M,low
crashkernel=512M
crashkernel=512M@0x4f000000
crashkernel=1G-4G:256M,4G-64G:320M,64G-:576M
crashkernel=0M
History:
v2->v3:
- Move crashk_res and crashk_low_res codes into crash_core.c, and add
<asm/crash_core.h> including in <linux/crash_core.h>. These two fix
compiling error reported by LKP when CONFIG_CRASH_CORE=on while
CONFIG_KEXEC_CORE is unset.
- Adjust the if-else and return logic in parse_crashkernel() according
to Lei's suggestion.
- Make riscv use the generic interface to simplify crahskernel
reservation code too since crashkernel=,high support has been added
into riscv.
- Some minor changes suggested by Lei.
v1->v2:
- Change to add asm/crash_core.h into x86 and arm64 to contain those
arch specific macro definitions for generic reservaton. This fixes the
compiling error reported by LKP in v1.
https://lore.kernel.org/all/[email protected]/T/#u
- Fix a log typo in patch 8, thanks to Samuel.
- RFC->v1:
https://lore.kernel.org/all/[email protected]/T/#u
[RFC PATCH 0/4] kdump: add generic functions to simplify crashkernel crashkernel in architecture
Dave and Philipp commented the old parse_crashkernel_common() and
parse_crashkernel_generic() are quite confusing. In this formal post,
I made change to address the concern by unifying all crashkernel
parsing into parse_crashkernel().
Baoquan He (9):
crash_core.c: remove unnecessary parameter of function
crash_core: change the prototype of function parse_crashkernel()
crash_core: change parse_crashkernel() to support
crashkernel=,high|low parsing
crash_core: add generic function to do reservation
crash_core: move crashk_*res definition into crash_core.c
x86: kdump: use generic interface to simplify crashkernel reservation
code
arm64: kdump: use generic interface to simplify crashkernel
reservation
riscv: kdump: use generic interface to simplify crashkernel
reservation
crash_core.c: remove unneeded functions
arch/arm/kernel/setup.c | 3 +-
arch/arm64/Kconfig | 3 +
arch/arm64/include/asm/crash_core.h | 10 ++
arch/arm64/mm/init.c | 140 ++------------------
arch/ia64/kernel/setup.c | 2 +-
arch/loongarch/kernel/setup.c | 4 +-
arch/mips/kernel/setup.c | 3 +-
arch/powerpc/kernel/fadump.c | 2 +-
arch/powerpc/kexec/core.c | 2 +-
arch/powerpc/mm/nohash/kaslr_booke.c | 2 +-
arch/riscv/Kconfig | 3 +
arch/riscv/include/asm/crash_core.h | 11 ++
arch/riscv/include/asm/processor.h | 2 +
arch/riscv/mm/init.c | 141 ++------------------
arch/s390/kernel/setup.c | 4 +-
arch/sh/kernel/machine_kexec.c | 2 +-
arch/x86/Kconfig | 3 +
arch/x86/include/asm/crash_core.h | 34 +++++
arch/x86/kernel/setup.c | 143 +++------------------
include/linux/crash_core.h | 49 ++++++-
include/linux/kexec.h | 4 -
kernel/crash_core.c | 184 ++++++++++++++++++++++++---
kernel/kexec_core.c | 17 ---
23 files changed, 321 insertions(+), 447 deletions(-)
create mode 100644 arch/arm64/include/asm/crash_core.h
create mode 100644 arch/riscv/include/asm/crash_core.h
create mode 100644 arch/x86/include/asm/crash_core.h
--
2.41.0
With the help of newly changed function parse_crashkernel() and
generic reserve_crashkernel_generic(), crashkernel reservation can be
simplified by steps:
1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
reserve_crashkernel_generic();
3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
arch/arm64/Kconfig.
The old reserve_crashkernel_low() and reserve_crashkernel() can be
removed.
Signed-off-by: Baoquan He <[email protected]>
Reviewed-by: Zhen Lei <[email protected]>
---
arch/arm64/Kconfig | 3 +
arch/arm64/include/asm/crash_core.h | 10 ++
arch/arm64/mm/init.c | 140 ++--------------------------
3 files changed, 21 insertions(+), 132 deletions(-)
create mode 100644 arch/arm64/include/asm/crash_core.h
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b10515c0200b..e7d374d994ad 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1483,6 +1483,9 @@ config ARCH_DEFAULT_KEXEC_IMAGE_VERIFY_SIG
config ARCH_SUPPORTS_CRASH_DUMP
def_bool y
+config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+ def_bool CRASH_CORE
+
config TRANS_TABLE
def_bool y
depends on HIBERNATION || KEXEC_CORE
diff --git a/arch/arm64/include/asm/crash_core.h b/arch/arm64/include/asm/crash_core.h
new file mode 100644
index 000000000000..9f5c8d339f44
--- /dev/null
+++ b/arch/arm64/include/asm/crash_core.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ARM64_CRASH_CORE_H
+#define _ARM64_CRASH_CORE_H
+
+/* Current arm64 boot protocol requires 2MB alignment */
+#define CRASH_ALIGN SZ_2M
+
+#define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit
+#define CRASH_ADDR_HIGH_MAX (PHYS_MASK + 1)
+#endif
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 801c59c39a8f..f2bf32e19371 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -64,15 +64,6 @@ EXPORT_SYMBOL(memstart_addr);
*/
phys_addr_t __ro_after_init arm64_dma_phys_limit;
-/* Current arm64 boot protocol requires 2MB alignment */
-#define CRASH_ALIGN SZ_2M
-
-#define CRASH_ADDR_LOW_MAX arm64_dma_phys_limit
-#define CRASH_ADDR_HIGH_MAX (PHYS_MASK + 1)
-#define CRASH_HIGH_SEARCH_BASE SZ_4G
-
-#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
-
/*
* To make optimal use of block mappings when laying out the linear
* mapping, round down the base of physical memory to a size that can
@@ -100,140 +91,25 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
#define ARM64_MEMSTART_ALIGN (1UL << ARM64_MEMSTART_SHIFT)
#endif
-static int __init reserve_crashkernel_low(unsigned long long low_size)
-{
- unsigned long long low_base;
-
- low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
- if (!low_base) {
- pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
- return -ENOMEM;
- }
-
- pr_info("crashkernel low memory reserved: 0x%08llx - 0x%08llx (%lld MB)\n",
- low_base, low_base + low_size, low_size >> 20);
-
- crashk_low_res.start = low_base;
- crashk_low_res.end = low_base + low_size - 1;
- insert_resource(&iomem_resource, &crashk_low_res);
-
- return 0;
-}
-
-/*
- * reserve_crashkernel() - reserves memory for crash kernel
- *
- * This function reserves memory area given in "crashkernel=" kernel command
- * line parameter. The memory reserved is used by dump capture kernel when
- * primary kernel is crashing.
- */
-static void __init reserve_crashkernel(void)
+static void __init arch_reserve_crashkernel(void)
{
- unsigned long long crash_low_size = 0, search_base = 0;
- unsigned long long crash_max = CRASH_ADDR_LOW_MAX;
+ unsigned long long low_size = 0;
unsigned long long crash_base, crash_size;
char *cmdline = boot_command_line;
- bool fixed_base = false;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
- /* crashkernel=X[@offset] */
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
- &crash_size, &crash_base, NULL, NULL);
- if (ret == -ENOENT) {
- ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
- if (ret || !crash_size)
- return;
-
- /*
- * crashkernel=Y,low can be specified or not, but invalid value
- * is not allowed.
- */
- ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
- if (ret == -ENOENT)
- crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
- else if (ret)
- return;
-
- search_base = CRASH_HIGH_SEARCH_BASE;
- crash_max = CRASH_ADDR_HIGH_MAX;
- high = true;
- } else if (ret || !crash_size) {
- /* The specified value is invalid */
+ &crash_size, &crash_base,
+ &low_size, &high);
+ if (ret)
return;
- }
-
- crash_size = PAGE_ALIGN(crash_size);
-
- /* User specifies base address explicitly. */
- if (crash_base) {
- fixed_base = true;
- search_base = crash_base;
- crash_max = crash_base + crash_size;
- }
-
-retry:
- crash_base = memblock_phys_alloc_range(crash_size, CRASH_ALIGN,
- search_base, crash_max);
- if (!crash_base) {
- /*
- * For crashkernel=size[KMG]@offset[KMG], print out failure
- * message if can't reserve the specified region.
- */
- if (fixed_base) {
- pr_warn("crashkernel reservation failed - memory is in use.\n");
- return;
- }
-
- /*
- * For crashkernel=size[KMG], if the first attempt was for
- * low memory, fall back to high memory, the minimum required
- * low memory will be reserved later.
- */
- if (!high && crash_max == CRASH_ADDR_LOW_MAX) {
- crash_max = CRASH_ADDR_HIGH_MAX;
- search_base = CRASH_ADDR_LOW_MAX;
- crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
- goto retry;
- }
-
- /*
- * For crashkernel=size[KMG],high, if the first attempt was
- * for high memory, fall back to low memory.
- */
- if (high && crash_max == CRASH_ADDR_HIGH_MAX) {
- crash_max = CRASH_ADDR_LOW_MAX;
- search_base = 0;
- goto retry;
- }
- pr_warn("cannot allocate crashkernel (size:0x%llx)\n",
- crash_size);
- return;
- }
-
- if ((crash_base >= CRASH_ADDR_LOW_MAX) && crash_low_size &&
- reserve_crashkernel_low(crash_low_size)) {
- memblock_phys_free(crash_base, crash_size);
- return;
- }
-
- pr_info("crashkernel reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
- crash_base, crash_base + crash_size, crash_size >> 20);
-
- /*
- * The crashkernel memory will be removed from the kernel linear
- * map. Inform kmemleak so that it won't try to access it.
- */
- kmemleak_ignore_phys(crash_base);
- if (crashk_low_res.end)
- kmemleak_ignore_phys(crashk_low_res.start);
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
- insert_resource(&iomem_resource, &crashk_res);
+ reserve_crashkernel_generic(cmdline, crash_size, crash_base,
+ low_size, high);
}
/*
@@ -479,7 +355,7 @@ void __init bootmem_init(void)
* request_standard_resources() depends on crashkernel's memory being
* reserved, so do it here.
*/
- reserve_crashkernel();
+ arch_reserve_crashkernel();
memblock_dump_all();
}
--
2.41.0
With the help of newly changed function parse_crashkernel() and
generic reserve_crashkernel_generic(), crashkernel reservation can be
simplified by steps:
1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
reserve_crashkernel_generic(), and do the ARCH specific work if
needed.
3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
arch/x86/Kconfig.
When adding DEFAULT_CRASH_KERNEL_LOW_SIZE, add crash_low_size_default()
to calculate crashkernel low memory because x86_64 has special
requirement.
The old reserve_crashkernel_low() and reserve_crashkernel() can be
removed.
Signed-off-by: Baoquan He <[email protected]>
---
arch/x86/Kconfig | 3 +
arch/x86/include/asm/crash_core.h | 34 +++++++
arch/x86/kernel/setup.c | 144 ++++--------------------------
3 files changed, 52 insertions(+), 129 deletions(-)
create mode 100644 arch/x86/include/asm/crash_core.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 982b777eadc7..d5ebb2ad2ad6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2062,6 +2062,9 @@ config ARCH_SUPPORTS_CRASH_DUMP
config ARCH_SUPPORTS_CRASH_HOTPLUG
def_bool y
+config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+ def_bool CRASH_CORE
+
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP)
default "0x1000000"
diff --git a/arch/x86/include/asm/crash_core.h b/arch/x86/include/asm/crash_core.h
new file mode 100644
index 000000000000..5fc5e4f94521
--- /dev/null
+++ b/arch/x86/include/asm/crash_core.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _X86_CRASH_CORE_H
+#define _X86_CRASH_CORE_H
+
+/* 16M alignment for crash kernel regions */
+#define CRASH_ALIGN SZ_16M
+
+/*
+ * Keep the crash kernel below this limit.
+ *
+ * Earlier 32-bits kernels would limit the kernel to the low 512 MB range
+ * due to mapping restrictions.
+ *
+ * 64-bit kdump kernels need to be restricted to be under 64 TB, which is
+ * the upper limit of system RAM in 4-level paging mode. Since the kdump
+ * jump could be from 5-level paging to 4-level paging, the jump will fail if
+ * the kernel is put above 64 TB, and during the 1st kernel bootup there's
+ * no good way to detect the paging mode of the target kernel which will be
+ * loaded for dumping.
+ */
+
+#ifdef CONFIG_X86_32
+# define CRASH_ADDR_LOW_MAX SZ_512M
+# define CRASH_ADDR_HIGH_MAX SZ_512M
+#else
+# define CRASH_ADDR_LOW_MAX SZ_4G
+# define CRASH_ADDR_HIGH_MAX SZ_64T
+#endif
+
+# define DEFAULT_CRASH_KERNEL_LOW_SIZE crash_low_size_default()
+
+extern unsigned long crash_low_size_default(void);
+
+#endif /* _X86_CRASH_CORE_H */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f945d88215b4..0acc86587fc0 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -473,152 +473,38 @@ static void __init memblock_x86_reserve_range_setup_data(void)
/*
* --------- Crashkernel reservation ------------------------------
*/
-
-/* 16M alignment for crash kernel regions */
-#define CRASH_ALIGN SZ_16M
-
-/*
- * Keep the crash kernel below this limit.
- *
- * Earlier 32-bits kernels would limit the kernel to the low 512 MB range
- * due to mapping restrictions.
- *
- * 64-bit kdump kernels need to be restricted to be under 64 TB, which is
- * the upper limit of system RAM in 4-level paging mode. Since the kdump
- * jump could be from 5-level paging to 4-level paging, the jump will fail if
- * the kernel is put above 64 TB, and during the 1st kernel bootup there's
- * no good way to detect the paging mode of the target kernel which will be
- * loaded for dumping.
- */
-#ifdef CONFIG_X86_32
-# define CRASH_ADDR_LOW_MAX SZ_512M
-# define CRASH_ADDR_HIGH_MAX SZ_512M
-#else
-# define CRASH_ADDR_LOW_MAX SZ_4G
-# define CRASH_ADDR_HIGH_MAX SZ_64T
-#endif
-
-static int __init reserve_crashkernel_low(void)
+unsigned long crash_low_size_default(void)
{
#ifdef CONFIG_X86_64
- unsigned long long base, low_base = 0, low_size = 0;
- unsigned long low_mem_limit;
- int ret;
-
- low_mem_limit = min(memblock_phys_mem_size(), CRASH_ADDR_LOW_MAX);
-
- /* crashkernel=Y,low */
- ret = parse_crashkernel_low(boot_command_line, low_mem_limit, &low_size, &base);
- if (ret) {
- /*
- * two parts from kernel/dma/swiotlb.c:
- * -swiotlb size: user-specified with swiotlb= or default.
- *
- * -swiotlb overflow buffer: now hardcoded to 32k. We round it
- * to 8M for other buffers that may need to stay low too. Also
- * make sure we allocate enough extra low memory so that we
- * don't run out of DMA buffers for 32-bit devices.
- */
- low_size = max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
- } else {
- /* passed with crashkernel=0,low ? */
- if (!low_size)
- return 0;
- }
-
- low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
- if (!low_base) {
- pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n",
- (unsigned long)(low_size >> 20));
- return -ENOMEM;
- }
-
- pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (low RAM limit: %ldMB)\n",
- (unsigned long)(low_size >> 20),
- (unsigned long)(low_base >> 20),
- (unsigned long)(low_mem_limit >> 20));
-
- crashk_low_res.start = low_base;
- crashk_low_res.end = low_base + low_size - 1;
- insert_resource(&iomem_resource, &crashk_low_res);
-#endif
+ return max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
+#else
return 0;
+#endif
}
-static void __init reserve_crashkernel(void)
+static void __init arch_reserve_crashkernel(void)
{
- unsigned long long crash_size, crash_base, total_mem;
+ unsigned long long crash_base, crash_size, low_size = 0;
+ char *cmdline = boot_command_line;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
- total_mem = memblock_phys_mem_size();
-
- /* crashkernel=XM */
- ret = parse_crashkernel(boot_command_line, total_mem,
- &crash_size, &crash_base, NULL, NULL);
- if (ret != 0 || crash_size <= 0) {
- /* crashkernel=X,high */
- ret = parse_crashkernel_high(boot_command_line, total_mem,
- &crash_size, &crash_base);
- if (ret != 0 || crash_size <= 0)
- return;
- high = true;
- }
+ ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
+ &crash_size, &crash_base,
+ &low_size, &high);
+ if (ret)
+ return;
if (xen_pv_domain()) {
pr_info("Ignoring crashkernel for a Xen PV domain\n");
return;
}
- /* 0 means: find the address automatically */
- if (!crash_base) {
- /*
- * Set CRASH_ADDR_LOW_MAX upper bound for crash memory,
- * crashkernel=x,high reserves memory over 4G, also allocates
- * 256M extra low memory for DMA buffers and swiotlb.
- * But the extra memory is not required for all machines.
- * So try low memory first and fall back to high memory
- * unless "crashkernel=size[KMG],high" is specified.
- */
- if (!high)
- crash_base = memblock_phys_alloc_range(crash_size,
- CRASH_ALIGN, CRASH_ALIGN,
- CRASH_ADDR_LOW_MAX);
- if (!crash_base)
- crash_base = memblock_phys_alloc_range(crash_size,
- CRASH_ALIGN, CRASH_ALIGN,
- CRASH_ADDR_HIGH_MAX);
- if (!crash_base) {
- pr_info("crashkernel reservation failed - No suitable area found.\n");
- return;
- }
- } else {
- unsigned long long start;
-
- start = memblock_phys_alloc_range(crash_size, SZ_1M, crash_base,
- crash_base + crash_size);
- if (start != crash_base) {
- pr_info("crashkernel reservation failed - memory is in use.\n");
- return;
- }
- }
-
- if (crash_base >= (1ULL << 32) && reserve_crashkernel_low()) {
- memblock_phys_free(crash_base, crash_size);
- return;
- }
-
- pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
- (unsigned long)(crash_size >> 20),
- (unsigned long)(crash_base >> 20),
- (unsigned long)(total_mem >> 20));
-
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
- insert_resource(&iomem_resource, &crashk_res);
+ reserve_crashkernel_generic(cmdline, crash_size, crash_base,
+ low_size, high);
}
static struct resource standard_io_resources[] = {
@@ -1232,7 +1118,7 @@ void __init setup_arch(char **cmdline_p)
* Reserve memory for crash kernel after SRAT is parsed so that it
* won't consume hotpluggable memory.
*/
- reserve_crashkernel();
+ arch_reserve_crashkernel();
memblock_find_dma_reserve();
--
2.41.0
Now parse_crashkernel() is a real entry point for all kinds of
crahskernel parsing on any architecture.
And wrap the crahskernel=,high|low handling inside
CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION ifdeffery scope.
Signed-off-by: Baoquan He <[email protected]>
---
include/linux/crash_core.h | 6 ++++++
kernel/crash_core.c | 36 +++++++++++++++++++++++++++++++++---
2 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index 6156355ef831..d8050a7eab01 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -79,6 +79,12 @@ Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
void *data, size_t data_len);
void final_note(Elf_Word *buf);
+#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
+#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
+#endif
+#endif
+
int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
unsigned long long *crash_size, unsigned long long *crash_base,
unsigned long long *low_size, bool *high);
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index cca1d76e8255..dce2f5874fea 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -283,6 +283,9 @@ static int __init __parse_crashkernel(char *cmdline,
/*
* That function is the entry point for command line parsing and should be
* called from the arch-specific code.
+ *
+ * If crashkernel=,high|low is supported on architecture, non-NULL values
+ * should be passed to parameters 'low_size' and 'high'.
*/
int __init parse_crashkernel(char *cmdline,
unsigned long long system_ram,
@@ -296,10 +299,37 @@ int __init parse_crashkernel(char *cmdline,
/* crashkernel=X[@offset] */
ret = __parse_crashkernel(cmdline, system_ram, crash_size,
crash_base, NULL);
- if (!high)
- return ret;
+#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+ /*
+ * If non-NULL 'high' passed in and no normal crashkernel
+ * setting detected, try parsing crashkernel=,high|low.
+ */
+ if (high && ret == -ENOENT) {
+ ret = __parse_crashkernel(cmdline, 0, crash_size,
+ crash_base, suffix_tbl[SUFFIX_HIGH]);
+ if (ret || !*crash_size)
+ return -EINVAL;
- return 0;
+ /*
+ * crashkernel=Y,low can be specified or not, but invalid value
+ * is not allowed.
+ */
+ ret = __parse_crashkernel(cmdline, 0, low_size,
+ crash_base, suffix_tbl[SUFFIX_LOW]);
+ if (ret == -ENOENT) {
+ *low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
+ ret = 0;
+ } else if (ret) {
+ return ret;
+ }
+
+ *high = true;
+ }
+#endif
+ if (!*crash_size)
+ ret = -EINVAL;
+
+ return ret;
}
int __init parse_crashkernel_high(char *cmdline,
--
2.41.0
With the help of newly changed function parse_crashkernel() and
generic reserve_crashkernel_generic(), crashkernel reservation can be
simplified by steps:
1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
reserve_crashkernel_generic();
3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
arch/riscv/Kconfig.
The old reserve_crashkernel_low() and reserve_crashkernel() can be
removed.
Signed-off-by: Baoquan He <[email protected]>
---
arch/riscv/Kconfig | 3 +
arch/riscv/include/asm/crash_core.h | 11 +++
arch/riscv/include/asm/processor.h | 2 +
arch/riscv/mm/init.c | 141 +++-------------------------
4 files changed, 27 insertions(+), 130 deletions(-)
create mode 100644 arch/riscv/include/asm/crash_core.h
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d607ab0f7c6d..25474f8c12b7 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -694,6 +694,9 @@ config ARCH_SUPPORTS_KEXEC_PURGATORY
config ARCH_SUPPORTS_CRASH_DUMP
def_bool y
+config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+ def_bool CRASH_CORE
+
config COMPAT
bool "Kernel support for 32-bit U-mode"
default 64BIT
diff --git a/arch/riscv/include/asm/crash_core.h b/arch/riscv/include/asm/crash_core.h
new file mode 100644
index 000000000000..e1874b23feaf
--- /dev/null
+++ b/arch/riscv/include/asm/crash_core.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _RISCV_CRASH_CORE_H
+#define _RISCV_CRASH_CORE_H
+
+#define CRASH_ALIGN PMD_SIZE
+
+#define CRASH_ADDR_LOW_MAX dma32_phys_limit
+#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM()
+
+extern phys_addr_t memblock_end_of_DRAM(void);
+#endif
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 3e23e1786d05..441da1839c94 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -116,6 +116,8 @@ static inline void wait_for_interrupt(void)
__asm__ __volatile__ ("wfi");
}
+extern phys_addr_t dma32_phys_limit;
+
struct device_node;
int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid);
int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid);
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 9fe448900059..d9a4e8702864 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -65,7 +65,7 @@ extern char _start[];
void *_dtb_early_va __initdata;
uintptr_t _dtb_early_pa __initdata;
-static phys_addr_t dma32_phys_limit __initdata;
+phys_addr_t dma32_phys_limit __initdata;
static void __init zone_sizes_init(void)
{
@@ -1333,28 +1333,6 @@ static inline void setup_vm_final(void)
}
#endif /* CONFIG_MMU */
-/* Reserve 128M low memory by default for swiotlb buffer */
-#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
-
-static int __init reserve_crashkernel_low(unsigned long long low_size)
-{
- unsigned long long low_base;
-
- low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit);
- if (!low_base) {
- pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
- return -ENOMEM;
- }
-
- pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
- low_base, low_base + low_size, low_size >> 20);
-
- crashk_low_res.start = low_base;
- crashk_low_res.end = low_base + low_size - 1;
-
- return 0;
-}
-
/*
* reserve_crashkernel() - reserves memory for crash kernel
*
@@ -1362,122 +1340,25 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
* line parameter. The memory reserved is used by dump capture kernel when
* primary kernel is crashing.
*/
-static void __init reserve_crashkernel(void)
+static void __init arch_reserve_crashkernel(void)
{
- unsigned long long crash_base = 0;
- unsigned long long crash_size = 0;
- unsigned long long crash_low_size = 0;
- unsigned long search_start = memblock_start_of_DRAM();
- unsigned long search_end = (unsigned long)dma32_phys_limit;
+ unsigned long long low_size = 0;
+ unsigned long long crash_base, crash_size;
char *cmdline = boot_command_line;
- bool fixed_base = false;
bool high = false;
-
- int ret = 0;
+ int ret;
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
- /*
- * Don't reserve a region for a crash kernel on a crash kernel
- * since it doesn't make much sense and we have limited memory
- * resources.
- */
- if (is_kdump_kernel()) {
- pr_info("crashkernel: ignoring reservation request\n");
- return;
- }
ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
- &crash_size, &crash_base, NULL, NULL);
- if (ret == -ENOENT) {
- /* Fallback to crashkernel=X,[high,low] */
- ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
- if (ret || !crash_size)
- return;
-
- /*
- * crashkernel=Y,low is valid only when crashkernel=X,high
- * is passed.
- */
- ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
- if (ret == -ENOENT)
- crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
- else if (ret)
- return;
-
- search_start = (unsigned long)dma32_phys_limit;
- search_end = memblock_end_of_DRAM();
- high = true;
- } else if (ret || !crash_size) {
- /* Invalid argument value specified */
+ &crash_size, &crash_base,
+ &low_size, &high);
+ if (ret)
return;
- }
-
- crash_size = PAGE_ALIGN(crash_size);
-
- if (crash_base) {
- fixed_base = true;
- search_start = crash_base;
- search_end = crash_base + crash_size;
- }
-
- /*
- * Current riscv boot protocol requires 2MB alignment for
- * RV64 and 4MB alignment for RV32 (hugepage size)
- *
- * Try to alloc from 32bit addressible physical memory so that
- * swiotlb can work on the crash kernel.
- */
- crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
- search_start, search_end);
- if (crash_base == 0) {
- /*
- * For crashkernel=size[KMG]@offset[KMG], print out failure
- * message if can't reserve the specified region.
- */
- if (fixed_base) {
- pr_warn("crashkernel: allocating failed with given size@offset\n");
- return;
- }
-
- if (high) {
- /*
- * For crashkernel=size[KMG],high, if the first attempt was
- * for high memory, fall back to low memory.
- */
- search_start = memblock_start_of_DRAM();
- search_end = (unsigned long)dma32_phys_limit;
- } else {
- /*
- * For crashkernel=size[KMG], if the first attempt was for
- * low memory, fall back to high memory, the minimum required
- * low memory will be reserved later.
- */
- search_start = (unsigned long)dma32_phys_limit;
- search_end = memblock_end_of_DRAM();
- crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
- }
-
- crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
- search_start, search_end);
- if (crash_base == 0) {
- pr_warn("crashkernel: couldn't allocate %lldKB\n",
- crash_size >> 10);
- return;
- }
- }
-
- if ((crash_base >= dma32_phys_limit) && crash_low_size &&
- reserve_crashkernel_low(crash_low_size)) {
- memblock_phys_free(crash_base, crash_size);
- return;
- }
-
- pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n",
- crash_base, crash_base + crash_size, crash_size >> 20);
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
+ reserve_crashkernel_generic(cmdline, crash_size, crash_base,
+ low_size, high);
}
void __init paging_init(void)
@@ -1495,7 +1376,7 @@ void __init misc_mem_init(void)
arch_numa_init();
sparse_init();
zone_sizes_init();
- reserve_crashkernel();
+ arch_reserve_crashkernel();
memblock_dump_all();
}
--
2.41.0
In all call sites of __parse_crashkernel(), the parameter 'name' is
hardcoded as "crashkernel=". So remove the unnecessary parameter 'name',
add local varibale 'name' inside __parse_crashkernel() instead.
Signed-off-by: Baoquan He <[email protected]>
Reviewed-by: Zhen Lei <[email protected]>
---
kernel/crash_core.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 03a7932cde0a..c9695204715d 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -248,11 +248,11 @@ static int __init __parse_crashkernel(char *cmdline,
unsigned long long system_ram,
unsigned long long *crash_size,
unsigned long long *crash_base,
- const char *name,
const char *suffix)
{
char *first_colon, *first_space;
char *ck_cmdline;
+ char *name = "crashkernel=";
BUG_ON(!crash_size || !crash_base);
*crash_size = 0;
@@ -290,7 +290,7 @@ int __init parse_crashkernel(char *cmdline,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
- "crashkernel=", NULL);
+ NULL);
}
int __init parse_crashkernel_high(char *cmdline,
@@ -299,7 +299,7 @@ int __init parse_crashkernel_high(char *cmdline,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
- "crashkernel=", suffix_tbl[SUFFIX_HIGH]);
+ suffix_tbl[SUFFIX_HIGH]);
}
int __init parse_crashkernel_low(char *cmdline,
@@ -308,7 +308,7 @@ int __init parse_crashkernel_low(char *cmdline,
unsigned long long *crash_base)
{
return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base,
- "crashkernel=", suffix_tbl[SUFFIX_LOW]);
+ suffix_tbl[SUFFIX_LOW]);
}
/*
--
2.41.0
With the help of newly changed function parse_crashkernel() and
generic reserve_crashkernel_generic(), crashkernel reservation can be
simplified by steps:
1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
reserve_crashkernel_generic(), and do the ARCH specific work if
needed.
3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
arch/x86/Kconfig.
When adding DEFAULT_CRASH_KERNEL_LOW_SIZE, add crash_low_size_default()
to calculate crashkernel low memory because x86_64 has special
requirement.
The old reserve_crashkernel_low() and reserve_crashkernel() can be
removed.
Signed-off-by: Baoquan He <[email protected]>
---
v3->v4:
Move crash_low_size_default() to <asm/crash_core.h> to make it a
static inline function. This fixes the warning reported by LKP.
arch/x86/Kconfig | 3 +
arch/x86/include/asm/crash_core.h | 42 +++++++++
arch/x86/kernel/setup.c | 148 +++---------------------------
3 files changed, 56 insertions(+), 137 deletions(-)
create mode 100644 arch/x86/include/asm/crash_core.h
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 982b777eadc7..d5ebb2ad2ad6 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -2062,6 +2062,9 @@ config ARCH_SUPPORTS_CRASH_DUMP
config ARCH_SUPPORTS_CRASH_HOTPLUG
def_bool y
+config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
+ def_bool CRASH_CORE
+
config PHYSICAL_START
hex "Physical address where the kernel is loaded" if (EXPERT || CRASH_DUMP)
default "0x1000000"
diff --git a/arch/x86/include/asm/crash_core.h b/arch/x86/include/asm/crash_core.h
new file mode 100644
index 000000000000..76af98f4e801
--- /dev/null
+++ b/arch/x86/include/asm/crash_core.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _X86_CRASH_CORE_H
+#define _X86_CRASH_CORE_H
+
+/* 16M alignment for crash kernel regions */
+#define CRASH_ALIGN SZ_16M
+
+/*
+ * Keep the crash kernel below this limit.
+ *
+ * Earlier 32-bits kernels would limit the kernel to the low 512 MB range
+ * due to mapping restrictions.
+ *
+ * 64-bit kdump kernels need to be restricted to be under 64 TB, which is
+ * the upper limit of system RAM in 4-level paging mode. Since the kdump
+ * jump could be from 5-level paging to 4-level paging, the jump will fail if
+ * the kernel is put above 64 TB, and during the 1st kernel bootup there's
+ * no good way to detect the paging mode of the target kernel which will be
+ * loaded for dumping.
+ */
+extern unsigned long swiotlb_size_or_default(void);
+
+#ifdef CONFIG_X86_32
+# define CRASH_ADDR_LOW_MAX SZ_512M
+# define CRASH_ADDR_HIGH_MAX SZ_512M
+#else
+# define CRASH_ADDR_LOW_MAX SZ_4G
+# define CRASH_ADDR_HIGH_MAX SZ_64T
+#endif
+
+# define DEFAULT_CRASH_KERNEL_LOW_SIZE crash_low_size_default()
+
+static inline unsigned long crash_low_size_default(void)
+{
+#ifdef CONFIG_X86_64
+ return max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
+#else
+ return 0;
+#endif
+}
+
+#endif /* _X86_CRASH_CORE_H */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index f945d88215b4..d7baa567c68e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -470,155 +470,29 @@ static void __init memblock_x86_reserve_range_setup_data(void)
}
}
-/*
- * --------- Crashkernel reservation ------------------------------
- */
-
-/* 16M alignment for crash kernel regions */
-#define CRASH_ALIGN SZ_16M
-
-/*
- * Keep the crash kernel below this limit.
- *
- * Earlier 32-bits kernels would limit the kernel to the low 512 MB range
- * due to mapping restrictions.
- *
- * 64-bit kdump kernels need to be restricted to be under 64 TB, which is
- * the upper limit of system RAM in 4-level paging mode. Since the kdump
- * jump could be from 5-level paging to 4-level paging, the jump will fail if
- * the kernel is put above 64 TB, and during the 1st kernel bootup there's
- * no good way to detect the paging mode of the target kernel which will be
- * loaded for dumping.
- */
-#ifdef CONFIG_X86_32
-# define CRASH_ADDR_LOW_MAX SZ_512M
-# define CRASH_ADDR_HIGH_MAX SZ_512M
-#else
-# define CRASH_ADDR_LOW_MAX SZ_4G
-# define CRASH_ADDR_HIGH_MAX SZ_64T
-#endif
-
-static int __init reserve_crashkernel_low(void)
+static void __init arch_reserve_crashkernel(void)
{
-#ifdef CONFIG_X86_64
- unsigned long long base, low_base = 0, low_size = 0;
- unsigned long low_mem_limit;
- int ret;
-
- low_mem_limit = min(memblock_phys_mem_size(), CRASH_ADDR_LOW_MAX);
-
- /* crashkernel=Y,low */
- ret = parse_crashkernel_low(boot_command_line, low_mem_limit, &low_size, &base);
- if (ret) {
- /*
- * two parts from kernel/dma/swiotlb.c:
- * -swiotlb size: user-specified with swiotlb= or default.
- *
- * -swiotlb overflow buffer: now hardcoded to 32k. We round it
- * to 8M for other buffers that may need to stay low too. Also
- * make sure we allocate enough extra low memory so that we
- * don't run out of DMA buffers for 32-bit devices.
- */
- low_size = max(swiotlb_size_or_default() + (8UL << 20), 256UL << 20);
- } else {
- /* passed with crashkernel=0,low ? */
- if (!low_size)
- return 0;
- }
-
- low_base = memblock_phys_alloc_range(low_size, CRASH_ALIGN, 0, CRASH_ADDR_LOW_MAX);
- if (!low_base) {
- pr_err("Cannot reserve %ldMB crashkernel low memory, please try smaller size.\n",
- (unsigned long)(low_size >> 20));
- return -ENOMEM;
- }
-
- pr_info("Reserving %ldMB of low memory at %ldMB for crashkernel (low RAM limit: %ldMB)\n",
- (unsigned long)(low_size >> 20),
- (unsigned long)(low_base >> 20),
- (unsigned long)(low_mem_limit >> 20));
-
- crashk_low_res.start = low_base;
- crashk_low_res.end = low_base + low_size - 1;
- insert_resource(&iomem_resource, &crashk_low_res);
-#endif
- return 0;
-}
-
-static void __init reserve_crashkernel(void)
-{
- unsigned long long crash_size, crash_base, total_mem;
+ unsigned long long crash_base, crash_size, low_size = 0;
+ char *cmdline = boot_command_line;
bool high = false;
int ret;
if (!IS_ENABLED(CONFIG_KEXEC_CORE))
return;
- total_mem = memblock_phys_mem_size();
-
- /* crashkernel=XM */
- ret = parse_crashkernel(boot_command_line, total_mem,
- &crash_size, &crash_base, NULL, NULL);
- if (ret != 0 || crash_size <= 0) {
- /* crashkernel=X,high */
- ret = parse_crashkernel_high(boot_command_line, total_mem,
- &crash_size, &crash_base);
- if (ret != 0 || crash_size <= 0)
- return;
- high = true;
- }
+ ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
+ &crash_size, &crash_base,
+ &low_size, &high);
+ if (ret)
+ return;
if (xen_pv_domain()) {
pr_info("Ignoring crashkernel for a Xen PV domain\n");
return;
}
- /* 0 means: find the address automatically */
- if (!crash_base) {
- /*
- * Set CRASH_ADDR_LOW_MAX upper bound for crash memory,
- * crashkernel=x,high reserves memory over 4G, also allocates
- * 256M extra low memory for DMA buffers and swiotlb.
- * But the extra memory is not required for all machines.
- * So try low memory first and fall back to high memory
- * unless "crashkernel=size[KMG],high" is specified.
- */
- if (!high)
- crash_base = memblock_phys_alloc_range(crash_size,
- CRASH_ALIGN, CRASH_ALIGN,
- CRASH_ADDR_LOW_MAX);
- if (!crash_base)
- crash_base = memblock_phys_alloc_range(crash_size,
- CRASH_ALIGN, CRASH_ALIGN,
- CRASH_ADDR_HIGH_MAX);
- if (!crash_base) {
- pr_info("crashkernel reservation failed - No suitable area found.\n");
- return;
- }
- } else {
- unsigned long long start;
-
- start = memblock_phys_alloc_range(crash_size, SZ_1M, crash_base,
- crash_base + crash_size);
- if (start != crash_base) {
- pr_info("crashkernel reservation failed - memory is in use.\n");
- return;
- }
- }
-
- if (crash_base >= (1ULL << 32) && reserve_crashkernel_low()) {
- memblock_phys_free(crash_base, crash_size);
- return;
- }
-
- pr_info("Reserving %ldMB of memory at %ldMB for crashkernel (System RAM: %ldMB)\n",
- (unsigned long)(crash_size >> 20),
- (unsigned long)(crash_base >> 20),
- (unsigned long)(total_mem >> 20));
-
- crashk_res.start = crash_base;
- crashk_res.end = crash_base + crash_size - 1;
- insert_resource(&iomem_resource, &crashk_res);
+ reserve_crashkernel_generic(cmdline, crash_size, crash_base,
+ low_size, high);
}
static struct resource standard_io_resources[] = {
@@ -1232,7 +1106,7 @@ void __init setup_arch(char **cmdline_p)
* Reserve memory for crash kernel after SRAT is parsed so that it
* won't consume hotpluggable memory.
*/
- reserve_crashkernel();
+ arch_reserve_crashkernel();
memblock_find_dma_reserve();
--
2.41.0
On 2023/9/14 11:31, Baoquan He wrote:
> Now parse_crashkernel() is a real entry point for all kinds of
> crahskernel parsing on any architecture.
>
> And wrap the crahskernel=,high|low handling inside
> CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION ifdeffery scope.
Reviewed-by: Zhen Lei <[email protected]>
>
> Signed-off-by: Baoquan He <[email protected]>
> ---
> include/linux/crash_core.h | 6 ++++++
> kernel/crash_core.c | 36 +++++++++++++++++++++++++++++++++---
> 2 files changed, 39 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
> index 6156355ef831..d8050a7eab01 100644
> --- a/include/linux/crash_core.h
> +++ b/include/linux/crash_core.h
> @@ -79,6 +79,12 @@ Elf_Word *append_elf_note(Elf_Word *buf, char *name, unsigned int type,
> void *data, size_t data_len);
> void final_note(Elf_Word *buf);
>
> +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> +#ifndef DEFAULT_CRASH_KERNEL_LOW_SIZE
> +#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
> +#endif
> +#endif
> +
> int __init parse_crashkernel(char *cmdline, unsigned long long system_ram,
> unsigned long long *crash_size, unsigned long long *crash_base,
> unsigned long long *low_size, bool *high);
> diff --git a/kernel/crash_core.c b/kernel/crash_core.c
> index cca1d76e8255..dce2f5874fea 100644
> --- a/kernel/crash_core.c
> +++ b/kernel/crash_core.c
> @@ -283,6 +283,9 @@ static int __init __parse_crashkernel(char *cmdline,
> /*
> * That function is the entry point for command line parsing and should be
> * called from the arch-specific code.
> + *
> + * If crashkernel=,high|low is supported on architecture, non-NULL values
> + * should be passed to parameters 'low_size' and 'high'.
> */
> int __init parse_crashkernel(char *cmdline,
> unsigned long long system_ram,
> @@ -296,10 +299,37 @@ int __init parse_crashkernel(char *cmdline,
> /* crashkernel=X[@offset] */
> ret = __parse_crashkernel(cmdline, system_ram, crash_size,
> crash_base, NULL);
> - if (!high)
> - return ret;
> +#ifdef CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> + /*
> + * If non-NULL 'high' passed in and no normal crashkernel
> + * setting detected, try parsing crashkernel=,high|low.
> + */
> + if (high && ret == -ENOENT) {
> + ret = __parse_crashkernel(cmdline, 0, crash_size,
> + crash_base, suffix_tbl[SUFFIX_HIGH]);
> + if (ret || !*crash_size)
> + return -EINVAL;
>
> - return 0;
> + /*
> + * crashkernel=Y,low can be specified or not, but invalid value
> + * is not allowed.
> + */
> + ret = __parse_crashkernel(cmdline, 0, low_size,
> + crash_base, suffix_tbl[SUFFIX_LOW]);
> + if (ret == -ENOENT) {
> + *low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> + ret = 0;
> + } else if (ret) {
> + return ret;
> + }
> +
> + *high = true;
> + }
> +#endif
> + if (!*crash_size)
> + ret = -EINVAL;
> +
> + return ret;
> }
>
> int __init parse_crashkernel_high(char *cmdline,
>
--
Regards,
Zhen Lei
On 2023/9/14 11:31, Baoquan He wrote:
> With the help of newly changed function parse_crashkernel() and
> generic reserve_crashkernel_generic(), crashkernel reservation can be
> simplified by steps:
>
> 1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
> CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
> DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
>
> 2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
> reserve_crashkernel_generic();
>
> 3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
> arch/riscv/Kconfig.
>
> The old reserve_crashkernel_low() and reserve_crashkernel() can be
> removed.
Hi Baoquan,
Sorry for the late response. The refactor code has unified multiple
arch via generic interface, which looks great!
However when I tested on my risc-v QEMU environment, a little problem
occurred with following messages:
[ 0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB)
[ 0.000000] crashkernel reserved: 0x0000000177e00000 - 0x0000000277e00000 (4096 MB)
[ 0.000000] ------------[ cut here ]------------
[ 0.000000] WARNING: CPU: 0 PID: 0 at kernel/resource.c:779 __insert_resource+0x8e/0xd0
[ 0.000000] Modules linked in:
[ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 6.6.0-rc2-next-20230920 #1
[ 0.000000] Hardware name: riscv-virtio,qemu (DT)
[ 0.000000] epc : __insert_resource+0x8e/0xd0
[ 0.000000] ra : insert_resource+0x28/0x4e
[ 0.000000] epc : ffffffff80017344 ra : ffffffff8001742e sp : ffffffff81203db0
[ 0.000000] gp : ffffffff812ece98 tp : ffffffff8120dac0 t0 : ff600001f7ff2b00
[ 0.000000] t1 : 0000000000000000 t2 : 3428203030303030 s0 : ffffffff81203dc0
[ 0.000000] s1 : ffffffff81211e18 a0 : ffffffff81211e18 a1 : ffffffff81289380
[ 0.000000] a2 : 0000000277dfffff a3 : 0000000177e00000 a4 : 0000000177e00000
[ 0.000000] a5 : ffffffff81289380 a6 : 0000000277dfffff a7 : 0000000000000078
[ 0.000000] s2 : ffffffff81289380 s3 : ffffffff80a0bac8 s4 : ff600001f7ff2880
[ 0.000000] s5 : 0000000000000280 s6 : 8000000a00006800 s7 : 000000000000007f
[ 0.000000] s8 : 0000000080017038 s9 : 0000000080038ea0 s10: 0000000000000000
[ 0.000000] s11: 0000000000000000 t3 : ffffffff80a0bc00 t4 : ffffffff80a0bc00
[ 0.000000] t5 : ffffffff80a0bbd0 t6 : ffffffff80a0bc00
[ 0.000000] status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003
[ 0.000000] [<ffffffff80017344>] __insert_resource+0x8e/0xd0
[ 0.000000] ---[ end trace 0000000000000000 ]---
[ 0.000000] Failed to add a Crash kernel resource at 177e00000
The crashkernel memory has been allocated successfully, whereas
it seems failed to insert into iomem_resource. This should due to
the unique reserving logic in risc-v arch specific code, i.e.
crashk_res/crashk_low_res will be added into iomem_resource
later in init_resources(), which is not aligned with the
unified reserving logic.
My simple solution here is removing the arch specific code within
#ifdef CONFIG_KEXEC_CORE in init_resources(), which has been tested
OK with all your testcases. Or do you have any other idea?
Best regards,
Jiahao
>
> Signed-off-by: Baoquan He <[email protected]>
> ---
> arch/riscv/Kconfig | 3 +
> arch/riscv/include/asm/crash_core.h | 11 +++
> arch/riscv/include/asm/processor.h | 2 +
> arch/riscv/mm/init.c | 141 +++-------------------------
> 4 files changed, 27 insertions(+), 130 deletions(-)
> create mode 100644 arch/riscv/include/asm/crash_core.h
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index d607ab0f7c6d..25474f8c12b7 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -694,6 +694,9 @@ config ARCH_SUPPORTS_KEXEC_PURGATORY
> config ARCH_SUPPORTS_CRASH_DUMP
> def_bool y
>
> +config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> + def_bool CRASH_CORE
> +
> config COMPAT
> bool "Kernel support for 32-bit U-mode"
> default 64BIT
> diff --git a/arch/riscv/include/asm/crash_core.h b/arch/riscv/include/asm/crash_core.h
> new file mode 100644
> index 000000000000..e1874b23feaf
> --- /dev/null
> +++ b/arch/riscv/include/asm/crash_core.h
> @@ -0,0 +1,11 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _RISCV_CRASH_CORE_H
> +#define _RISCV_CRASH_CORE_H
> +
> +#define CRASH_ALIGN PMD_SIZE
> +
> +#define CRASH_ADDR_LOW_MAX dma32_phys_limit
> +#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM()
> +
> +extern phys_addr_t memblock_end_of_DRAM(void);
> +#endif
> diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
> index 3e23e1786d05..441da1839c94 100644
> --- a/arch/riscv/include/asm/processor.h
> +++ b/arch/riscv/include/asm/processor.h
> @@ -116,6 +116,8 @@ static inline void wait_for_interrupt(void)
> __asm__ __volatile__ ("wfi");
> }
>
> +extern phys_addr_t dma32_phys_limit;
> +
> struct device_node;
> int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid);
> int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid);
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 9fe448900059..d9a4e8702864 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -65,7 +65,7 @@ extern char _start[];
> void *_dtb_early_va __initdata;
> uintptr_t _dtb_early_pa __initdata;
>
> -static phys_addr_t dma32_phys_limit __initdata;
> +phys_addr_t dma32_phys_limit __initdata;
>
> static void __init zone_sizes_init(void)
> {
> @@ -1333,28 +1333,6 @@ static inline void setup_vm_final(void)
> }
> #endif /* CONFIG_MMU */
>
> -/* Reserve 128M low memory by default for swiotlb buffer */
> -#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
> -
> -static int __init reserve_crashkernel_low(unsigned long long low_size)
> -{
> - unsigned long long low_base;
> -
> - low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit);
> - if (!low_base) {
> - pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
> - return -ENOMEM;
> - }
> -
> - pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
> - low_base, low_base + low_size, low_size >> 20);
> -
> - crashk_low_res.start = low_base;
> - crashk_low_res.end = low_base + low_size - 1;
> -
> - return 0;
> -}
> -
> /*
> * reserve_crashkernel() - reserves memory for crash kernel
> *
> @@ -1362,122 +1340,25 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
> * line parameter. The memory reserved is used by dump capture kernel when
> * primary kernel is crashing.
> */
> -static void __init reserve_crashkernel(void)
> +static void __init arch_reserve_crashkernel(void)
> {
> - unsigned long long crash_base = 0;
> - unsigned long long crash_size = 0;
> - unsigned long long crash_low_size = 0;
> - unsigned long search_start = memblock_start_of_DRAM();
> - unsigned long search_end = (unsigned long)dma32_phys_limit;
> + unsigned long long low_size = 0;
> + unsigned long long crash_base, crash_size;
> char *cmdline = boot_command_line;
> - bool fixed_base = false;
> bool high = false;
> -
> - int ret = 0;
> + int ret;
>
> if (!IS_ENABLED(CONFIG_KEXEC_CORE))
> return;
> - /*
> - * Don't reserve a region for a crash kernel on a crash kernel
> - * since it doesn't make much sense and we have limited memory
> - * resources.
> - */
> - if (is_kdump_kernel()) {
> - pr_info("crashkernel: ignoring reservation request\n");
> - return;
> - }
>
> ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
> - &crash_size, &crash_base, NULL, NULL);
> - if (ret == -ENOENT) {
> - /* Fallback to crashkernel=X,[high,low] */
> - ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
> - if (ret || !crash_size)
> - return;
> -
> - /*
> - * crashkernel=Y,low is valid only when crashkernel=X,high
> - * is passed.
> - */
> - ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
> - if (ret == -ENOENT)
> - crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> - else if (ret)
> - return;
> -
> - search_start = (unsigned long)dma32_phys_limit;
> - search_end = memblock_end_of_DRAM();
> - high = true;
> - } else if (ret || !crash_size) {
> - /* Invalid argument value specified */
> + &crash_size, &crash_base,
> + &low_size, &high);
> + if (ret)
> return;
> - }
> -
> - crash_size = PAGE_ALIGN(crash_size);
> -
> - if (crash_base) {
> - fixed_base = true;
> - search_start = crash_base;
> - search_end = crash_base + crash_size;
> - }
> -
> - /*
> - * Current riscv boot protocol requires 2MB alignment for
> - * RV64 and 4MB alignment for RV32 (hugepage size)
> - *
> - * Try to alloc from 32bit addressible physical memory so that
> - * swiotlb can work on the crash kernel.
> - */
> - crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
> - search_start, search_end);
> - if (crash_base == 0) {
> - /*
> - * For crashkernel=size[KMG]@offset[KMG], print out failure
> - * message if can't reserve the specified region.
> - */
> - if (fixed_base) {
> - pr_warn("crashkernel: allocating failed with given size@offset\n");
> - return;
> - }
> -
> - if (high) {
> - /*
> - * For crashkernel=size[KMG],high, if the first attempt was
> - * for high memory, fall back to low memory.
> - */
> - search_start = memblock_start_of_DRAM();
> - search_end = (unsigned long)dma32_phys_limit;
> - } else {
> - /*
> - * For crashkernel=size[KMG], if the first attempt was for
> - * low memory, fall back to high memory, the minimum required
> - * low memory will be reserved later.
> - */
> - search_start = (unsigned long)dma32_phys_limit;
> - search_end = memblock_end_of_DRAM();
> - crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> - }
> -
> - crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
> - search_start, search_end);
> - if (crash_base == 0) {
> - pr_warn("crashkernel: couldn't allocate %lldKB\n",
> - crash_size >> 10);
> - return;
> - }
> - }
> -
> - if ((crash_base >= dma32_phys_limit) && crash_low_size &&
> - reserve_crashkernel_low(crash_low_size)) {
> - memblock_phys_free(crash_base, crash_size);
> - return;
> - }
> -
> - pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n",
> - crash_base, crash_base + crash_size, crash_size >> 20);
>
> - crashk_res.start = crash_base;
> - crashk_res.end = crash_base + crash_size - 1;
> + reserve_crashkernel_generic(cmdline, crash_size, crash_base,
> + low_size, high);
> }
>
> void __init paging_init(void)
> @@ -1495,7 +1376,7 @@ void __init misc_mem_init(void)
> arch_numa_init();
> sparse_init();
> zone_sizes_init();
> - reserve_crashkernel();
> + arch_reserve_crashkernel();
> memblock_dump_all();
> }
>
On 09/21/23 at 10:36am, chenjiahao (C) wrote:
>
> On 2023/9/14 11:31, Baoquan He wrote:
> > With the help of newly changed function parse_crashkernel() and
> > generic reserve_crashkernel_generic(), crashkernel reservation can be
> > simplified by steps:
> >
> > 1) Add a new header file <asm/crash_core.h>, and define CRASH_ALIGN,
> > CRASH_ADDR_LOW_MAX, CRASH_ADDR_HIGH_MAX and
> > DEFAULT_CRASH_KERNEL_LOW_SIZE in <asm/crash_core.h>;
> >
> > 2) Add arch_reserve_crashkernel() to call parse_crashkernel() and
> > reserve_crashkernel_generic();
> >
> > 3) Add ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION Kconfig in
> > arch/riscv/Kconfig.
> >
> > The old reserve_crashkernel_low() and reserve_crashkernel() can be
> > removed.
>
> Hi Baoquan,
>
> Sorry for the late response. The refactor code has unified multiple
> arch via generic interface, which looks great!
>
> However when I tested on my risc-v QEMU environment, a little problem
> occurred with following messages:
>
> [ 0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB)
> [ 0.000000] crashkernel reserved: 0x0000000177e00000 - 0x0000000277e00000 (4096 MB)
> [ 0.000000] ------------[ cut here ]------------
> [ 0.000000] WARNING: CPU: 0 PID: 0 at kernel/resource.c:779 __insert_resource+0x8e/0xd0
> [ 0.000000] Modules linked in:
> [ 0.000000] CPU: 0 PID: 0 Comm: swapper Not tainted 6.6.0-rc2-next-20230920 #1
> [ 0.000000] Hardware name: riscv-virtio,qemu (DT)
> [ 0.000000] epc : __insert_resource+0x8e/0xd0
> [ 0.000000] ra : insert_resource+0x28/0x4e
> [ 0.000000] epc : ffffffff80017344 ra : ffffffff8001742e sp : ffffffff81203db0
> [ 0.000000] gp : ffffffff812ece98 tp : ffffffff8120dac0 t0 : ff600001f7ff2b00
> [ 0.000000] t1 : 0000000000000000 t2 : 3428203030303030 s0 : ffffffff81203dc0
> [ 0.000000] s1 : ffffffff81211e18 a0 : ffffffff81211e18 a1 : ffffffff81289380
> [ 0.000000] a2 : 0000000277dfffff a3 : 0000000177e00000 a4 : 0000000177e00000
> [ 0.000000] a5 : ffffffff81289380 a6 : 0000000277dfffff a7 : 0000000000000078
> [ 0.000000] s2 : ffffffff81289380 s3 : ffffffff80a0bac8 s4 : ff600001f7ff2880
> [ 0.000000] s5 : 0000000000000280 s6 : 8000000a00006800 s7 : 000000000000007f
> [ 0.000000] s8 : 0000000080017038 s9 : 0000000080038ea0 s10: 0000000000000000
> [ 0.000000] s11: 0000000000000000 t3 : ffffffff80a0bc00 t4 : ffffffff80a0bc00
> [ 0.000000] t5 : ffffffff80a0bbd0 t6 : ffffffff80a0bc00
> [ 0.000000] status: 0000000200000100 badaddr: 0000000000000000 cause: 0000000000000003
> [ 0.000000] [<ffffffff80017344>] __insert_resource+0x8e/0xd0
> [ 0.000000] ---[ end trace 0000000000000000 ]---
> [ 0.000000] Failed to add a Crash kernel resource at 177e00000
>
> The crashkernel memory has been allocated successfully, whereas
> it seems failed to insert into iomem_resource. This should due to
> the unique reserving logic in risc-v arch specific code, i.e.
> crashk_res/crashk_low_res will be added into iomem_resource
> later in init_resources(), which is not aligned with the
> unified reserving logic.
You are right, I didn't check this in riscv arch carefully. The resouce
adding is done repeatedly.
>
> My simple solution here is removing the arch specific code within
> #ifdef CONFIG_KEXEC_CORE in init_resources(), which has been tested
> OK with all your testcases. Or do you have any other idea?
Yeah, that sounds good to me. You can post a patch with a detailed log
to describe the spotted problem and the root cause.
Thanks for working on this, Jiahao.
>
>
> >
> > Signed-off-by: Baoquan He <[email protected]>
> > ---
> > arch/riscv/Kconfig | 3 +
> > arch/riscv/include/asm/crash_core.h | 11 +++
> > arch/riscv/include/asm/processor.h | 2 +
> > arch/riscv/mm/init.c | 141 +++-------------------------
> > 4 files changed, 27 insertions(+), 130 deletions(-)
> > create mode 100644 arch/riscv/include/asm/crash_core.h
> >
> > diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> > index d607ab0f7c6d..25474f8c12b7 100644
> > --- a/arch/riscv/Kconfig
> > +++ b/arch/riscv/Kconfig
> > @@ -694,6 +694,9 @@ config ARCH_SUPPORTS_KEXEC_PURGATORY
> > config ARCH_SUPPORTS_CRASH_DUMP
> > def_bool y
> > +config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
> > + def_bool CRASH_CORE
> > +
> > config COMPAT
> > bool "Kernel support for 32-bit U-mode"
> > default 64BIT
> > diff --git a/arch/riscv/include/asm/crash_core.h b/arch/riscv/include/asm/crash_core.h
> > new file mode 100644
> > index 000000000000..e1874b23feaf
> > --- /dev/null
> > +++ b/arch/riscv/include/asm/crash_core.h
> > @@ -0,0 +1,11 @@
> > +/* SPDX-License-Identifier: GPL-2.0-only */
> > +#ifndef _RISCV_CRASH_CORE_H
> > +#define _RISCV_CRASH_CORE_H
> > +
> > +#define CRASH_ALIGN PMD_SIZE
> > +
> > +#define CRASH_ADDR_LOW_MAX dma32_phys_limit
> > +#define CRASH_ADDR_HIGH_MAX memblock_end_of_DRAM()
> > +
> > +extern phys_addr_t memblock_end_of_DRAM(void);
> > +#endif
> > diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
> > index 3e23e1786d05..441da1839c94 100644
> > --- a/arch/riscv/include/asm/processor.h
> > +++ b/arch/riscv/include/asm/processor.h
> > @@ -116,6 +116,8 @@ static inline void wait_for_interrupt(void)
> > __asm__ __volatile__ ("wfi");
> > }
> > +extern phys_addr_t dma32_phys_limit;
> > +
> > struct device_node;
> > int riscv_of_processor_hartid(struct device_node *node, unsigned long *hartid);
> > int riscv_early_of_processor_hartid(struct device_node *node, unsigned long *hartid);
> > diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> > index 9fe448900059..d9a4e8702864 100644
> > --- a/arch/riscv/mm/init.c
> > +++ b/arch/riscv/mm/init.c
> > @@ -65,7 +65,7 @@ extern char _start[];
> > void *_dtb_early_va __initdata;
> > uintptr_t _dtb_early_pa __initdata;
> > -static phys_addr_t dma32_phys_limit __initdata;
> > +phys_addr_t dma32_phys_limit __initdata;
> > static void __init zone_sizes_init(void)
> > {
> > @@ -1333,28 +1333,6 @@ static inline void setup_vm_final(void)
> > }
> > #endif /* CONFIG_MMU */
> > -/* Reserve 128M low memory by default for swiotlb buffer */
> > -#define DEFAULT_CRASH_KERNEL_LOW_SIZE (128UL << 20)
> > -
> > -static int __init reserve_crashkernel_low(unsigned long long low_size)
> > -{
> > - unsigned long long low_base;
> > -
> > - low_base = memblock_phys_alloc_range(low_size, PMD_SIZE, 0, dma32_phys_limit);
> > - if (!low_base) {
> > - pr_err("cannot allocate crashkernel low memory (size:0x%llx).\n", low_size);
> > - return -ENOMEM;
> > - }
> > -
> > - pr_info("crashkernel low memory reserved: 0x%016llx - 0x%016llx (%lld MB)\n",
> > - low_base, low_base + low_size, low_size >> 20);
> > -
> > - crashk_low_res.start = low_base;
> > - crashk_low_res.end = low_base + low_size - 1;
> > -
> > - return 0;
> > -}
> > -
> > /*
> > * reserve_crashkernel() - reserves memory for crash kernel
> > *
> > @@ -1362,122 +1340,25 @@ static int __init reserve_crashkernel_low(unsigned long long low_size)
> > * line parameter. The memory reserved is used by dump capture kernel when
> > * primary kernel is crashing.
> > */
> > -static void __init reserve_crashkernel(void)
> > +static void __init arch_reserve_crashkernel(void)
> > {
> > - unsigned long long crash_base = 0;
> > - unsigned long long crash_size = 0;
> > - unsigned long long crash_low_size = 0;
> > - unsigned long search_start = memblock_start_of_DRAM();
> > - unsigned long search_end = (unsigned long)dma32_phys_limit;
> > + unsigned long long low_size = 0;
> > + unsigned long long crash_base, crash_size;
> > char *cmdline = boot_command_line;
> > - bool fixed_base = false;
> > bool high = false;
> > -
> > - int ret = 0;
> > + int ret;
> > if (!IS_ENABLED(CONFIG_KEXEC_CORE))
> > return;
> > - /*
> > - * Don't reserve a region for a crash kernel on a crash kernel
> > - * since it doesn't make much sense and we have limited memory
> > - * resources.
> > - */
> > - if (is_kdump_kernel()) {
> > - pr_info("crashkernel: ignoring reservation request\n");
> > - return;
> > - }
> > ret = parse_crashkernel(cmdline, memblock_phys_mem_size(),
> > - &crash_size, &crash_base, NULL, NULL);
> > - if (ret == -ENOENT) {
> > - /* Fallback to crashkernel=X,[high,low] */
> > - ret = parse_crashkernel_high(cmdline, 0, &crash_size, &crash_base);
> > - if (ret || !crash_size)
> > - return;
> > -
> > - /*
> > - * crashkernel=Y,low is valid only when crashkernel=X,high
> > - * is passed.
> > - */
> > - ret = parse_crashkernel_low(cmdline, 0, &crash_low_size, &crash_base);
> > - if (ret == -ENOENT)
> > - crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> > - else if (ret)
> > - return;
> > -
> > - search_start = (unsigned long)dma32_phys_limit;
> > - search_end = memblock_end_of_DRAM();
> > - high = true;
> > - } else if (ret || !crash_size) {
> > - /* Invalid argument value specified */
> > + &crash_size, &crash_base,
> > + &low_size, &high);
> > + if (ret)
> > return;
> > - }
> > -
> > - crash_size = PAGE_ALIGN(crash_size);
> > -
> > - if (crash_base) {
> > - fixed_base = true;
> > - search_start = crash_base;
> > - search_end = crash_base + crash_size;
> > - }
> > -
> > - /*
> > - * Current riscv boot protocol requires 2MB alignment for
> > - * RV64 and 4MB alignment for RV32 (hugepage size)
> > - *
> > - * Try to alloc from 32bit addressible physical memory so that
> > - * swiotlb can work on the crash kernel.
> > - */
> > - crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
> > - search_start, search_end);
> > - if (crash_base == 0) {
> > - /*
> > - * For crashkernel=size[KMG]@offset[KMG], print out failure
> > - * message if can't reserve the specified region.
> > - */
> > - if (fixed_base) {
> > - pr_warn("crashkernel: allocating failed with given size@offset\n");
> > - return;
> > - }
> > -
> > - if (high) {
> > - /*
> > - * For crashkernel=size[KMG],high, if the first attempt was
> > - * for high memory, fall back to low memory.
> > - */
> > - search_start = memblock_start_of_DRAM();
> > - search_end = (unsigned long)dma32_phys_limit;
> > - } else {
> > - /*
> > - * For crashkernel=size[KMG], if the first attempt was for
> > - * low memory, fall back to high memory, the minimum required
> > - * low memory will be reserved later.
> > - */
> > - search_start = (unsigned long)dma32_phys_limit;
> > - search_end = memblock_end_of_DRAM();
> > - crash_low_size = DEFAULT_CRASH_KERNEL_LOW_SIZE;
> > - }
> > -
> > - crash_base = memblock_phys_alloc_range(crash_size, PMD_SIZE,
> > - search_start, search_end);
> > - if (crash_base == 0) {
> > - pr_warn("crashkernel: couldn't allocate %lldKB\n",
> > - crash_size >> 10);
> > - return;
> > - }
> > - }
> > -
> > - if ((crash_base >= dma32_phys_limit) && crash_low_size &&
> > - reserve_crashkernel_low(crash_low_size)) {
> > - memblock_phys_free(crash_base, crash_size);
> > - return;
> > - }
> > -
> > - pr_info("crashkernel: reserved 0x%016llx - 0x%016llx (%lld MB)\n",
> > - crash_base, crash_base + crash_size, crash_size >> 20);
> > - crashk_res.start = crash_base;
> > - crashk_res.end = crash_base + crash_size - 1;
> > + reserve_crashkernel_generic(cmdline, crash_size, crash_base,
> > + low_size, high);
> > }
> > void __init paging_init(void)
> > @@ -1495,7 +1376,7 @@ void __init misc_mem_init(void)
> > arch_numa_init();
> > sparse_init();
> > zone_sizes_init();
> > - reserve_crashkernel();
> > + arch_reserve_crashkernel();
> > memblock_dump_all();
> > }
>