Skip to content

Commit

Permalink
of: fdt: Add generic support for handling elf core headers property
Browse files Browse the repository at this point in the history
There are two methods to specify the location of the elf core headers:
using the "elfcorehdr=" kernel parameter, as handled by generic code in
kernel/crash_dump.c, or using the "linux,elfcorehdr" property under the
"/chosen" node in the Device Tree, as handled by architecture-specific
code in arch/arm64/mm/init.c.

Extend support for "linux,elfcorehdr" to all platforms supporting DT by
adding platform-agnostic handling for handling this property to the FDT
core code.  This can co-exist safely with the architecture-specific
handling, until the latter has been removed.

This requires moving the call to of_scan_flat_dt() up, as the code
scanning the "/chosen" node now needs to be aware of the values of
"#address-cells" and "#size-cells".

Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Signed-off-by: Rob Herring <robh@kernel.org>
Link: https://lore.kernel.org/r/c7e46e50aaf87ef49bdaa61358d25b122f32b7df.1628670468.git.geert+renesas@glider.be
  • Loading branch information
Geert Uytterhoeven authored and Rob Herring committed Aug 24, 2021
1 parent 3370941 commit f7e7ce9
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 6 deletions.
6 changes: 3 additions & 3 deletions Documentation/devicetree/bindings/chosen.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ respectively, of the root node.
linux,elfcorehdr
----------------

This property (currently used only on arm64) holds the memory range,
the address and the size, of the elf core header which mainly describes
the panicked kernel's memory layout as PT_LOAD segments of elf format.
This property holds the memory range, the address and the size, of the elf
core header which mainly describes the panicked kernel's memory layout as
PT_LOAD segments of elf format.
e.g.

/ {
Expand Down
59 changes: 56 additions & 3 deletions drivers/of/fdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#define pr_fmt(fmt) "OF: fdt: " fmt

#include <linux/crash_dump.h>
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/initrd.h>
Expand Down Expand Up @@ -597,6 +598,30 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
return 0;
}

/*
* reserve_elfcorehdr() - reserves memory for elf core header
*
* This function reserves the memory occupied by an elf core header
* described in the device tree. This region contains all the
* information about primary kernel's core image and is used by a dump
* capture kernel to access the system memory on primary kernel.
*/
static void __init reserve_elfcorehdr(void)
{
if (!IS_ENABLED(CONFIG_CRASH_DUMP) || !elfcorehdr_size)
return;

if (memblock_is_region_reserved(elfcorehdr_addr, elfcorehdr_size)) {
pr_warn("elfcorehdr is overlapped\n");
return;
}

memblock_reserve(elfcorehdr_addr, elfcorehdr_size);

pr_info("Reserving %llu KiB of memory at 0x%llx for elfcorehdr\n",
elfcorehdr_size >> 10, elfcorehdr_addr);
}

/**
* early_init_fdt_scan_reserved_mem() - create reserved memory regions
*
Expand All @@ -622,6 +647,7 @@ void __init early_init_fdt_scan_reserved_mem(void)

of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
reserve_elfcorehdr();
}

/**
Expand Down Expand Up @@ -920,6 +946,32 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
}
#endif /* CONFIG_BLK_DEV_INITRD */

/**
* early_init_dt_check_for_elfcorehdr - Decode elfcorehdr location from flat
* tree
* @node: reference to node containing elfcorehdr location ('chosen')
*/
static void __init early_init_dt_check_for_elfcorehdr(unsigned long node)
{
const __be32 *prop;
int len;

if (!IS_ENABLED(CONFIG_CRASH_DUMP))
return;

pr_debug("Looking for elfcorehdr property... ");

prop = of_get_flat_dt_prop(node, "linux,elfcorehdr", &len);
if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells)))
return;

elfcorehdr_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
elfcorehdr_size = dt_mem_next_cell(dt_root_size_cells, &prop);

pr_debug("elfcorehdr_start=0x%llx elfcorehdr_size=0x%llx\n",
elfcorehdr_addr, elfcorehdr_size);
}

#ifdef CONFIG_SERIAL_EARLYCON

int __init early_init_dt_scan_chosen_stdout(void)
Expand Down Expand Up @@ -1067,6 +1119,7 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
return 0;

early_init_dt_check_for_initrd(node);
early_init_dt_check_for_elfcorehdr(node);

/* Retrieve command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
Expand Down Expand Up @@ -1190,14 +1243,14 @@ void __init early_init_dt_scan_nodes(void)
{
int rc = 0;

/* Initialize {size,address}-cells info */
of_scan_flat_dt(early_init_dt_scan_root, NULL);

/* Retrieve various information from the /chosen node */
rc = of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
if (!rc)
pr_warn("No chosen node found, continuing without\n");

/* Initialize {size,address}-cells info */
of_scan_flat_dt(early_init_dt_scan_root, NULL);

/* Setup memory, calling early_init_dt_add_memory_arch */
of_scan_flat_dt(early_init_dt_scan_memory, NULL);
}
Expand Down

0 comments on commit f7e7ce9

Please sign in to comment.