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