mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-01 10:45:49 +00:00
x86: kdump: use generic interface to simplify crashkernel reservation code
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>
This commit is contained in:
parent
b631b95dde
commit
9c08a2a139
@ -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"
|
||||
|
42
arch/x86/include/asm/crash_core.h
Normal file
42
arch/x86/include/asm/crash_core.h
Normal file
@ -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 */
|
@ -466,155 +466,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[] = {
|
||||
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user