linux-3.4.2内核源码分析——(二)内核启动流程

1.首先要解决的问题就是内核如何进行多平台的适配,内核是如何认识这些板子的,在linux-3.4.2\arch\arm\kernel\vmlinux.lds.S 中定义了很多很多的段,如下就是其中一段

	.init.arch.info : {
		__arch_info_begin = .;
		*(.arch.info.init)
		__arch_info_end = .;
	}

搜索.arch.info.init 的引用会查看到如下的宏定义代码

#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这个宏定义的引用会发现会有很多地方引用,这些即是linux中不同板子对应的宏定义调用。

我们打开其中一个板子对应的宏定义调用查看

MACHINE_START(AFEB9260, "Custom afeb9260 board")
	/* Maintainer: Sergey Lapin <slapin@ossfans.org> */
	.timer		= &at91sam926x_timer,
	.map_io		= at91_map_io,
	.init_early	= afeb9260_init_early,
	.init_irq	= at91_init_irq_default,
	.init_machine	= afeb9260_board_init,
MACHINE_END

将宏定义和具体的某个板子的信息结合一下就可以得到如下代码

#define MACHINE_START(_type,_name)			
static const struct machine_desc __mach_desc_CPUAT9G20	
 __used							
 __attribute__((__section__(".arch.info.init"))) = {  //系统指定将这个结构体放在代码段arch.info.init上	
	.nr		= MACH_TYPE_CPUAT9G20		
	.name		= "Eukrea CPU9G20",

    .timer		= &at91rm9200_timer,
	.map_io		= at91_map_io,
	.init_early	= carmeva_init_early,
	.init_irq	= at91_init_irq_default,
	.init_machine	= carmeva_board_init,
#define MACHINE_END				
};

如上可知系统创建了一个 machine_desc结构体对应的变量叫__mach_desc_CPUAT9G20  

, 系统指定将这个结构体放在代码段arch.info.init上(使用attribute)。linux就是这样,在vmlinux.lds.S链接文件中定义不同段,将要用到的信息放进段里去。

下面我们来看看machine_desc这个结构体:

struct machine_desc {
	unsigned int		nr;		/* architecture number	*/
	const char		*name;		/* architecture name	*/
	unsigned long		atag_offset;	/* tagged list (relative) */
	const char *const 	*dt_compat;	/* array of device tree
						 * 'compatible' strings	*/

	unsigned int		nr_irqs;	/* number of IRQs */

#ifdef CONFIG_ZONE_DMA
	unsigned long		dma_zone_size;	/* size of DMA-able area */
#endif

	unsigned int		video_start;	/* start of video RAM	*/
	unsigned int		video_end;	/* end of video RAM	*/

	unsigned char		reserve_lp0 :1;	/* never has lp0	*/
	unsigned char		reserve_lp1 :1;	/* never has lp1	*/
	unsigned char		reserve_lp2 :1;	/* never has lp2	*/
	char			restart_mode;	/* default restart mode	*/
	void			(*fixup)(struct tag *, char **,
					 struct meminfo *);
	void			(*reserve)(void);/* reserve mem blocks	*/
	void			(*map_io)(void);/* IO mapping function	*/
	void			(*init_early)(void);
	void			(*init_irq)(void);
	struct sys_timer	*timer;		/* system tick timer	*/
	void			(*init_machine)(void);
#ifdef CONFIG_MULTI_IRQ_HANDLER
	void			(*handle_irq)(struct pt_regs *);
#endif
	void			(*restart)(char, const char *);
};

这里面存放着大量的针对板子的信息,会对uboot传过来的参数进行结构体配置(atag_offset;    /* tagged list (relative) */)。并且在linux移植的时候也要对该结构体的变量进行赋值。并且在之后的启动或其他函数中,可以对该结构体的变量进行调用。

在arch.h中有如下的宏定义

#define for_each_machine_desc(p)			\
	for (p = __arch_info_begin; p < __arch_info_end; p++)

上面代码的_arch_info_begin和 _arch_info_end会指向链接文件vmlinux.lds.S中的一段代码

.init.arch.info : {
		__arch_info_begin = .;
		*(.arch.info.init)
		__arch_info_end = .;
	}

由此可知这些板子的结构体machine_desc都放到了arch_info_begin到_arch_info_end这段内存当中。

我们可以查看一下arch.info.init这段内存到底存了些什么,搜索arch.info.init会找到上面提到过的宏定义#define MACHINE_START(_type,_name) 。         

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

找到for_each_machine_desc宏定义的引用setup_machine_fd函数如下:

struct machine_desc * __init setup_machine_fdt(unsigned int dt_phys)
{

    。。。。。。。。。。。。。。。。。。。。。。
	
    for_each_machine_desc(mdesc) {
		score = of_flat_dt_match(dt_root, mdesc->dt_compat);
		if (score > 0 && score < mdesc_score) {
			mdesc_best = mdesc;
			mdesc_score = score;
		}
	}


    。。。。。。。。。。。。。。。。。。。。。。
    return mdesc_best;

}

该代码会找到一个移植Linux时,写的最适合的machine desc结构体mdesc_best;并且返回。

查看setup_machine_fd是被谁调用时会找到如下代码:

void __init setup_arch(char **cmdline_p){


        。。。。。。。。。。。。。。。。。。。。。

        mdesc = setup_machine_fdt(__atags_pointer);

	    machine_desc = mdesc;    //定义各种全局变量
    	machine_name = mdesc->name;

        。。。。。。。。。。。。。。。。。。。。。。。
           

        }


    

    atags_pointer是uboot传过来的参数列表,Linux将这个数据通过setup_machine_fd函数对板子的信息进行参数解析。将返回的值,即mdesc_best适配的结构体赋值给各种全局变量,然后在其他函数中调用。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值