Skip to content
Closed
16 changes: 8 additions & 8 deletions Documentation/admin-guide/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1122,14 +1122,14 @@ Kernel parameters
It will be ignored when crashkernel=X,high is not used
or memory reserved is below 4G.
crashkernel=size[KMG],cma
[KNL, X86, ppc] Reserve additional crash kernel memory from
CMA. This reservation is usable by the first system's
userspace memory and kernel movable allocations (memory
balloon, zswap). Pages allocated from this memory range
will not be included in the vmcore so this should not
be used if dumping of userspace memory is intended and
it has to be expected that some movable kernel pages
may be missing from the dump.
[KNL, X86, ARM64, RISCV, PPC] Reserve additional crash
kernel memory from CMA. This reservation is usable by
the first system's userspace memory and kernel movable
allocations (memory balloon, zswap). Pages allocated
from this memory range will not be included in the vmcore
so this should not be used if dumping of userspace memory
is intended and it has to be expected that some movable
kernel pages may be missing from the dump.

A standard crashkernel reservation, as described above,
is still needed to hold the crash kernel and initrd.
Expand Down
39 changes: 12 additions & 27 deletions arch/arm64/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,46 +40,31 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
}

#ifdef CONFIG_CRASH_DUMP
static int prepare_elf_headers(void **addr, unsigned long *sz)
unsigned int arch_get_system_nr_ranges(void)
{
struct crash_mem *cmem;
unsigned int nr_ranges;
int ret;
u64 i;
unsigned int nr_ranges = 2 + crashk_cma_cnt; /* for exclusion of crashkernel region */
phys_addr_t start, end;
u64 i;

nr_ranges = 2; /* for exclusion of crashkernel region */
for_each_mem_range(i, &start, &end)
nr_ranges++;

cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
return -ENOMEM;
return nr_ranges;
}

int arch_crash_populate_cmem(struct crash_mem *cmem)
{
phys_addr_t start, end;
u64 i;

cmem->max_nr_ranges = nr_ranges;
cmem->nr_ranges = 0;
for_each_mem_range(i, &start, &end) {
cmem->ranges[cmem->nr_ranges].start = start;
cmem->ranges[cmem->nr_ranges].end = end - 1;
cmem->nr_ranges++;
}

/* Exclude crashkernel region */
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
if (ret)
goto out;

if (crashk_low_res.end) {
ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
if (ret)
goto out;
}

ret = crash_prepare_elf64_headers(cmem, true, addr, sz);

out:
kfree(cmem);
return ret;
return 0;
}
#endif

Expand Down Expand Up @@ -109,7 +94,7 @@ int load_other_segments(struct kimage *image,
void *headers;
unsigned long headers_sz;
if (image->type == KEXEC_TYPE_CRASH) {
ret = prepare_elf_headers(&headers, &headers_sz);
ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
if (ret) {
pr_err("Preparing elf core header failed\n");
goto out_err;
Expand Down
5 changes: 3 additions & 2 deletions arch/arm64/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;

static void __init arch_reserve_crashkernel(void)
{
unsigned long long crash_base, crash_size, cma_size = 0;
unsigned long long low_size = 0;
unsigned long long crash_base, crash_size;
bool high = false;
int ret;

Expand All @@ -106,11 +106,12 @@ static void __init arch_reserve_crashkernel(void)

ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
&crash_size, &crash_base,
&low_size, NULL, &high);
&low_size, &cma_size, &high);
if (ret)
return;

reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
reserve_crashkernel_cma(cma_size);
}

static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
Expand Down
39 changes: 12 additions & 27 deletions arch/loongarch/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,46 +56,31 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
}

#ifdef CONFIG_CRASH_DUMP

static int prepare_elf_headers(void **addr, unsigned long *sz)
unsigned int arch_get_system_nr_ranges(void)
{
int ret, nr_ranges;
uint64_t i;
int nr_ranges = 2; /* for exclusion of crashkernel region */
phys_addr_t start, end;
struct crash_mem *cmem;
uint64_t i;

nr_ranges = 2; /* for exclusion of crashkernel region */
for_each_mem_range(i, &start, &end)
nr_ranges++;

cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
return -ENOMEM;
return nr_ranges;
}

int arch_crash_populate_cmem(struct crash_mem *cmem)
{
phys_addr_t start, end;
uint64_t i;

cmem->max_nr_ranges = nr_ranges;
cmem->nr_ranges = 0;
for_each_mem_range(i, &start, &end) {
cmem->ranges[cmem->nr_ranges].start = start;
cmem->ranges[cmem->nr_ranges].end = end - 1;
cmem->nr_ranges++;
}

/* Exclude crashkernel region */
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
if (ret < 0)
goto out;

if (crashk_low_res.end) {
ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
if (ret < 0)
goto out;
}

ret = crash_prepare_elf64_headers(cmem, true, addr, sz);

out:
kfree(cmem);
return ret;
return 0;
}

