解析设备树的流程(获取dtb内存地址->创建设备树内存表->创建注册设备及总线)

一、汇编相关部分的代码流程分析

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

ENTRY(stext)    {//head.S (kernel-3.10\arch\arm\kernel)

  bl    __lookup_processor_type

  bl    __vet_atags

  bl    __fixup_smp

  bl    __create_page_tables

  ldr   r13, =__mmap_switched        //__mmap_switched是一个函数,具体在head-common.S (kernel-3.10\arch\arm\kernel)

  b __enable_mmu    {

    b   __turn_mmu_on {

      mov   r3, r13

      mov   pc, r3  {        //调到r13中存放的地址去执行,即执行__mmap_switched函数。

        b   start_kernel        //跳转到start_kernel函数去执行,该函数具体在kernel-3.10\init\Main.c

      }

    }

  }

}

二、C相关的函数流程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

start_kernel(void)  {   // kernel-3.10\init\Main.c

  setup_arch(&command_line);    {   // kernel-3.10\arch\arm\kernel\Setup.c

    struct machine_desc *mdesc;

    mdesc = setup_machine_fdt(__atags_pointer);     {       //setup_machine_fdt(unsigned int dt_phys)

      devtree = phys_to_virt(dt_phys);

      initial_boot_params = devtree;        // initial_boot_params 变量为全局变量,在后面的解析设备树会用到

    }

    mdesc = setup_machine_tags(__atags_pointer, __machine_arch_type);       {   //if (!mdesc)

      for_each_machine_desc(p){         //#define for_each_machine_desc(p)      for (p = __arch_info_begin; p < __arch_info_end; p++)

        if (machine_nr == p->nr){

          mdesc = p;

          break;

        }

      }

    }

    machine_desc = mdesc;               //注意全局变量 machine_desc

    unflatten_device_tree();    {

      __unflatten_device_tree(initial_boot_params, &of_allnodes, early_init_dt_alloc_memory_arch); {    //注意全局参数  of_allnodes       create tree of device_nodes from flat blob

        struct device_node **allnextp = &of_allnodes;

        start = ((unsigned long)blob) + be32_to_cpu(blob->off_dt_struct);        //获取fdt开始的地址

        size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);       //先获取到需要的内存大小

        mem = (unsigned long)dt_alloc(size + 4, __alignof__(struct device_node));  //分配内存

        unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);       //解析所有的fdt_node Alloc and populate a device_node from the flat tree

      }

      of_alias_scan(early_init_dt_alloc_memory_arch);   {   //把设备树中的/chosen 和 /aliases 节点解析出来,单独放到一个变量中

                                                                                                                //Get pointer to "/chosen" and "/aliasas" nodes for use everywhere

        of_chosen = of_find_node_by_path("/chosen");        //注意变量  of_chosen, 在Base.c (kernel-3.10\drivers\of) 文件中共享

        of_aliases = of_find_node_by_path("/aliases");  //注意变量  of_aliases, 在Base.c (kernel-3.10\drivers\of)    文件中共享

        for_each_property_of_node(of_aliases, pp) {

          of_alias_add(ap, np, id, start, len);

            list_add_tail(&ap->link, &aliases_lookup);   //注意变量 aliases_lookup,把 /aliases中的元素全部解析到该链表

        }

      }

    }

  }

  rest_init();{

    kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND); {       //启动一个内核线程,运行kernel_init函数

      ... ...                                       //经过一系列的初始化后,运行kernel_init函数

      kernel_init(void *unused){

        kernel_init_freeable();{

          do_basic_setup();{

            do_initcalls();{

              for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++){

                do_initcall_level(level);{

                  for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++){

                    do_one_initcall(*fn);{

                      fn();

                    }

                  }

                }

              }

            }

          }

        }

      }

    }

  }

}

三、友情提供相关信息

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

{

    #define DT_MACHINE_START(_name, _namestr)       \

    static const struct machine_desc __mach_desc_##_name    \

     __used                         \

     __attribute__((__section__(".arch.info.init"))) = {    \

        .nr     = ~0,               \

        .name       = _namestr,

    }

     

    Core.c (kernel-3.10\drivers\misc\mediatek\mach\mt6735)  2632    2016/9/14

         

    DT_MACHINE_START(MT6735_DT, "MT6735")

        .map_io     = mt_map_io,

        .smp        = smp_ops(mt_smp_ops),

        /*.init_irq = mt_dt_init_irq,*/

        /*.init_time    = mt_timer_init,*/

        .init_machine   = mt_init,

        .fixup      = mt_dt_fixup,

        /* FIXME: need to implement the restart function */

        .restart    = arm_machine_restart,

        .reserve    = mt_reserve,

      .dt_compat  = mt_dt_match,

    MACHINE_END    

 

    .init.arch.info : {

      __arch_info_begin = .;

      *(.arch.info.init)

      __arch_info_end = .;

    }

}

