memblock从类型上面来分,分为三类:memory, reserve和physmem.常见的就是普通的memory和reserve的memory。
struct memblock {
bool bottom_up; /* is bottom up direction? */
phys_addr_t current_limit;
struct memblock_type memory;
struct memblock_type reserved;
#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP
struct memblock_type physmem;
#endif
};
首先从start_kernel->setup_arch->setup_machine_fdt()进行FDT的扫描。
static void __init setup_machine_fdt(phys_addr_t dt_phys)
{
void *dt_virt = fixmap_remap_fdt(dt_phys);
if (!dt_virt || !early_init_dt_scan(dt_virt)) {
pr_crit("\n"
"Error: invalid device tree blob at physical address %pa (virtual address 0x%p)\n"
"The dtb must be 8-byte aligned and must not exceed 2 MB in size\n"
"\nPlease check your bootloader.",
&dt_phys, dt_virt);
while (true)
cpu_relax();
}
dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
}
在此函数中将FDT的物理地址通过fixmap_remap_fdt转化为虚拟地址,然后通过early_init_dt_scan->early_init_dt_scan_nodes函数来遍历整个FDT。
void __init early_init_dt_scan_nodes(void)
{
/* Retrieve various information from the /chosen node */
of_scan_flat_dt(early_init_dt_scan_chosen, boot_command_line);
/* 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);
}
首先通过of_scan_flat_dt针对FDT的每一个node执行callback函数。
early_init_dt_scan_chosen函数主要是找到chosen节点并将相关参数写到boot_command_line中去。
early_init_dt_scan_root函数获取root节点的size_cell和addr_cell的值。
early_init_dt_scan_memory获取memory节点的reg属性中的起始地址和大小,并通过early_init_dt_add_memory_arch函数添加到memory type的memblock中去。