kenrel: 5.10
arch: arm64
如果节点名字为reserved-memory,则意味着找到了这个节点,则下一次遍历时会遍历reserved-memory的子节点,每个子节点描述了具体的预留地址范围,这个地址范围可能包含多组address,size 对,对于每个子节点查看nomap属性如果有定义,则需要从memblock.memory中移除对应的物理地址范围所涵盖的memblock_region,并添加到memblock.reserved中,如果没有定义,则只会添加到memblock.reserved中
/**
* fdt_scan_reserved_mem() - scan a single FDT node for reserved memory
*/
static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
int depth, void *data)
{
static int found;
int err;
if (!found && depth == 1 && strcmp(uname, "reserved-memory") == 0) {
if (__reserved_mem_check_root(node) != 0) {
pr_err("Reserved memory: unsupported node format, ignoring\n");
/* break scan */
return 1;
}
found = 1;
/* scan next node */
return 0;
} else if (!found) {
/* scan next node */
return 0;
} else if (found && depth < 2) {
/* scanning of /reserved-memory has been finished */
return 1;
}
if (!of_fdt_device_is_available(initial_boot_params, node))
return 0;
err = __reserved_mem_reserve_reg(node, uname);
if (err == -ENOENT && of_get_flat_dt_prop(node, "size", NULL))
fdt_reserved_mem_save_node(node, uname, 0, 0);
/* scan next node */
return 0;
}
- __reserved_mem_reserve_reg
解析reserve memoy node的一个子节点,将其描述的物理地址范围添加到memblock.reserved中,由于每个子节点描述的物理地址范围可以是多个,因此会通过while循环遍历,此处会将第一个地址范围通过fdt_reserved_mem_save_node初始化reserved_mem。reserved_mem数组是通过静态分配的,主要用于存放struct reserved_mem结构体,用于描述reserved memory的每个子节点
/**
* __reserved_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
static int __init __reserved_mem_reserve_reg(unsigned long node,
const char *uname)
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t base, size;
int len;
const __be32 *prop;
int first = 1;
bool nomap;
prop = of_get_flat_dt_prop(node, "reg", &len);
if (!prop)
return -ENOENT;
if (len && len % t_len != 0) {
pr_err("Reserved memory: invalid reg property in '%s', skipping node.\n",
uname);
return -EINVAL;
}
nomap = of_get_flat_dt_prop(node, "no-map", NULL) != NULL;
while (len >= t_len) {
base = dt_mem_next_cell(dt_root_addr_cells, &prop);
size = dt_mem_next_cell(dt_root_size_cells, &prop);
if (size &&
early_init_dt_reserve_memory_arch(base, size, nomap) == 0)
pr_debug("Reserved memory: reserved region for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
else
pr_info("Reserved memory: failed to reserve memory for node '%s': base %pa, size %ld MiB\n",
uname, &base, (unsigned long)size / SZ_1M);
len -= t_len;
if (first) {
fdt_reserved_mem_save_node(node, uname, base, size);
first = 0;
}
}
return 0;
}
- fdt_reserved_mem_save_node
初始化reserved_mem为静态定义的数组
/**
* fdt_reserved_mem_save_node() - save fdt node for second pass initialization
*/
void __init fdt_reserved_mem_save_node(unsigned long node, const char *uname,
phys_addr_t base, phys_addr_t size)
{
struct reserved_mem *rmem = &reserved_mem[reserved_mem_count];
if (reserved_mem_count == ARRAY_SIZE(reserved_mem)) {
pr_err("not enough space for all defined regions.\n");
return;
}
rmem->fdt_node = node;
rmem->name = uname;
rmem->base = base;
rmem->size = size;
reserved_mem_count++;
return;
}