| From: Baoquan He <bhe@redhat.com> |
| Subject: x86: kdump: use generic interface to simplify crashkernel reservation code |
| Date: Thu, 14 Sep 2023 11:31:39 +0800 |
| |
| 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. |
| |
| [bhe@redhat.com: move crash_low_size_default() code into <asm/crash_core.h>] |
| Link: https://lkml.kernel.org/r/ZQpeAjOmuMJBFw1/@MiWiFi-R3L-srv |
| Link: https://lkml.kernel.org/r/20230914033142.676708-7-bhe@redhat.com |
| Signed-off-by: Baoquan He <bhe@redhat.com> |
| Cc: Catalin Marinas <catalin.marinas@arm.com> |
| Cc: Chen Jiahao <chenjiahao16@huawei.com> |
| Cc: Zhen Lei <thunder.leizhen@huawei.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| 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(-) |
| |
| --- /dev/null |
| +++ a/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 */ |
| --- a/arch/x86/Kconfig~x86-kdump-use-generic-interface-to-simplify-crashkernel-reservation-code |
| +++ a/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" |
| --- a/arch/x86/kernel/setup.c~x86-kdump-use-generic-interface-to-simplify-crashkernel-reservation-code |
| +++ a/arch/x86/kernel/setup.c |
| @@ -466,155 +466,29 @@ static void __init memblock_x86_reserve_ |
| } |
| } |
| |
| -/* |
| - * --------- 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[] = { |
| @@ -1228,7 +1102,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(); |
| |
| _ |