四、接下来执行那些initcall函数:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

arch_initcall(customize_machine);   {   //Setup.c (kernel-3.10\arch\arm\kernel)         // 解析设备树中的所有顶层的节点和符合match节点的子节点,添加到platform BUS的设备链表中

    customize_machine(void) {

        machine_desc->init_machine();        //此处就是我们友情提供的信息中的相关函数

        mt_init(void)   {

            mt_dt_init();{

                of_platform_populate(NULL, dt_bus_match, NULL, NULL);{

                    root = of_find_node_by_path("/");{

                        根据of_allnodes中的所有节点,找到根节点

                    }

                    for_each_child_of_node(root, child){

                        of_platform_bus_create(child, matches, lookup, parent, true);{

                            dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent); {    //创建一个platform设备的结构体,并加到链表中

                                dev = of_device_alloc(np, bus_id, parent);      //为platform设备结构体分配内存

                                dev->dev.bus = &platform_bus_type;       //指定设备bus为platform

                                of_device_add(dev); {                       //添加设备结构体到链表中

                                    device_add(&ofdev->dev); {

                                        bus_add_device(dev);{

                                            struct bus_type *bus = bus_get(dev->bus);

                                            klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);

                                        }

                                        dpm_sysfs_add(dev);

                                        device_pm_add(dev);{

                                            list_add_tail(&dev->power.entry, &dpm_list);

                                        }

                                        bus_probe_device(dev);{

                                            //把添加的设备与该总线下的驱动进行一一适配

                                        }

                                    }

                                }

                            }

                            if (!dev || !of_match_node(matches, bus))

                                return 0;       //如果该节点没有子节点或者分配失败,则返回。

                            for_each_child_of_node(bus, child){     //递归调用,将所有子节点均添加到platform bus下面。

                                of_platform_bus_create(child, matches, lookup, &dev->dev, strict);

                            }

                        }

                    }

                }

            }

        }

    }

}

 

module_init(mt_i2c_init);   {       //I2c.c (kernel-3.10\drivers\misc\mediatek\i2c\mt6735)  //注册I2C平台驱动,把符合I2C match的节点解析出来,添加到I2C BUS的设备链表中

    platform_driver_register(&mt_i2c_driver);

        ... ...

        mt_i2c_probe(struct platform_device *pdev)  {

            mt_i2c *i2c = kzalloc(sizeof(mt_i2c), GFP_KERNEL);

            i2c->adap.dev.of_node  = pdev->dev.of_node;

            i2c_add_numbered_adapter(&i2c->adap);    {       //注册i2c的adapter

                __i2c_add_numbered_adapter(adap);{

                    i2c_register_adapter(adap);{

                        adap->dev.bus = &i2c_bus_type;

                        adap->dev.type = &i2c_adapter_type;

                        device_register(&adap->dev);

                    }

                }

            }

            of_i2c_register_devices(&i2c->adap); {       //注册I2C adapter节点下面的全部I2C设备

                for_each_available_child_of_node(adap->dev.of_node, node)    {

                    i2c_new_device(adap, &info);    {

                        struct i2c_client   *client = kzalloc(sizeof *client, GFP_KERNEL);

                        client->dev.bus = &i2c_bus_type;

                        client->dev.type = &i2c_client_type;

                        device_register(&client->dev);{

                            device_add(dev);{

                                bus_add_device(dev);{

                                    klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices);

                                }

                                device_pm_add(dev);{

                                    list_add_tail(&dev->power.entry, &dpm_list);

                                }

                            }

                        }

                    }

                }

            }

        }

}

 

