zoukankan      html  css  js  c++  java
  • MACHINE_START 怎样调用

    MACHINE_START是怎样被系统调用的

    MACHINE_START(AM335XEVM, "am335xevm")

    /* Maintainer: Texas Instruments */

    .atag_offset = 0x100,

    .map_io = am335x_evm_map_io,

    .init_early = am33xx_init_early,

    .init_irq = ti81xx_init_irq,

    .handle_irq     = omap3_intc_handle_irq,

    .timer = &omap3_am33xx_timer,

    .init_machine = am335x_evm_init,

    MACHINE_END

    移植过arm-linux的都应该知道在/arch/arm目录下有许多与具体处理器相关的目录,当然对于AM335X的话所对应的目录就是mach-omap2,在里面找到与具体板子相关的文件Board-am335xevm.c,没错,就是它。无论是出于想移植到新的内核还是出于想深入学习某一款arm等,对这个文件的学习是必不可少的。这个文件大部分内容是对平台设备(例如串口,LCDNand falsh等)的结构体初始化,在这个文件的最后有一个非常重要的宏:

    该结构是在linux-3.2.0-04.06.00.08archarmmach-omap2Board-am335xevm.c文件中,

    am335xevm这个宏在/arch/arm/tools/mach-types文件里定义:

    am335xevm MACH_AM335XEVM AM335XEVM 3589

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

    #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

    };

    解析之后为:

    static const struct machine_desc __mach_desc_AM335XEVM __used __attribute__((__section__(".arch.info.init"))) = 

    {

    .nr = MACH_TYPE_AM335XEVM,

    .name = "am335xevm",

    .atag_offset = 0x100,

    .map_io = am335x_evm_map_io,

    .init_early = am33xx_init_early,

    .init_irq = ti81xx_init_irq,

    .handle_irq     = omap3_intc_handle_irq,

    .timer = &omap3_am33xx_timer,

    .init_machine = am335x_evm_init,

    };

    其实就是定义了一个struct machine_desc类型结构体变量,这个结构体还定义了其他一些成员,接下来着重关注.init_machine这个成员,它是一个函数指针,值为am335x_evm_init,这个函数也在Board-am335xevm.c中定义。内容是什么呢?呵呵,因为在这里只给出大体流程,具体内容先不分析。现在最关心的是这个结构体变量在哪里被调用,从而调用它里面的成员和成员函数呢?先来看/arch/arm/kernel/setup.c里面的setup_arch()函数:

    void __init setup_arch(char **cmdline_p)

    {

    struct machine_desc *mdesc;

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

    reboot_setup(&mdesc->restart_mode);

    init_mm.start_code = (unsigned long) _text;

    init_mm.end_code   = (unsigned long) _etext;

    init_mm.end_data   = (unsigned long) _edata;

    init_mm.brk    = (unsigned long) _end;

    /* populate cmd_line too for later use, preserving boot_command_line */

    strlcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE);

    *cmdline_p = cmd_line;

    parse_early_param();

    ......

    这个函数在/init/main.cstart_kernel()函数里被调用。看这里的setup_machine_tags()函数的作用就是找到我们想要的struct machine_desc类型的变量,也就是在Board-am335xevm.c里定义那个变量。函数的参数machine_arch_type的值是什么呢?继续看:

    #define MACH_TYPE_AM335XEVM            3589

    ......

    #ifdef CONFIG_MACH_AM335XEVM

    # ifdef machine_arch_type

    #  undef machine_arch_type

    #  define machine_arch_type __machine_arch_type

    # else

    #  define machine_arch_type MACH_TYPE_AM335XEVM

    # endif

    # define machine_is_am335xevm() (machine_arch_type == MACH_TYPE_AM335XEVM)

    #else

    # define machine_is_am335xevm() (0)

    #endif

    也就是说参数machine_arch_type的值为3589。在setup_machine_tags函数里主要调用了函数来查找对应的type,应该是出于效率的原因,这个函数是通过汇编实现的,在此就不给出具体代码了。

    到这里,知道了在/init/main.cstart_kernel()函数里调用了setup_arch(),在setup_arch()里找到了具体的struct machine_desc类型的变量,但是在哪里通过这个变量调用里面的成员或成员函数的呢?继续找。还是在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);

    成员函数init_machine就是在这里被调用的。但是它没有被显式调用,而是放在了arch_initcall这个宏里,去看看它怎么定义的:

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

    #define __define_initcall(level,fn,id) 

    static initcall_t __initcall_##fn##id __used 

    __attribute__((__section__(".initcall" level ".init"))) = fn

    嗯,它被链接到了.initcall段里,现在简单看看/arch/arm/kernel/vmlinux.lds这个链接脚本里关于initcall的定义

     1 __initcall_start = .; 

     2 *(.initcallearly.init) __early_initcall_end = .; 

     3 *(.initcall0.init) *(.initcall0s.init) 

     4 *(.initcall1.init) *(.initcall1s.init) 

     5 *(.initcall2.init) *(.initcall2s.init) 

     6 *(.initcall3.init) *(.initcall3s.init) 

     7 *(.initcall4.init) *(.initcall4s.init) 

     8 *(.initcall5.init) *(.initcall5s.init) 

     9 *(.initcallrootfs.init) 

    10 *(.initcall6.init) *(.initcall6s.init) 

    11 *(.initcall7.init) *(.initcall7s.init) 

    12 __initcall_end = .;

    可以看到customize_machine()被放到了.initcall3.init里。说了那么多定义,究竟它在哪里被调用啊?好吧,它是在/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()也是在其间被调用。好了,到这里差不多该结束了,最后总结一下这些函数调用顺序:

    start_kernel()--->rest_init()--->kernel_init()--->do_basic_setup()--->do_initcalls()--->customize_machine()--->am335x_evm_init()

    整个调用过程就是这样,在setup_arch()函数中只是对链表进行了初始化,

    参考自博客:http://www.cnblogs.com/lknlfy/archive/2012/05/06/2486479.html


  • 相关阅读:
    一百二十三:CMS系统之登录功能
    一百二十二:CMS系统之页面抽离和登录页面
    一百二十一:CMS系统之注册后跳转到上一个页面
    一百二十:CMS系统之注册功能前后端逻辑
    Python基础语法习题二
    编程语言分类和Python解释器介绍
    VS Code设置中文和配置Python环境
    Windows10系统下安装python2和python3双版本
    Python下载与安装
    前端开发之jQuery位置属性和筛选方法
  • 原文地址:https://www.cnblogs.com/longbiao831/p/4556260.html
Copyright © 2011-2022 走看看