Commit 0d3ff067 authored by Sourabh Jain's avatar Sourabh Jain Committed by Michael Ellerman

powerpc/kexec_file: fix extra size calculation for kexec FDT

While setting up the FDT for kexec, CPU nodes that are added after the
system boots and reserved memory ranges are incorporated into the
initial_boot_params (base FDT).

However, they are not taken into account when determining the additional
size needed for the kexec FDT. As a result, kexec fails to load,
generating the following error:

[1116.774451] Error updating memory reserve map: FDT_ERR_NOSPACE
kexec_file_load failed: No such process

Therefore, consider the extra size for CPU nodes added post-system boot
and reserved memory ranges while preparing the kexec FDT.

While adding a new parameter to the setup_new_fdt_ppc64 function, it was
noticed that there were a couple of unused parameters, so they were
removed.
Signed-off-by: default avatarSourabh Jain <sourabhjain@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240510102235.2269496-2-sourabhjain@linux.ibm.com
parent 0300a92e
...@@ -103,10 +103,8 @@ int load_crashdump_segments_ppc64(struct kimage *image, ...@@ -103,10 +103,8 @@ int load_crashdump_segments_ppc64(struct kimage *image,
int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, int setup_purgatory_ppc64(struct kimage *image, const void *slave_code,
const void *fdt, unsigned long kernel_load_addr, const void *fdt, unsigned long kernel_load_addr,
unsigned long fdt_load_addr); unsigned long fdt_load_addr);
unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image); unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem);
int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem);
unsigned long initrd_load_addr,
unsigned long initrd_len, const char *cmdline);
#endif /* CONFIG_PPC64 */ #endif /* CONFIG_PPC64 */
#endif /* CONFIG_KEXEC_FILE */ #endif /* CONFIG_KEXEC_FILE */
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/of_fdt.h> #include <linux/of_fdt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
#include <asm/kexec_ranges.h>
static void *elf64_load(struct kimage *image, char *kernel_buf, static void *elf64_load(struct kimage *image, char *kernel_buf,
unsigned long kernel_len, char *initrd, unsigned long kernel_len, char *initrd,
...@@ -36,6 +37,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, ...@@ -36,6 +37,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
const void *slave_code; const void *slave_code;
struct elfhdr ehdr; struct elfhdr ehdr;
char *modified_cmdline = NULL; char *modified_cmdline = NULL;
struct crash_mem *rmem = NULL;
struct kexec_elf_info elf_info; struct kexec_elf_info elf_info;
struct kexec_buf kbuf = { .image = image, .buf_min = 0, struct kexec_buf kbuf = { .image = image, .buf_min = 0,
.buf_max = ppc64_rma_size }; .buf_max = ppc64_rma_size };
...@@ -102,17 +104,20 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, ...@@ -102,17 +104,20 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr); kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr);
} }
ret = get_reserved_memory_ranges(&rmem);
if (ret)
goto out;
fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr,
initrd_len, cmdline, initrd_len, cmdline,
kexec_extra_fdt_size_ppc64(image)); kexec_extra_fdt_size_ppc64(image, rmem));
if (!fdt) { if (!fdt) {
pr_err("Error setting up the new device tree.\n"); pr_err("Error setting up the new device tree.\n");
ret = -EINVAL; ret = -EINVAL;
goto out; goto out;
} }
ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, ret = setup_new_fdt_ppc64(image, fdt, rmem);
initrd_len, cmdline);
if (ret) if (ret)
goto out_free_fdt; goto out_free_fdt;
...@@ -146,6 +151,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, ...@@ -146,6 +151,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf,
out_free_fdt: out_free_fdt:
kvfree(fdt); kvfree(fdt);
out: out:
kfree(rmem);
kfree(modified_cmdline); kfree(modified_cmdline);
kexec_free_elf_info(&elf_info); kexec_free_elf_info(&elf_info);
......
...@@ -803,10 +803,9 @@ static unsigned int cpu_node_size(void) ...@@ -803,10 +803,9 @@ static unsigned int cpu_node_size(void)
return size; return size;
} }
static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image, unsigned int cpu_nodes)
{ {
unsigned int cpu_nodes, extra_size = 0; unsigned int extra_size = 0;
struct device_node *dn;
u64 usm_entries; u64 usm_entries;
#ifdef CONFIG_CRASH_HOTPLUG #ifdef CONFIG_CRASH_HOTPLUG
unsigned int possible_cpu_nodes; unsigned int possible_cpu_nodes;
...@@ -826,18 +825,6 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) ...@@ -826,18 +825,6 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image)
extra_size += (unsigned int)(usm_entries * sizeof(u64)); extra_size += (unsigned int)(usm_entries * sizeof(u64));
} }
/*
* Get the number of CPU nodes in the current DT. This allows to
* reserve places for CPU nodes added since the boot time.
*/
cpu_nodes = 0;
for_each_node_by_type(dn, "cpu") {
cpu_nodes++;
}
if (cpu_nodes > boot_cpu_node_count)
extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size();
#ifdef CONFIG_CRASH_HOTPLUG #ifdef CONFIG_CRASH_HOTPLUG
/* /*
* Make sure enough space is reserved to accommodate possible CPU nodes * Make sure enough space is reserved to accommodate possible CPU nodes
...@@ -861,16 +848,30 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) ...@@ -861,16 +848,30 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image)
* *
* Returns the estimated extra size needed for kexec/kdump kernel FDT. * Returns the estimated extra size needed for kexec/kdump kernel FDT.
*/ */
unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image) unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem)
{ {
unsigned int extra_size = 0; struct device_node *dn;
unsigned int cpu_nodes = 0, extra_size = 0;
// Budget some space for the password blob. There's already extra space // Budget some space for the password blob. There's already extra space
// for the key name // for the key name
if (plpks_is_available()) if (plpks_is_available())
extra_size += (unsigned int)plpks_get_passwordlen(); extra_size += (unsigned int)plpks_get_passwordlen();
return extra_size + kdump_extra_fdt_size_ppc64(image); /* Get the number of CPU nodes in the current device tree */
for_each_node_by_type(dn, "cpu") {
cpu_nodes++;
}
/* Consider extra space for CPU nodes added since the boot time */
if (cpu_nodes > boot_cpu_node_count)
extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size();
/* Consider extra space for reserved memory ranges if any */
if (rmem->nr_ranges > 0)
extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges;
return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes);
} }
static int copy_property(void *fdt, int node_offset, const struct device_node *dn, static int copy_property(void *fdt, int node_offset, const struct device_node *dn,
...@@ -924,18 +925,13 @@ static int update_pci_dma_nodes(void *fdt, const char *dmapropname) ...@@ -924,18 +925,13 @@ static int update_pci_dma_nodes(void *fdt, const char *dmapropname)
* being loaded. * being loaded.
* @image: kexec image being loaded. * @image: kexec image being loaded.
* @fdt: Flattened device tree for the next kernel. * @fdt: Flattened device tree for the next kernel.
* @initrd_load_addr: Address where the next initrd will be loaded. * @rmem: Reserved memory ranges.
* @initrd_len: Size of the next initrd, or 0 if there will be none.
* @cmdline: Command line for the next kernel, or NULL if there will
* be none.
* *
* Returns 0 on success, negative errno on error. * Returns 0 on success, negative errno on error.
*/ */
int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem)
unsigned long initrd_load_addr,
unsigned long initrd_len, const char *cmdline)
{ {
struct crash_mem *umem = NULL, *rmem = NULL; struct crash_mem *umem = NULL;
int i, nr_ranges, ret; int i, nr_ranges, ret;
#ifdef CONFIG_CRASH_DUMP #ifdef CONFIG_CRASH_DUMP
...@@ -991,10 +987,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, ...@@ -991,10 +987,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
goto out; goto out;
/* Update memory reserve map */ /* Update memory reserve map */
ret = get_reserved_memory_ranges(&rmem);
if (ret)
goto out;
nr_ranges = rmem ? rmem->nr_ranges : 0; nr_ranges = rmem ? rmem->nr_ranges : 0;
for (i = 0; i < nr_ranges; i++) { for (i = 0; i < nr_ranges; i++) {
u64 base, size; u64 base, size;
...@@ -1014,7 +1006,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, ...@@ -1014,7 +1006,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
ret = plpks_populate_fdt(fdt); ret = plpks_populate_fdt(fdt);
out: out:
kfree(rmem);
kfree(umem); kfree(umem);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment