以 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
- ...