http://blog.chinaunix.net/uid-20522771-id-3785808.html
本文代码均来自标准 linux kernel 3.10,可以到这里下载 https://www.kernel.org/
以 arch/arm/mach-msm/board-dt-8960.c 为例,在该文件中的 msm_dt_init 函数的作用就是利用 dt(device tree)结构初始化 platform device。
点击(此处)折叠或打开
- static void __init msm_dt_init(void)
- {
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
- }
点击(此处)折叠或打开
- int of_platform_populate(struct device_node *root,
- const struct of_device_id *matches,
- const struct of_dev_auxdata *lookup,
- struct device *parent)
- {
- struct device_node *child;
- int rc = 0;
- root = root ? of_node_get(root) : of_find_node_by_path("/");
- if (!root)
- return -EINVAL;
- for_each_child_of_node(root, child) {
- rc = of_platform_bus_create(child, matches, lookup, parent, true);
- if (rc)
- break;
- }
- of_node_put(root);
- return rc;
- }
在 of_platform_populate 中如果 root 为 NULL,则将 root 赋值为根节点,这个根节点是用 of_find_node_by_path 取到的。
点击(此处)折叠或打开
- struct device_node *of_find_node_by_path(const char *path)
- {
- struct device_node *np = of_allnodes;
- unsigned long flags;
- raw_spin_lock_irqsave(&devtree_lock, flags);
- for (; np; np = np->allnext) {
- if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
- && of_node_get(np))
- break;
- }
- raw_spin_unlock_irqrestore(&devtree_lock, flags);
- return np;
- }
点击(此处)折叠或打开
- struct device_node *of_allnodes;
既然如此,我们来看看 kernel 初始化的代码(init/main.c),大部分代码与本主题无关用 ... 代替。
点击(此处)折叠或打开
- asmlinkage void __init start_kernel(void)
- {
- ...
- setup_arch(&command_line);
- ...
- }
同样,无关的代码以 ... 代替。
点击(此处)折叠或打开
- void __init setup_arch(char **cmdline_p)
- {
- ...
- mdesc = setup_machine_fdt(__atags_pointer);
- ...
- unflatten_device_tree();
- ...
- }
点击(此处)折叠或打开
- /* kernel/arch/arm/kernel/devtree.c */
- struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
- {
- ...
- devtree = phys_to_virt(dt_phys);
- ...
- initial_boot_params = devtree;
- ...
- }
点击(此处)折叠或打开
- struct boot_param_header {
- __be32 magic; /* magic word OF_DT_HEADER */
- __be32 totalsize; /* total size of DT block */
- __be32 off_dt_struct; /* offset to structure */
- __be32 off_dt_strings; /* offset to strings */
- __be32 off_mem_rsvmap; /* offset to memory reserve map */
- __be32 version; /* format version */
- __be32 last_comp_version; /* last compatible version */
- /* version 2 fields below */
- __be32 boot_cpuid_phys; /* Physical CPU id we're booting on */
- /* version 3 fields below */
- __be32 dt_strings_size; /* size of the DT strings block */
- /* version 17 fields below */
- __be32 dt_struct_size; /* size of the DT structure block */
- };
点击(此处)折叠或打开
- /* kernel/drivers/of/fdt.c */
- void __init unflatten_device_tree(void)
- {
- __unflatten_device_tree(initial_boot_params, &of_allnodes,
- early_init_dt_alloc_memory_arch);
- ...
- }
到此为止,device tree 的初始化就算完成了,在以后的启动过程中,kernel 就会依据这个 dt 来初始化各个设备。但是还有一个小问题,那就是在 setup_arch 函数中 __atags _pointer 从何而来。全局搜索这个变量,结构在 arch/arm/kernel/head-common.S 中发现了它的踪迹。
点击(此处)折叠或打开
- #define ATAG_CORE 0x54410001
- ...
- __mmap_switched:
- adr r3, __mmap_switched_data
- ldmia {r4, r5, r6, r7}
- ...
- THUMB( ldr sp, [r3, #16] )
- ...
- str r2, [r6] @ Save atags pointer
- ...
- __mmap_switched_data:
- ...
- .long __atags_pointer @ r6
- ...