zoukankan      html  css  js  c++  java
  • MACHINE_START-内核板级初始化实现机制(linux3.1.0)

    转:https://blog.csdn.net/charliewangg12/article/details/41518549

    在驱动开发时,我们都是以一块开发板为基础移植驱动程序。每一块开发板对应一个板级文件,如开发

    TI AM335x系列,则对应board-am335xevm.c,这个文件完成芯片和板级的初始化工作。对于驱动开发,还有

    一个很重要的文件devices.c,这个文件主要是设备接口相关资源。

    今天就来说说board-am335xevm.c文件,如何全面的了解这个文件呢?先找到这个文件的入口,在文件的

    最后几行:

    [cpp] view plain copy
     
    1. MACHINE_START(AM335XEVM, "am335xevm")  
    2.     /* Maintainer: Texas Instruments */  
    3.     .atag_offset    = 0x100,  
    4.     .map_io     = am335x_evm_map_io,  
    5.     .init_irq   = ti816x_init_irq,  
    6.     .init_early = am335x_init_early,  
    7.     .timer      = &omap3_am33xx_timer,  
    8.     .init_machine   = am335x_evm_init,  
    9. MACHINE_END  

    看以看出,am335x_evm_map_io,i816x_init_irq,am335x_init_early,am335x_evm_init就是各个初始化函数

    的总入口函数。

    下面来分析一下这几个函数是如何被调用,何时被调用的?

    [cpp] view plain copy
     
    1. #define MACHINE_START(_type,_name)            
    2. static const struct machine_desc __mach_desc_##_type      
    3.  __used                           
    4.  __attribute__((__section__(".arch.info.init"))) = {      
    5.     .nr     = MACH_TYPE_##_type,          
    6.     .name       = _name,  
    7. #define MACHINE_END               
    8. };  

    宏展开之后得到:

    [cpp] view plain copy
     
    1. static const struct machine_desc __mach_desc_AM335XEVM    
    2.  __attribute__((__used__))                
    3.  __attribute__((__section__(".arch.info.init"))) = {      
    4.     .nr     = MACH_TYPE_AM335XEVM,        
    5.     .name       = _name,  
    6.     .atag_offset    = 0x100,  
    7.     .map_io     = am335x_evm_map_io,  
    8.     .init_irq   = ti816x_init_irq,  
    9.     .init_early = am335x_init_early,  
    10.     .timer      = &omap3_am33xx_timer,  
    11.     .init_machine   = am335x_evm_init,    
    12. };  

     __mach_desc_AM335XEVM是一个struct machine_desc 类型结构体,这个结构体存放的段是

    .arch.info.init,这里注意一下,后边匹配machine_desc的时候就是到这个段中寻找,然后根据nr的值匹配。

    [cpp] view plain copy
     
    1. struct machine_desc {  
    2.     unsigned int        nr;     /* architecture number  */  
    3.     const char      *name;      /* architecture name    */  
    4.     unsigned long       boot_params;    /* tagged list      */  
    5.     unsigned long       atag_offset;    /* tagged list (relative) */  
    6.     const char      **dt_compat;    /* array of device tree 
    7.                          * 'compatible' strings */  
    8.     unsigned int        nr_irqs;    /* number of IRQs */  
    9. #ifdef CONFIG_ZONE_DMA  
    10.     unsigned long       dma_zone_size;  /* size of DMA-able area */  
    11. #endif  
    12.     unsigned int        video_start;    /* start of video RAM   */  
    13.     unsigned int        video_end;  /* end of video RAM */  
    14.     unsigned int        reserve_lp0 :1; /* never has lp0    */  
    15.     unsigned int        reserve_lp1 :1; /* never has lp1    */  
    16.     unsigned int        reserve_lp2 :1; /* never has lp2    */  
    17.     unsigned int        soft_reboot :1; /* soft reboot      */  
    18.     void            (*fixup)(struct machine_desc *,  
    19.                      struct tag *, char **,  
    20.                      struct meminfo *);  
    21.     void            (*reserve)(void);/* reserve mem blocks  */  
    22.     void            (*map_io)(void);/* IO mapping function  */  
    23.     void            (*init_early)(void);  
    24.     void            (*init_irq)(void);  
    25.     struct sys_timer    *timer;     /* system tick timer    */  
    26.     void            (*init_machine)(void);  
    27. #ifdef CONFIG_MULTI_IRQ_HANDLER  
    28.     void            (*handle_irq)(struct pt_regs *);  
    29. #endif  
    30. };  

    内核启动的时候跳转的C语言入口在main.c/start_kernel(void),start_kernel(void)会调用setup_arch(),

    接下来看看setup_arch():

    [cpp] view plain copy
     
    1. void __init setup_arch(char **cmdline_p)  
    2. {  
    3.     struct machine_desc *mdesc;  
    4.     unwind_init();  
    5.     setup_processor();  
    6.     /*__atags_pointer是uboot传递的参数地址 0x80000100*/  
    7.     mdesc = setup_machine_fdt(__atags_pointer);   
    8.     /*由于参数非设备树结构,返回NULL*/  
    9.     if (!mdesc)  
    10.         mdesc = setup_machine_tags(machine_arch_type);  
    11.     machine_desc = mdesc;  
    12.     machine_name = mdesc->name  
    13.     .........  
    14. }  

    首先使用mdesc = setup_machine_fdt(__atags_pointer)获取mdes,__atags_pointer是uboot传递的

    参数存放位置,这里等于0x80000100,后边会解释。setup_machine_fdt()起作用的话,需要uboot传递的

    参数是设备树device tree的存放方式,我们实际使用的是tags_list方式,所以这里返回值为NULL。
    所以是通过mdesc =  setup_machine_tags(machine_arch_type)获得的machine desc,machine_arch_type

    是uboot传递的machid。
    setup_machine_tags()中:

    [cpp] view plain copy
     
    1.           for_each_machine_desc(p)  
    2. f (nr == p->nr) {  
    3. printk("Machine: %s ", p->name);  
    4. mdesc = p;  
    5. break;  


    nr= machid=MACH_TYPE_AM335XEVM=3589是uboot传递过来的,内核中的MACH_TYPE_AM335XEVM

    在/include/generated/mach-types.h中定义,这个文件是动态产生的。产生过程请参考

    http://blog.csdn.net/charliewangg12/article/details/41483261

    在mach-types.h中定义:
     #define MACH_TYPE_AM335XEVM  3589

    如何确定是哪个machine_desc,从machine_desc存放的段中选择机器码与从uboot传递过来的机器号

    nr比较,相等即得到了machine_desc。

    [cpp] view plain copy
     
    1. #define for_each_machine_desc(p) for (p = __arch_info_begin; p < __arch_info_end; p++)  

    __arch_info_begin是machine_desc存放的位置,通过属性定义

    [cpp] view plain copy
     
    1. //在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递  

    uboot的参数传递给内核:
    uboot的板级文件evm.c中定义了板级信息

    [cpp] view plain copy
     
    1. int board_evm_init()  
    2. {  
    3.     gd->bd->bi_arch_number=MACH_TYPE_TIAM335EVM;  
    4.     gd->bd->bi_boot_params=PHYS_DRAM_1+0x100;  //PHYS_DRAM_1=0x80000000  
    5. }  

    当使用bootm启动内核的时候,调用了do_bootm_linux函数:

    [cpp] view plain copy
     
    1. int do_bootm_linux(int flag ,int argc ,char *argv[] , bootm_headers_t *images)  
    2. {  
    3.     bd_t *bd=gd->bd;  
    4.     int machid=bd->bi_arch_number;  
    5. /*使用device tree 结构传递参数,我们没有使用这种方式*/  
    6.     #ifdef CONFIG_OF_LIBFDT  
    7.     if(images->ft_len)  
    8.     return bootm_linux_fdt(machid,images);  
    9.     #endif  
    10.   
    11. #if defined (CONFIG_SETUP_MEMORY_TAGS) || defined (CONFIG_CMDLINE_TAG) || .........  
    12.         setup_start_tag(bd);  
    13. #endif  
    14. #if  defined (CONFIG_CMDLINE_TAG)  
    15.     setup_commandline_tag(bd,commandline);  
    16. #endif  
    17.   
    18.        kernel_entry(0,machid,bd->bi_arch_number);  
    19.         //r0=0,  
    20.     //r1=machid=3589  machine type number,在setup_machine_tags(machine_arch_type)中<pre name="code" class="cpp"><span style="white-space:pre">    </span>//machine_arch_type由此传递  
    21.     // r2=bd->bi_arch_number=0x80000100  physical address of tagged list in system RAM,<pre name="code" class="cpp"><span style="white-space:pre">   </span>//在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递  
    [cpp] view plain copy
     
    1. }  
    
    
    
    


    通过以上分析,已经可以知道内核是如何找到__mach_desc_AM335XEVM,那何时去使用这个结构体定义

    的函数呢?
    我们知道全局变量赋值给machine_desc = mdesc,后边使用machine_desc指向各个函数进行调用。

    .map_io:
    /init/main.c/start_kernel(void)->setup_arch-> paging_init(mdesc) ->paging_init(mdesc)->devicemaps_init

    init_early:
    setup_arch-> mdesc->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_initcall(customize_machine)调用的。
    .init_machine :

    [csharp] view plain copy
     
    1. setup.c/arch_initcall(customize_machine);  
    2. static int __init customize_machine(void)  
    3. {  
    4.     /* customizes platform devices, or adds new ones */  
    5.     if (machine_desc->init_machine)  
    6.         machine_desc->init_machine();  
    7.     return 0;  
    8. }  
    9. arch_initcall(customize_machine);  

    调用先后顺序是:
    map_io
    init_early
    init_irq
    time_init
    init_machine
    全部是在start_kernel()和setup_arch()中完成的。

  • 相关阅读:
    ASP.NET生成静态页
    IE9下silverlight 里边MessageBox.Show 失效!
    Android与iOS:谁更适合HTML 5?
    编程修改IIS7的MIME类型的问题
    (译)理解“渐进增强(Progressive Enhancement)”
    C# 获取msi文件的ProductCode
    修改chrome浏览器useragent;在电脑上也能打开pad 或者 iphone 的专用网站
    开始的iOS编程之前的准备
    测试博客
    Google Maps Android API v2
  • 原文地址:https://www.cnblogs.com/newjiang/p/8676726.html
Copyright © 2011-2022 走看看