(转载)MACHINE_START MACHINE_END 宏

一、定义

[cpp]  
#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             \  
};  
 
MACHINE_START和MACHINE_END框起了一个machine_desc结构体的声明并根据MACHINE_START宏的参数初始化其.nr和.name成员
并将该结构体标记编译到.arch.info.init段
在MACHINE_START和MACHINE_END宏之间可以初始化machine_desc结构体的剩余成员
machine_desc结构体的定义
[cpp]  
struct machine_desc {  
    unsigned int    nr;     /* architecture number 编号   */  
    const char  *name;      /* architecture name 名字 */  
    unsigned long   boot_params;    /* tagged list      */  
    unsigned int    nr_irqs;        /* number of IRQs 中断数   */  
    unsigned int    video_start;    /* start of video RAM   */  
    unsigned int    video_end;  /* end of video RAM */  
    unsigned int    reserve_lp0 :1; /* never has lp0    */  
    unsigned int    reserve_lp1 :1; /* never has lp1    */  
    unsigned int    reserve_lp2 :1; /* never has lp2    */  
    unsigned int    soft_reboot :1; /* soft reboot      */  
    void    (*fixup)(struct machine_desc *,struct tag *, char **,struct meminfo *);  
    void    (*reserve)(void);       /* reserve mem blocks   */  
    void    (*map_io)(void);        /* IO mapping function io映射函数 */  
    void    (*init_irq)(void);      /* 中断初始化函数 */  
    struct sys_timer    *timer;     /* system tick timer 滴答定时器 */  
    void    (*init_machine)(void);  /* 初始化函数 */  
};  
使用例子:
[cpp] 
MACHINE_START(SMDKC110, "SMDKC110")  
    /* Maintainer: Kukjin Kim <kgene.kim@samsung.com> */  
    .boot_params    = S5P_PA_SDRAM + 0x100,  
    .init_irq   = s5pv210_init_irq,  
    .map_io     = smdkc110_map_io,  
    .init_machine   = smdkc110_machine_init,  
    .timer      = &s3c24xx_timer,  
MACHINE_END  
这里smdkc110_machine_init就是对应的板级初始化函数,s5pv210_init_irq就是板级中断初始化函数,smdkc110_map_io就是板级io初始化函数...
二、调用关系
MACHINE_START宏将machine_desc标记编译到.arch.info.init段,而/arch/arm/kernel/vmlinux.lds中
[cpp] 
__arch_info_begin = .;  
 *(.arch.info.init)  
__arch_info_end = .;  
在linux启动函数start_kernel中调用了setup_arch(&command_line);
[cpp] 
void __init setup_arch(char **cmdline_p)  
{  
    struct tag *tags = (struct tag *)&init_tags;  
    struct machine_desc *mdesc; //声明了一个machine_desc结构体指针  
    char *from = default_command_line;  
  
    init_tags.mem.start = PHYS_OFFSET;  
  
    unwind_init();  
  
    setup_processor();  
    mdesc = setup_machine(machine_arch_type);   //0根据machine_arch_type获取machine_desc  
    machine_name = mdesc->name;  //设置名字  
  
    if (mdesc->soft_reboot)  //需要软重启?  
        reboot_setup("s");  
  
    if (__atags_pointer)  
        tags = phys_to_virt(__atags_pointer);  
    else if (mdesc->boot_params) {   //处理启动参数  
#ifdef CONFIG_MMU  
        if (mdesc->boot_params < PHYS_OFFSET ||  
            mdesc->boot_params >= PHYS_OFFSET + SZ_1M) {  
            printk(KERN_WARNING"Default boot params at physical 0x%08lx out of reach\n",mdesc->boot_params);  
        } else  
#endif  
        {  
            tags = phys_to_virt(mdesc->boot_params);  
        }  
    }  
  
#if defined(CONFIG_DEPRECATED_PARAM_STRUCT)  
    if (tags->hdr.tag != ATAG_CORE)  
        convert_to_tag_list(tags);  
#endif  
    if (tags->hdr.tag != ATAG_CORE)  
        tags = (struct tag *)&init_tags;  
  
    if (mdesc->fixup)    //若存在fixup方法则调用其方法  
        mdesc->fixup(mdesc, tags, &from, &meminfo);  
  
    if (tags->hdr.tag == ATAG_CORE) {  
        if (meminfo.nr_banks != 0)  
            squash_mem_tags(tags);  
        save_atags(tags);  
        parse_tags(tags);  
    }  
  
    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;  
  
    /* parse_early_param needs a boot_command_line */  
    strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);  
  
    /* 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();  
  
    arm_memblock_init(&meminfo, mdesc); //这里可能会调用reserve方法  
  
    paging_init(mdesc); //->devicemaps_init(mdesc)->map_io方法  
    request_standard_resources(&meminfo, mdesc);    //这里可能会调用video_start方法  
  
#ifdef CONFIG_SMP  
    if (is_smp())  
        smp_init_cpus();  
#endif  
    reserve_crashkernel();  
    cpu_init();  
    tcm_init();  
  
    arch_nr_irqs = mdesc->nr_irqs;   //1设置全局变量 中断个数  
    init_arch_irq = mdesc->init_irq; //2设置全局变量 中断初始化函数  
    system_timer = mdesc->timer; //3设置全局变量 sys_timer结构体  
    init_machine = mdesc->init_machine;  //4设置全局变量 板级初始化函数  
  
#ifdef CONFIG_VT  
#if defined(CONFIG_VGA_CONSOLE)  
    conswitchp = &vga_con;  
#elif defined(CONFIG_DUMMY_CONSOLE)  
    conswitchp = &dummy_con;  
#endif  
#endif  
    early_trap_init();  
}  
0.
[cpp]  
static struct machine_desc * __init setup_machine(unsigned int nr)  
{  
    extern struct machine_desc __arch_info_begin[], __arch_info_end[];  
    struct machine_desc *p;  
  
    for (p = __arch_info_begin; p < __arch_info_end; p++)//遍历__arch_info_begin和__arch_info_end之间的machine_desc结构体  
        if (nr == p->nr) {   //找到对应的板  
            printk("Machine: %s\n", p->name);//打印板级信息  
            return p;  
        }  
  
    early_print("\n"  
        "Error: unrecognized/unsupported machine ID (r1 = 0x%08x).\n\n"  
        "Available machine support:\n\nID (hex)\tNAME\n", nr);  
  
    for (p = __arch_info_begin; p < __arch_info_end; p++)  
        early_print("%08x\t%s\n", p->nr, p->name);  
  
    early_print("\nPlease check your kernel config and/or bootloader.\n");  
  
    while (true)  
        /* can't use cpu_relax() here as it may require MMU setup */;  
}  
 
