MACHINE_START MACHINE_END 宏 .
来源:互联网 发布:最小的中文linux系统 编辑:程序博客网 时间:2024/05/17 22:40
一、定义
#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结构体的定义
struct machine_desc {unsigned intnr;/* architecture number 编号*/const char*name;/* architecture name 名字*/unsigned longboot_params;/* tagged list*/unsigned intnr_irqs;/* number of IRQs 中断数*/unsigned intvideo_start;/* start of video RAM */unsigned intvideo_end;/* end of video RAM*/unsigned intreserve_lp0 :1;/* never has lp0*/unsigned intreserve_lp1 :1;/* never has lp1*/unsigned intreserve_lp2 :1;/* never has lp2*/unsigned intsoft_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);/* 初始化函数 */};
使用例子:
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中
__arch_info_begin = .; *(.arch.info.init) __arch_info_end = .;
在linux启动函数start_kernel中调用了setup_arch(&command_line);
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_descmachine_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_MMUif (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);#endifif (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_SMPif (is_smp())smp_init_cpus();#endifreserve_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#endifearly_trap_init();}
0.
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.板级初始化函数
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中定义
#define arch_initcall(fn)__define_initcall("3",fn,3)
__define_initcall的定义
#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中
__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_initcalls()
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
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);elseret = fn();//执行了fn函数也就是customize_machinemsgbuf[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;}