//如果成功申请到了,就将这块地址保留下来 if (dt_virt) memblock_reserve(dt_phys, size);
//如果没有成功申请到,或者设备树早期扫描失败,直接宕机 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(); }
/* Early fixups are done, map the FDT as read-only now */ //重新将这段内存映射为只读的 fixmap_remap_fdt(dt_phys, &size, PAGE_KERNEL_RO); //功能无关,无需关注 dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name()); }
status = early_init_dt_verify(params); //由上面可以看到,基本上是fdt格式不对,或者crc校验不过,这里false返回 if (!status) returnfalse; //否者就先扫描设备树的节点 early_init_dt_scan_nodes(); returntrue; }
早期设备树节点的扫描,这一步主要是获得设备树的cells,别名,可选属性,内存信息等
1 2 3 4 5 6 7 8 9 10 11
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);
/** * unflatten_device_tree - create tree of device_nodes from flat blob * * unflattens the device-tree passed by the firmware, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used. */ void __init unflatten_device_tree(void) { __unflatten_device_tree(initial_boot_params, NULL, &of_root, early_init_dt_alloc_memory_arch, false);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */ of_alias_scan(early_init_dt_alloc_memory_arch); }
/** * __unflatten_device_tree - create tree of device_nodes from flat blob * * unflattens a device-tree, creating the * tree of struct device_node. It also fills the "name" and "type" * pointers of the nodes so the normal device-tree walking functions * can be used. * @blob: The blob to expand * @dad: Parent device node * @mynodes: The device_node tree created by the call * @dt_alloc: An allocator that provides a virtual address to memory * for the resulting tree * * Returns NULL on failure or the memory chunk containing the unflattened * device tree on success. */ staticvoid *__unflatten_device_tree(constvoid *blob, struct device_node *dad, struct device_node **mynodes, void *(*dt_alloc)(u64 size, u64 align), bool detached) { int size; void *mem;
pr_debug(" -> unflatten_device_tree()\n");
//blob是fdt的虚拟地址 if (!blob) { pr_debug("No device tree pointer\n"); returnNULL; }
/* Allocate memory for the expanded device tree */ //为node分配内存空间,注意调用的是传入的回调函数,并且size多了四个字节,用来放魔数 mem = dt_alloc(size + 4, __alignof__(struct device_node)); if (!mem) returnNULL;
/* Second pass, do actual unflattening */ //实际的展开dtb到node unflatten_dt_nodes(blob, mem, dad, mynodes); //超过边界了!!! if (be32_to_cpup(mem + size) != 0xdeadbeef) pr_warning("End of tree marker overwritten: %08x\n", be32_to_cpup(mem + size)); //如果设置了detached并且mynodes存在,将这个设备树设置为detached状态 if (detached && mynodes) { of_node_set_flag(*mynodes, OF_DETACHED); pr_debug("unflattened tree is detached\n"); }
/** * unflatten_dt_nodes - Alloc and populate a device_node from the flat tree * @blob: The parent device tree blob * @mem: Memory chunk to use for allocating device nodes and properties * @dad: Parent struct device_node * @nodepp: The device_node tree created by the call * * It returns the size of unflattened device tree or error code */ staticintunflatten_dt_nodes(constvoid *blob, void *mem, struct device_node *dad, struct device_node **nodepp) { structdevice_node *root; int offset = 0, depth = 0, initial_depth = 0; //节点最大嵌套深度 #define FDT_MAX_DEPTH 64 unsignedint fpsizes[FDT_MAX_DEPTH]; structdevice_node *nps[FDT_MAX_DEPTH]; void *base = mem; //这里的dryrun只有在没有传入mem时为真,此时只返回设备树展开后的大小,而不是真的展开设备树 bool dryrun = !base;
if (nodepp) *nodepp = NULL;
/* * We're unflattening device sub-tree if @dad is valid. There are * possibly multiple nodes in the first level of depth. We need * set @depth to 1 to make fdt_next_node() happy as it bails * immediately when negative @depth is found. Otherwise, the device * nodes except the first one won't be unflattened successfully. */ //如果dad存在,那么是展开子树,将下面这两个变量赋初值 if (dad) depth = initial_depth = 1;
/* version 0x10 has a more compact unit name here instead of the full * path. we accumulate the full path size using "fpsize", we'll rebuild * it later. We detect this because the first character of the name is * not '/'. */ if ((*pathp) != '/') { new_format = 1; if (fpsize == 0) { /* root node: special case. fpsize accounts for path * plus terminating zero. root node only has '/', so * fpsize should be 2, but we want to avoid the first * level nodes to have two '/' so we use fpsize 1 here */ fpsize = 1; allocl = 2; l = 1; pathp = ""; } else { /* account for '/' and path size minus terminal 0 * already in 'l' */ fpsize += l; allocl = fpsize; } }
np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl, __alignof__(struct device_node)); if (!dryrun) { char *fn; of_node_init(np); np->full_name = fn = ((char *)np) + sizeof(*np); if (new_format) { /* rebuild full path for new format */ if (dad && dad->parent) { strcpy(fn, dad->full_name); #ifdef DEBUG if ((strlen(fn) + l + 1) != allocl) { pr_debug("%s: p: %d, l: %d, a: %d\n", pathp, (int)strlen(fn), l, allocl); } #endif fn += strlen(fn); } *(fn++) = '/'; } memcpy(fn, pathp, l);
/* * Handle ramoops explicitly, since it is inside /reserved-memory, * which lacks a "compatible" property. */ node = of_find_node_by_path("/reserved-memory"); if (node) { node = of_find_compatible_node(node, NULL, "ramoops"); if (node) of_platform_device_create(node, NULL, NULL); }