module_init ( mt_spi_init );{ //Spi.c (kernel-3.10\drivers\misc\mediatek\spi\mt6735)    //注册I2C平台驱动,把符合spi match的节点解析出来,添加到SPI BUS的设备链表中

    platform_driver_register ( &mt_spi_driver );

        ... ...

        mt_spi_probe(struct platform_device *pdev){

            struct spi_master *master = spi_alloc_master(&pdev->dev, sizeof(struct mt_spi_t));

            ms = spi_master_get_devdata(master);

            ms->pdev =   pdev;

            spi_register_master ( master );{

                of_spi_register_master(master);{

                    //这里面没有继续向后分析

                }

                device_add(&master->dev);{

                    //老生常谈的步骤,就不再继续分析。

                }

                list_add_tail(&master->list, &spi_master_list);

                /* Register devices from the device tree and ACPI */

                of_register_spi_devices(master);{

                    for_each_available_child_of_node(master->dev.of_node, nc){

                        spi = spi_alloc_device(master);{

                            spi = kzalloc(sizeof *spi, GFP_KERNEL);

                            spi->master = master;

                            spi->dev.bus = &spi_bus_type;

                        }

                        spi_add_device(spi);{

                            device_add(&spi->dev);{

                                //老生常谈的步骤,不再分析。

                            }

                        }

                    }

                }

                acpi_register_spi_devices(master);{

                    //没有具体分析,不清楚什么功能

                }

            }

        }

}

五、initcall的执行顺序:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#define pure_initcall(fn)       __define_initcall(fn, 0)

#define core_initcall(fn)       __define_initcall(fn, 1)

#define core_initcall_sync(fn)      __define_initcall(fn, 1s)

#define postcore_initcall(fn)       __define_initcall(fn, 2)

#define postcore_initcall_sync(fn)  __define_initcall(fn, 2s)

#define arch_initcall(fn)       __define_initcall(fn, 3)

#define arch_initcall_sync(fn)      __define_initcall(fn, 3s)

#define subsys_initcall(fn)     __define_initcall(fn, 4)

#define subsys_initcall_sync(fn)    __define_initcall(fn, 4s)

#define fs_initcall(fn)         __define_initcall(fn, 5)

#define fs_initcall_sync(fn)        __define_initcall(fn, 5s)

#define rootfs_initcall(fn)     __define_initcall(fn, rootfs)

#define device_initcall(fn)     __define_initcall(fn, 6)

#define device_initcall_sync(fn)    __define_initcall(fn, 6s)

#define late_initcall(fn)       __define_initcall(fn, 7)

#define late_initcall_sync(fn)      __define_initcall(fn, 7s)

若等级相同,则根据编译进目标代码的顺序执行。

注意Init.h (kernel-3.10\include\linux) 中的宏的定义:
在编译进内核时,MODULE 是没有定义的,所以 #ifndef MODULE 是真的;
当编译成.ko模块时,MODULE 是已经定义的, #ifndef MODULE 为假;

也就是根据编译到的目的地方不同,所定义的宏也不一致:
例如:
#ifndef MODULE
#define arch_initcall(fn) __define_initcall(fn, 3)
#else
#define arch_initcall(fn) module_init(fn)
#endif

 

在MODULE被定义的情况下(大部分可动态加载的driver模块都属于此, obj-m),module_init定义如下:

#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));

这段宏定义关键点是后面一句,通过alias将initfn变名为init_module。
前面那个__inittest的定义其实是种技巧,用来对initfn进行某种静态的类型检查,
如果阁下将模块初始化函数定义成,比如,void gpio_init(void)或者是int gpio_init(int),
那么在编译时都会有类似下面的warning:
GPIO/fsl-gpio.c: In function '__inittest':
GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

通过module_init将模块初始化函数统一别名为init_module,这样以后insmod时候,
在系统内部会调用sys_init_module()去找到init_module函数的入口地址。
如果objdump -t gpio.ko,就会发现init_module和gpio_init位于相同的地址偏移处。
简言之,这种情况下模块的初始化函数在insmod时候被调用

六、编译和反编译设备树

单独编译设备树:

  cd linux-x.xx & make dtbs

生成的dtb在目录linux-x.xx/arch/xxx/boot/dts下;

Android系统对应的目录为:out\target\product\rq6735_35gt_b_l1\obj\KERNEL_OBJ\arch\arm\boot\dts下;

生成的目标文件的后缀为.dtb。

 

利用dtc工具,反编译dtb,生成dts:

  Linux源码生成的工具路径:linux-x.xx/scripts/dtc/dtc

  Android源码生成的工具路径:out\target\product\rq6735_35gt_b_l1\obj\KERNEL_OBJ\scripts\dtc\dtc

 

  ./dtc -I dtb -O dts xxxx.dtb -o xxxx.dts 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值