/*
Expand Down Expand Up @@ -163,7 +148,7 @@ int load_other_segments(struct kimage *image,
void *headers;
unsigned long headers_sz;

ret = prepare_elf_headers(&headers, &headers_sz);
ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
if (ret < 0) {
pr_err("Preparing elf core header failed\n");
goto out_err;
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/include/asm/kexec_ranges.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
int get_crash_memory_ranges(struct crash_mem **mem_ranges);
Expand Down
7 changes: 4 additions & 3 deletions arch/powerpc/kexec/crash.c
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
struct crash_mem *cmem = NULL;
struct kexec_segment *ksegment;
void *ptr, *mem, *elfbuf = NULL;
unsigned long elfsz, memsz, base_addr, size;
unsigned long elfsz, memsz, base_addr, size, end;

ksegment = &image->segment[image->elfcorehdr_index];
mem = (void *) ksegment->mem;
Expand All @@ -440,7 +440,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
ret = get_crash_memory_ranges(&cmem);
if (ret) {
pr_err("Failed to get crash mem range\n");
return;
goto out;
}

/*
Expand All @@ -450,7 +450,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
if (image->hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY) {
base_addr = PFN_PHYS(mn->start_pfn);
size = mn->nr_pages * PAGE_SIZE;
ret = remove_mem_range(&cmem, base_addr, size);
end = base_addr + size - 1;
ret = arch_crash_exclude_mem_range(&cmem, base_addr, end);
if (ret) {
pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
goto out;
Expand Down
101 changes: 4 additions & 97 deletions arch/powerpc/kexec/ranges.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,9 +553,9 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
#endif /* CONFIG_KEXEC_FILE */

#ifdef CONFIG_CRASH_DUMP
static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
unsigned long long mstart,
unsigned long long mend)
int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges,
unsigned long long mstart,
unsigned long long mend)
{
struct crash_mem *tmem = *mem_ranges;

Expand Down Expand Up @@ -604,18 +604,10 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
sort_memory_ranges(*mem_ranges, true);
}

/* Exclude crashkernel region */
ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end);
ret = crash_exclude_core_ranges(mem_ranges);
if (ret)
goto out;

for (i = 0; i < crashk_cma_cnt; ++i) {
ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start,
crashk_cma_ranges[i].end);
if (ret)
goto out;
}

/*
* FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
* regions are exported to save their context at the time of
Expand All @@ -641,89 +633,4 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
pr_err("Failed to setup crash memory ranges\n");
return ret;
}

/**
* remove_mem_range - Removes the given memory range from the range list.
* @mem_ranges: Range list to remove the memory range to.
* @base: Base address of the range to remove.
* @size: Size of the memory range to remove.
*
* (Re)allocates memory, if needed.
*
* Returns 0 on success, negative errno on error.
*/
int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
{
u64 end;
int ret = 0;
unsigned int i;
u64 mstart, mend;
struct crash_mem *mem_rngs = *mem_ranges;

if (!size)
return 0;

/*
* Memory range are stored as start and end address, use
* the same format to do remove operation.
*/
end = base + size - 1;

for (i = 0; i < mem_rngs->nr_ranges; i++) {
mstart = mem_rngs->ranges[i].start;
mend = mem_rngs->ranges[i].end;

/*
* Memory range to remove is not part of this range entry
* in the memory range list
*/
if (!(base >= mstart && end <= mend))
continue;

/*
* Memory range to remove is equivalent to this entry in the
* memory range list. Remove the range entry from the list.
*/
if (base == mstart && end == mend) {
for (; i < mem_rngs->nr_ranges - 1; i++) {
mem_rngs->ranges[i].start = mem_rngs->ranges[i+1].start;
mem_rngs->ranges[i].end = mem_rngs->ranges[i+1].end;
}
mem_rngs->nr_ranges--;
goto out;
}
/*
* Start address of the memory range to remove and the
* current memory range entry in the list is same. Just
* move the start address of the current memory range
* entry in the list to end + 1.
*/
else if (base == mstart) {
mem_rngs->ranges[i].start = end + 1;
goto out;
}
/*
* End address of the memory range to remove and the
* current memory range entry in the list is same.
* Just move the end address of the current memory
* range entry in the list to base - 1.
*/
else if (end == mend) {
mem_rngs->ranges[i].end = base - 1;
goto out;
}
/*
* Memory range to remove is not at the edge of current
* memory range entry. Split the current memory entry into
* two half.
*/
else {
size = mem_rngs->ranges[i].end - end + 1;
mem_rngs->ranges[i].end = base - 1;
ret = add_mem_range(mem_ranges, end + 1, size);
}
}
out:
return ret;
}
#endif /* CONFIG_CRASH_DUMP */
Loading
Loading