// SPDX-License-Identifier: GPL-2.0
/*
* Functions for working with the Flattened Device Tree data format
*
* Copyright 2009 Benjamin Herrenschmidt, IBM Corp
* benh@kernel.crashing.org
*/
#define pr_fmt(fmt) "OF: fdt: " fmt
#include <linux/acpi.h>
#include <linux/crash_dump.h>
#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/sizes.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/libfdt.h>
#include <linux/debugfs.h>
#include <linux/serial_core.h>
#include <linux/sysfs.h>
#include <linux/random.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include <asm/page.h>
#include "of_private.h"
/*
* __dtb_empty_root_begin[] and __dtb_empty_root_end[] magically created by
* cmd_dt_S_dtb in scripts/Makefile.lib
*/
extern uint8_t __dtb_empty_root_begin[];
extern uint8_t __dtb_empty_root_end[];
/*
* of_fdt_limit_memory - limit the number of regions in the /memory node
* @limit: maximum entries
*
* Adjust the flattened device tree to have at most 'limit' number of
* memory entries in the /memory node. This function may be called
* any time after initial_boot_param is set.
*/
void __init of_fdt_limit_memory(int limit)
{
int memory;
int len;
const void *val;
int nr_address_cells = OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
int nr_size_cells = OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
const __be32 *addr_prop;
const __be32 *size_prop;
int root_offset;
int cell_size;
root_offset = fdt_path_offset(initial_boot_params, "/");
if (root_offset < 0)
return;
addr_prop = fdt_getprop(initial_boot_params, root_offset,
"#address-cells", NULL);
if (addr_prop)
nr_address_cells = fdt32_to_cpu(*addr_prop);
size_prop = fdt_getprop(initial_boot_params, root_offset,
"#size-cells", NULL);
if (size_prop)
nr_size_cells = fdt32_to_cpu(*size_prop);
cell_size = sizeof(uint32_t)*(nr_address_cells + nr_size_cells);
memory = fdt_path_offset(initial_boot_params, "/memory");
if (memory > 0) {
val = fdt_getprop(initial_boot_params, memory, "reg", &len);
if (len > limit*cell_size) {
len = limit*cell_size;
pr_debug("Limiting number of entries to %d\n", limit);
fdt_setprop(initial_boot_params, memory, "reg", val,
len);
}
}
}
bool of_fdt_device_is_available(const void *blob, unsigned long node)
{
const char *status = fdt_getprop(blob, node, "status", NULL);
if (!status)
return true;
if (!strcmp(status, "ok") || !strcmp(status, "okay"))
return true;
return false;
}
static void *unflatten_dt_alloc(void **mem, unsigned long size,
unsigned long align