1. 程式人生 > >linux板級初始化

linux板級初始化

最近拿到了明遠智睿 的EK314開發板,以前主要用2440,眼界過於狹隘,藉此機會練習下。

/arch/arm/mach-mx6/board-myimx6ek314.c

在他的末尾指定了map_io、init_irq、init_machine、timer等初始化函式,MACHINE_START是個巨集定義,他的展開我列了出來

MACHINE_START(MYIMX6EK314, "MYZR i.MX6 Evaluation Kit ( MXM 314 )")
    .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(MYIMX6EK314, "MYZR i.MX6 Evaluation Kit ( MXM 314 )") .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 `#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 \ };

// 使用 attribute ((packed)) ,讓編譯器取消結構在編譯過程中的優化對齊,按照實際佔用位元組數進行對齊,
// 這樣子兩邊都需要使用 attribute ((packed))取消優化對齊,就不會出現對齊的錯位現象。

這裡的話,是定義了一個struct machine_desc __mach_desc__MYIMX6EK314 的結構體

這個結構體存放的段是.arch.info.init,這裡注意一下,後邊匹配machine_desc的時候就是到這個段中尋找,然後根據nr的值匹配。

這裡的machine_desc指定的初始化函式的呼叫分別在以下階段

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");


       .....................

    parse_early_param();

    sanity_check_meminfo();
    arm_memblock_init(&meminfo, mdesc);

    paging_init(mdesc);      // ->paging_init(mdesc)->devicemaps_init
    request_standard_resources(mdesc);

        ...................
    early_trap_init();

    if (mdesc->init_early)
        mdesc->init_early();      //init_early:
}



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");


       .....................

    parse_early_param();

    sanity_check_meminfo();
    arm_memblock_init(&meminfo, mdesc);

    paging_init(mdesc);      // ->paging_init(mdesc)->devicemaps_init
    request_standard_resources(mdesc);

        ...................
    early_trap_init();

    if (mdesc->init_early)
        mdesc->init_early();      //init_early:
}

init_irq:
/init/main.c/start_kernel(void)->init_IRQ()->machine_desc->init_irq()
(mdesc) ->devicemaps_init() -> mdesc->map_io()
time_init:
start_kernel() –> time_init()->system_timer = machine_desc->timer;system_timer->init()

init_machine:

他是用了arch/arm/kernel/setup.c

@729
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);


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

這個arch_initcall 執行了machine_desc->init_machine(),那麼arch_initcall 是何時呼叫的呢?

在main.c ->do_basic_setup();->do_initcalls();中

static void __init do_initcalls(void)
{
    initcall_t *fn;

    for (fn = __early_initcall_end; fn < __initcall_end; fn++)
        do_one_initcall(*fn);
}

static void __init do_initcalls(void)
{
    initcall_t *fn;

    for (fn = __early_initcall_end; fn < __initcall_end; fn++)
        do_one_initcall(*fn);
}

這裡的一個for迴圈do_one_initcall,呼叫了所有的 xxxx_initcall,在include/linux/init.h 中

以下程式碼是對標號進行處理,方便統一呼叫
`#define pure_initcall(fn) __define_initcall(“0”,fn,0)

#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall(“1s”,fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall(“2s”,fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall(“3s”,fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall(“4s”,fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall(“5s”,fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall(“6”,fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall(“7”,fn,7)
`#define late_initcall_sync(fn) __define_initcall(“7s”,fn,7s)

`#define __initcall(fn) device_initcall(fn)

`#define pure_initcall(fn) __define_initcall(“0”,fn,0)

#define core_initcall(fn) __define_initcall("1",fn,1)
#define core_initcall_sync(fn) __define_initcall(“1s”,fn,1s)
#define postcore_initcall(fn) __define_initcall("2",fn,2)
#define postcore_initcall_sync(fn) __define_initcall(“2s”,fn,2s)
#define arch_initcall(fn) __define_initcall("3",fn,3)
#define arch_initcall_sync(fn) __define_initcall(“3s”,fn,3s)
#define subsys_initcall(fn) __define_initcall("4",fn,4)
#define subsys_initcall_sync(fn) __define_initcall(“4s”,fn,4s)
#define fs_initcall(fn) __define_initcall("5",fn,5)
#define fs_initcall_sync(fn) __define_initcall(“5s”,fn,5s)
#define rootfs_initcall(fn) __define_initcall("rootfs",fn,rootfs)
#define device_initcall(fn) __define_initcall(“6”,fn,6)
#define device_initcall_sync(fn) __define_initcall("6s",fn,6s)
#define late_initcall(fn) __define_initcall(“7”,fn,7)
`#define late_initcall_sync(fn) __define_initcall(“7s”,fn,7s)

`#define __initcall(fn) device_initcall(fn)

`#define __define_initcall(level,fn,id) \
static initcall_t _initcall##fn##id __used \
attribute((section(“.initcall” level “.init”))) = fn

initcall_t 的原型是typedef int (*initcall_t)(void); 就是個函式指標

__define_initcall就是把函式指標指向xxx_initcall() ,對應我們的初始化函式

而屬性 attribute((section())) 則表示把物件放在一個這個由括號中的名稱所指代的section中。

所以__define_initcall的含義是:

1) 宣告一個名稱為_initcall##fn的函式指標;

2) 將這個函式指標初始化為fn;

3) 編譯的時候需要把這個函式指標變數放置到名稱為 “.initcall” level “.init”的section中。

這個section是在/include/asm-generic/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) = .;


#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) = .;

而這些SECTION裡的函式在初始化時被順序執行(init核心執行緒->do_basic_setup()[main.C#778]->do_initcalls())。

程式(init/main.c檔案do_initcalls()函式)do_initcalls()把.initcallXX.init中的函式按順序都執行一遍。