Commit fdc26823 authored by Baoquan He's avatar Baoquan He Committed by Andrew Morton
Browse files

arm64: kdump: use generic interface to simplify crashkernel reservation

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.

Link: https://lkml.kernel.org/r/20230914033142.676708-8-bhe@redhat.com


Signed-off-by: default avatarBaoquan He <bhe@redhat.com>
Reviewed-by: default avatarZhen Lei <thunder.leizhen@huawei.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Chen Jiahao <chenjiahao16@huawei.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 9c08a2a1
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -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
+10 −0
Original line number Diff line number Diff line
/* 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
+8 −132
Original line number Diff line number Diff line
@@ -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();
}