Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions arch/arm64/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/memblock.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
Expand Down Expand Up @@ -51,6 +52,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
nr_ranges = 2; /* for exclusion of crashkernel region */
for_each_mem_range(i, &start, &end)
nr_ranges++;
nr_ranges += of_reserved_mem_kdump_nr_ranges();

cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
Expand All @@ -75,6 +77,10 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
goto out;
}

ret = of_reserved_mem_kdump_exclude(cmem);
if (ret)
goto out;

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

out:
Expand Down
6 changes: 6 additions & 0 deletions arch/loongarch/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/kernel.h>
#include <linux/kexec.h>
#include <linux/memblock.h>
#include <linux/of_reserved_mem.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/types.h>
Expand Down Expand Up @@ -67,6 +68,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
nr_ranges = 2; /* for exclusion of crashkernel region */
for_each_mem_range(i, &start, &end)
nr_ranges++;
nr_ranges += of_reserved_mem_kdump_nr_ranges();

cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
Expand All @@ -91,6 +93,10 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
goto out;
}

ret = of_reserved_mem_kdump_exclude(cmem);
if (ret)
goto out;

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

out:
Expand Down
4 changes: 4 additions & 0 deletions arch/riscv/kernel/machine_kexec_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include <linux/elf.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_reserved_mem.h>
#include <linux/libfdt.h>
#include <linux/types.h>
#include <linux/memblock.h>
Expand Down Expand Up @@ -64,6 +65,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)

nr_ranges = 1; /* For exclusion of crashkernel region */
walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
nr_ranges += of_reserved_mem_kdump_nr_ranges();

cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
if (!cmem)
Expand All @@ -77,6 +79,8 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)

/* Exclude crashkernel region */
ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
if (!ret)
ret = of_reserved_mem_kdump_exclude(cmem);
if (!ret)
ret = crash_prepare_elf64_headers(cmem, true, addr, sz);

Expand Down
11 changes: 9 additions & 2 deletions drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ void __init early_init_fdt_scan_reserved_mem(void)
int n;
int res;
u64 base, size;
int nr_memreserve = 0;

if (!initial_boot_params)
return;
Expand All @@ -516,7 +517,9 @@ void __init early_init_fdt_scan_reserved_mem(void)
if (!size)
break;
memblock_reserve(base, size);
nr_memreserve++;
}
fdt_reserved_mem_account_memreserve(nr_memreserve);
}

/**
Expand Down Expand Up @@ -1284,8 +1287,12 @@ void __init unflatten_device_tree(void)
{
void *fdt = initial_boot_params;

/* Save the statically-placed regions in the reserved_mem array */
fdt_scan_reserved_mem_late();
/* Attempt dynamic allocation of a new reserved_mem array */
if (fdt && alloc_reserved_mem_array()) {
/* Save the statically-placed regions in the reserved_mem array */
fdt_scan_reserved_mem_late();
fdt_reserved_mem_save_memreserve_entries();
}

/* Populate an empty root node when bootloader doesn't provide one */
if (!fdt) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/of/of_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,9 @@ static inline struct device_node *__of_get_dma_parent(const struct device_node *

int fdt_scan_reserved_mem(void);
void __init fdt_scan_reserved_mem_late(void);
bool __init alloc_reserved_mem_array(void);
void __init fdt_reserved_mem_account_memreserve(int n);
void __init fdt_reserved_mem_save_memreserve_entries(void);

bool of_fdt_device_is_available(const void *blob, unsigned long node);

Expand Down
117 changes: 107 additions & 10 deletions drivers/of/of_reserved_mem.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/memblock.h>
#include <linux/kmemleak.h>
#include <linux/crash_core.h>

#include "of_private.h"

Expand Down Expand Up @@ -69,29 +70,31 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
* the initial static array is copied over to this new array and
* the new array is used from this point on.
*/
static void __init alloc_reserved_mem_array(void)
bool __init alloc_reserved_mem_array(void)
{
struct reserved_mem *new_array;
size_t alloc_size, copy_size, memset_size;

if (!total_reserved_mem_cnt)
return true;

alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
if (alloc_size == SIZE_MAX) {
pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
return;
goto fail;
}

new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
if (!new_array) {
pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
return;
goto fail;
}

copy_size = array_size(reserved_mem_count, sizeof(*new_array));
if (copy_size == SIZE_MAX) {
memblock_free(new_array, alloc_size);
total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
return;
goto fail;
}

memset_size = alloc_size - copy_size;
Expand All @@ -100,6 +103,11 @@ static void __init alloc_reserved_mem_array(void)
memset(new_array + reserved_mem_count, 0, memset_size);

reserved_mem = new_array;
return true;

fail:
reserved_mem_count = 0;
return false;
}

static void fdt_init_reserved_mem_node(unsigned long node, const char *uname,
Expand Down Expand Up @@ -241,6 +249,43 @@ static void __init __rmem_check_for_overlap(void)
}
}

static void __init fdt_reserved_mem_add_memreserve(phys_addr_t base,
phys_addr_t size)
{
struct reserved_mem *rmem;
bool dumpable = false;
int i;

if (reserved_mem_count == total_reserved_mem_cnt) {
pr_err("not enough space for memreserve regions.\n");
return;
}

for (i = 0; i < reserved_mem_count; i++) {
rmem = &reserved_mem[i];

if (!rmem->dumpable)
continue;

if (base < rmem->base + rmem->size && rmem->base < base + size) {
dumpable = true;
break;
}
}

rmem = &reserved_mem[reserved_mem_count];
rmem->base = base;
rmem->size = size;
rmem->dumpable = dumpable;

reserved_mem_count++;
}

