MACHINE_START 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				\
};


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 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);	/* 初始化函数 */
};

使用例子:

MACHINE_START(SMDKC110, "SMDKC110")
	/* Maintainer: Kukjin Kim <[email protected]> */
	.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_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.

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


 

 

 

 

你可能感兴趣的:(linux,宏,MACHINE_START,MACHINE_END,machine_desc)