1.中断个数
start_kernel->early_irq_init->arch_probe_nr_irqs函数中nr_irqs = arch_nr_irqs ? arch_nr_irqs : NR_IRQS;设置全局nr_irqs变量
2.中断初始化函数
start_kernel->init_IRQ->init_arch_irq()
3.sys_timer结构体
start_kernel->time_init()调用system_timer->init()方法既sys_timer->init()
4.板级初始化函数
[cpp] 
static void (*init_machine)(void) __initdata;  
  
static int __init customize_machine(void)  
{  
    /* customizes platform devices, or adds new ones */  
    if (init_machine)//全局函数init_machine存在  
        init_machine();//则调用,既mdesc->init_machine()  
    return 0;  
}  
arch_initcall(customize_machine);//用arch_initcall修饰customize_machine函数  
arch_iniitcall函数在/include/linux/init.h中定义
[cpp] 
#define arch_initcall(fn)       __define_initcall("3",fn,3)  
__define_initcall的定义
[cpp]  
#define __define_initcall(level,fn,id) \  
    static initcall_t __initcall_##fn##id __used \  
    __attribute__((__section__(".initcall" level ".init"))) = fn  
展开就是static initcall_t __initcall_customize_machine3 __used __attribute__((__section__(".initcall3.init")))=customize_machine
在vmlinux.lds中
[cpp] 
__initcall_start = .;   
*(.initcallearly.init)   
__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)   
__initcall_end = .;  
标注为.initcall3.init的函数编译进__initcall_start和__initcall_end框起的section中
而在系统启动的时候
start_kernel->rest_init()->kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);创建了kernel线程
kernel_init->do_pre_smp  
static void __init do_pre_smp_initcalls(void)  
{  
    initcall_t *fn;  
  
    for (fn = __initcall_start; fn < __early_initcall_end; fn++)  
        do_one_initcall(*fn);  
}  
该函数遍历__initcall_start和__early_initcall_end中的函数,并调用do_one_initcall
[cpp]  
int __init_or_module do_one_initcall(initcall_t fn)  
{  
    int count = preempt_count();  
    int ret;  
  
    if (initcall_debug)  
        ret = do_one_initcall_debug(fn);  
    else  
        ret = fn();//执行了fn函数也就是customize_machine  
  
    msgbuf[0] = 0;  
  
    if (ret && ret != -ENODEV && initcall_debug)  
        sprintf(msgbuf, "error code %d ", ret);  
  
    if (preempt_count() != count) {  
        strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf));  
        preempt_count() = count;  
    }  
    if (irqs_disabled()) {  
        strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));  
        local_irq_enable();  
    }  
    if (msgbuf[0]) {  
        printk("initcall %pF returned with %s\n", fn, msgbuf);  
    }  
  
    return ret;  

posted on 2013-09-24 19:29  熊猫酒仙是也  阅读(238)  评论(0编辑  收藏  举报

导航