I.Mx6 3.0.35 MACHINE_START 分析

1、在/arch/arm 目录下有许多与具体处理器相关的目录,对于I.Mx6q 对应的目录就是 arch/arm/mach-mx6/

在里面找到与具体板子相关的文件 board-mx6q_sabresd.c ,这个文件大部分内容是对平台设备(如nand,串口,spi,nor等)

的结构体的初始化。在这个文件的最后有一个非常重要的宏:

/*

 * initialize __mach_desc_MX6Q_SABRESD data structure.

 */

MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")

    /* Maintainer: Freescale Semiconductor, Inc. */

    .boot_params = MX6_PHYS_OFFSET + 0x100,

    .fixup = fixup_mxc_board,

    .map_io = mx6_map_io,

    .init_irq = mx6_init_irq,

    .init_machine = mx6_sabresd_board_init,

    .timer = &mx6_sabresd_timer,

    .reserve = mx6q_sabresd_reserve,

MACHINE_END

 

MACHINE_START 的定义在 arch/arm/include/asm/mach/arch.h 中,如下:

/*

 * Set of macros to define architecture features.  This is built into

 * a table by the linker.

 */

#define MACHINE_START(_type,_name)            \

static const struct machine_desc __mach_desc_##_type    \

 __used                            \

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

    .nr        = MACH_TYPE_##_type,        \

    .name        = _name,



#define MACHINE_END                \

};

其定义了一个 struct machine_desc 类型的结构体变量。

 

2、那么这个结构体变量在哪里被调用,从而调用它里面的成员和成员函数呢?

在 arch/arm/kernel/setup.c 中查看 setup_arch()

void __init setup_arch(char **cmdline_p)

{

    struct machine_desc *mdesc;



    unwind_init();



    setup_processor();

    mdesc = setup_machine_fdt(__atags_pointer);

    if (!mdesc)

        mdesc = setup_machine_tags(machine_arch_type);

    machine_desc = mdesc;

    machine_name = mdesc->name;



    if (mdesc->soft_reboot)

        reboot_setup("s");



    ...

}

在该函数中setup_machine_xxx() 函数的作用就是找到我们想要的 struct machine_desc 类型的变量,也就是在

board-mx6q_sabresd.c 中定义的那个变量。

 

3、setup_arch() 函数是在哪里调用的?

在 init/main.c 的 start_kernel() 中,定义如下:

asmlinkage void __init start_kernel(void)

{

    ...



    tick_init();

    boot_cpu_init();

    page_address_init();

    printk(KERN_NOTICE "%s", linux_banner);

    setup_arch(&command_line);

    mm_init_owner(&init_mm, &init_task);

    mm_init_cpumask(&init_mm);

    setup_command_line(command_line);

    setup_nr_cpu_ids();

    setup_per_cpu_areas();

    smp_prepare_boot_cpu();    /* arch-specific boot-cpu hooks */



        ...

}

 

4、到这里,知道了在 /init/main.c 的 start_kernel() 函数里调用了setup_arch(),在 setup_arch() 里找到了具体的

struct machine_desc 类型的变量,但是在哪里通过这个变量调用里面的成员或成员函数的呢?

在 arch/arm/kernel/setup.c 中有如下定义 :

static int __init customize_machine(void)

{

    /* customizes platform devices, or adds new ones */

    if (machine_desc->init_machine)

        machine_desc->init_machine();

    return 0;

}

arch_initcall(customize_machine);

 

在 include/linux/init.h 中有如下定义:

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

在 arch/arm/kernel/vmlinux.lds.h 中有如下定义:

#define INITCALLS                            \

    *(.initcallearly.init)                        \

    VMLINUX_SYMBOL(__early_initcall_end) = .;            \

      *(.initcall0.init)                        \

      *(.initcall0s.init)                        \

      *(.initcall1.init)                        \

      *(.initcall1s.init)                        \

      *(.initcall2.init)                        \

      *(.initcall2s.init)                        \

      *(.initcall3.init)                        \

      *(.initcall3s.init)                        \

      *(.initcall4.init)                        \

      *(.initcall4s.init)                        \

      *(.initcall5.init)                        \

      *(.initcall5s.init)                        \

    *(.initcallrootfs.init)                        \

      *(.initcall6.init)                        \

      *(.initcall6s.init)                        \

      *(.initcall7.init)                        \

      *(.initcall7s.init)

#define INIT_CALLS                            \
        VMLINUX_SYMBOL(__initcall_start) = .;            \
        INITCALLS                        \
        VMLINUX_SYMBOL(__initcall_end) = .;

 

可以看到 customize_machine() 被放到了.initcall3.init里。

 

5、customize_machine()在哪里被调用的?

在/init/main.c 的 do_initcalls() 的函数中,定义如下:

static void __init do_initcalls(void)

{

    initcall_t *fn;



    for (fn = __early_initcall_end; fn < __initcall_end; fn++)

        do_one_initcall(*fn);

}

在for 循环里依次调用了从__early_initcall_end开始到__initcall_end结束的所有函数。customize_machine() 也是在其间被调用。

 

6、总体调用顺序

start_kernel()--->setup_arch()--->do_initcalls()--->customize_machine()--->mx6_sabresd_board_init()

 

你可能感兴趣的:(start)