#define pr_fmt(fmt) "OF: fdt: " fmt
+#include <linux/crash_dump.h>
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/initrd.h>
pp->length = len;
pp->value = pp + 1;
*pprev = pp;
- pprev = &pp->next;
memcpy(pp->value, ps, len - 1);
((char *)pp->value)[len - 1] = 0;
pr_debug("fixed up name for %s -> %s\n",
nodename, (char *)pp->value);
}
}
-
- if (!dryrun)
- *pprev = NULL;
}
static int populate_node(const void *blob,
static u32 of_fdt_crc32;
+static int __init early_init_dt_reserve_memory_arch(phys_addr_t base,
+ phys_addr_t size, bool nomap)
+{
+ if (nomap) {
+ /*
+ * If the memory is already reserved (by another region), we
+ * should not allow it to be marked nomap.
+ */
+ if (memblock_is_region_reserved(base, size))
+ return -EBUSY;
+
+ return memblock_mark_nomap(base, size);
+ }
+ return memblock_reserve(base, size);
+}
+
/*
* __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
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
*
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
+ reserve_elfcorehdr();
}
/**
return best_data;
}
-#ifdef CONFIG_BLK_DEV_INITRD
static void __early_init_dt_declare_initrd(unsigned long start,
unsigned long end)
{
int len;
const __be32 *prop;
+ if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
+ return;
+
pr_debug("Looking for initrd properties... ");
prop = of_get_flat_dt_prop(node, "linux,initrd-start", &len);
pr_debug("initrd_start=0x%llx initrd_end=0x%llx\n", start, end);
}
-#else
-static inline void early_init_dt_check_for_initrd(unsigned long node)
+
+/**
+ * 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);
+}
+
+static phys_addr_t cap_mem_addr;
+static phys_addr_t cap_mem_size;
+
+/**
+ * early_init_dt_check_for_usable_mem_range - Decode usable memory range
+ * location from flat tree
+ * @node: reference to node containing usable memory range location ('chosen')
+ */
+static void __init early_init_dt_check_for_usable_mem_range(unsigned long node)
{
+ const __be32 *prop;
+ int len;
+
+ pr_debug("Looking for usable-memory-range property... ");
+
+ prop = of_get_flat_dt_prop(node, "linux,usable-memory-range", &len);
+ if (!prop || (len < (dt_root_addr_cells + dt_root_size_cells)))
+ return;
+
+ cap_mem_addr = dt_mem_next_cell(dt_root_addr_cells, &prop);
+ cap_mem_size = dt_mem_next_cell(dt_root_size_cells, &prop);
+
+ pr_debug("cap_mem_start=%pa cap_mem_size=%pa\n", &cap_mem_addr,
+ &cap_mem_size);
}
-#endif /* CONFIG_BLK_DEV_INITRD */
#ifdef CONFIG_SERIAL_EARLYCON
if (!hotpluggable)
continue;
- if (early_init_dt_mark_hotplug_memory_arch(base, size))
+ if (memblock_mark_hotplug(base, size))
pr_warn("failed to mark hotplug range 0x%llx - 0x%llx\n",
base, base + size);
}
return 0;
early_init_dt_check_for_initrd(node);
+ early_init_dt_check_for_elfcorehdr(node);
+ early_init_dt_check_for_usable_mem_range(node);
/* Retrieve command line */
p = of_get_flat_dt_prop(node, "bootargs", &l);
memblock_add(base, size);
}
-int __init __weak early_init_dt_mark_hotplug_memory_arch(u64 base, u64 size)
-{
- return memblock_mark_hotplug(base, size);
-}
-
-int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
- phys_addr_t size, bool nomap)
-{
- if (nomap) {
- /*
- * If the memory is already reserved (by another region), we
- * should not allow it to be marked nomap.
- */
- if (memblock_is_region_reserved(base, size))
- return -EBUSY;
-
- return memblock_mark_nomap(base, size);
- }
- return memblock_reserve(base, size);
-}
-
static void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
{
void *ptr = memblock_alloc(size, align);
{
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);
+
+ /* Handle linux,usable-memory-range property */
+ memblock_cap_memory_range(cap_mem_addr, cap_mem_size);
}
bool __init early_init_dt_scan(void *params)