void __init fdt_reserved_mem_account_memreserve(int n)
{
total_reserved_mem_cnt += n;
}

/**
* fdt_scan_reserved_mem_late() - Scan FDT and initialize remaining reserved
* memory regions.
Expand All @@ -265,9 +310,6 @@ void __init fdt_scan_reserved_mem_late(void)
return;
}

/* Attempt dynamic allocation of a new reserved_mem array */
alloc_reserved_mem_array();

if (__reserved_mem_check_root(node)) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
return;
Expand Down Expand Up @@ -301,6 +343,24 @@ void __init fdt_scan_reserved_mem_late(void)
__rmem_check_for_overlap();
}

void __init fdt_reserved_mem_save_memreserve_entries(void)
{
const void *fdt = initial_boot_params;
u64 base, size;
int n;

if (!fdt)
return;

for (n = 0; ; n++) {
if (fdt_get_mem_rsv(fdt, n, &base, &size))
break;
if (!size)
break;
fdt_reserved_mem_add_memreserve(base, size);
}
}

static int __init __reserved_mem_alloc_size(unsigned long node, const char *uname);

/*
Expand All @@ -321,11 +381,14 @@ int __init fdt_scan_reserved_mem(void)
const void *fdt = initial_boot_params;

node = fdt_path_offset(fdt, "/reserved-memory");
if (node < 0)
if (node < 0) {
total_reserved_mem_cnt = 0;
return -ENODEV;
}

if (__reserved_mem_check_root(node) != 0) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
total_reserved_mem_cnt = 0;
return -EINVAL;
}

Expand Down Expand Up @@ -788,13 +851,47 @@ struct reserved_mem *of_reserved_mem_lookup(struct device_node *np)

name = kbasename(np->full_name);
for (i = 0; i < reserved_mem_count; i++)
if (!strcmp(reserved_mem[i].name, name))
if (reserved_mem[i].name &&
!strcmp(reserved_mem[i].name, name))
return &reserved_mem[i];

return NULL;
}
EXPORT_SYMBOL_GPL(of_reserved_mem_lookup);

/*
* Count non-dumpable reserved regions. Excluding each one may split a
* crash_mem range in two, callers use this to size the allocation.
*/
unsigned int of_reserved_mem_kdump_nr_ranges(void)
{
unsigned int i, n = 0;

for (i = 0; i < reserved_mem_count; i++)
if (reserved_mem[i].size && !reserved_mem[i].dumpable)
n++;
return n;
}

/* Exclude non-dumpable reserved regions from @cmem. */
int of_reserved_mem_kdump_exclude(struct crash_mem *cmem)
{
unsigned int i;
int ret;

for (i = 0; i < reserved_mem_count; i++) {
struct reserved_mem *r = &reserved_mem[i];

if (!r->size || r->dumpable)
continue;
ret = crash_exclude_mem_range(cmem, r->base,
r->base + r->size - 1);
if (ret)
return ret;
}
return 0;
}

/**
* of_reserved_mem_region_to_resource() - Get a reserved memory region as a resource
* @np: node containing 'memory-region' property
Expand Down
6 changes: 6 additions & 0 deletions include/linux/crash_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ static inline int kexec_should_crash(struct task_struct *p) { return 0; }
static inline int kexec_crash_loaded(void) { return 0; }
static inline void crash_save_cpu(struct pt_regs *regs, int cpu) {};
static inline int kimage_crash_copy_vmcoreinfo(struct kimage *image) { return 0; };
static inline int crash_exclude_mem_range(struct crash_mem *mem,
unsigned long long mstart,
unsigned long long mend)
{
return 0;
}
#endif /* CONFIG_CRASH_DUMP*/

#ifdef CONFIG_CRASH_DM_CRYPT
Expand Down
15 changes: 15 additions & 0 deletions include/linux/of_reserved_mem.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@
struct of_phandle_args;
struct reserved_mem_ops;
struct resource;
struct crash_mem;

struct reserved_mem {
const char *name;
const struct reserved_mem_ops *ops;
phys_addr_t base;
phys_addr_t size;
void *priv;
bool dumpable;
};

struct reserved_mem_ops {
Expand Down Expand Up @@ -47,6 +49,9 @@ int of_reserved_mem_region_to_resource_byname(const struct device_node *np,
const char *name, struct resource *res);
int of_reserved_mem_region_count(const struct device_node *np);

unsigned int of_reserved_mem_kdump_nr_ranges(void);
int of_reserved_mem_kdump_exclude(struct crash_mem *cmem);

#else

#define RESERVEDMEM_OF_DECLARE(name, compat, ops) \
Expand Down Expand Up @@ -91,6 +96,16 @@ static inline int of_reserved_mem_region_count(const struct device_node *np)
{
return 0;
}

static inline unsigned int of_reserved_mem_kdump_nr_ranges(void)
{
return 0;
}

static inline int of_reserved_mem_kdump_exclude(struct crash_mem *cmem)
{
return 0;
}
#endif

/**
Expand Down
1 change: 1 addition & 0 deletions kernel/dma/contiguous.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,7 @@ static int __init rmem_cma_setup(unsigned long node, struct reserved_mem *rmem)
dma_contiguous_default_area = cma;

rmem->priv = cma;
rmem->dumpable = true;

pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
&rmem->base, (unsigned long)rmem->size / SZ_1M);
Expand Down