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()

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。