/*
* linux device tree 解析DTB文件
*/
/* 内核启动时解析DTB文件的调用 */
start_kernel -> setup_arch -> unflatten_device_tree ->
__unflatten_device_tree -> unflatten_dt_nodes (drivers/of/fdt.c)
/* 节点处理函数 */
查找节点的 of 函数
of_find_node_by_name
of_find_node_by_type
of_find_compatible_node
of_find_matching_node_and_match
of_find_node_by_path
查找父/子节点的 OF 函数
of_get_parent
of_get_next_child
提取属性值的 OF 函数
of_find_property
of_property_count_elems_of_size
of_property_read_u32_index
of_property_read_u8_array
of_property_read_u8
of_property_read_string
of_n_addr_cells
of_n_size_cells
of_iomap
/* unflatten_device_tree */
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);
unittest_unflatten_overlay_base();
}
void *initial_boot_params; (drivers/of/fdt.c)
struct device_node *of_root; (drivers/of/base.c)
在 unflatten_device_tree() 中,调用函数 __unflatten_device_tree(),
initial_boot_params 指向 Device Tree 在内存中的首地址,of_root 在经过该函数处理之后,会指向根节点.
early_init_dt_alloc_memory_arch 是一个函数指针,为 struct device_node 和 struct property 结构体分配内存的回调函数(callback)。
在 __unflatten_device_tree() 函数中,两次调用 unflatten_dt_node() 函数,
/* First pass, scan for size */
size = unflatten_dt_nodes(blob, NULL, dad, NULL);
/* Second pass, do actual unflattening */
unflatten_dt_nodes(blob, mem, dad, mynodes);
第一次是为了得到 Device Tree 转换成 struct device_node 和 struct property 结构体需要分配的内存大小,
第二次调用才是具体填充每一个 struct device_node 和 struct property 结构体。
struct device_node {
const char *name;
const char *type;
phandle phandle; /* typedef u32 phandle */
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
#if defined(CONFIG_OF_KOBJ)
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
const char *path_component_name;
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
struct property {
char *name;
int length;
void *value;
struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};