您的位置:首页 > 运维架构 > Linux

MACHINE_START-内核板级初始化实现机制(linux3.1.0)

2014-11-26 17:03 267 查看
在驱动开发时,我们都是以一块开发板为基础移植驱动程序。每一块开发板对应一个板级文件,如开发

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

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

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

最后几行:

MACHINE_START(AM335XEVM, "am335xevm")
/* Maintainer: Texas Instruments */
.atag_offset	= 0x100,
.map_io		= am335x_evm_map_io,
.init_irq	= ti816x_init_irq,
.init_early	= am335x_init_early,
.timer		= &omap3_am33xx_timer,
.init_machine	= am335x_evm_init,
MACHINE_END


看以看出,am335x_evm_map_io,i816x_init_irq,am335x_init_early,am335x_evm_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				\
};

宏展开之后得到:

static const struct machine_desc __mach_desc_AM335XEVM	\
__attribute__((__used__))				\
__attribute__((__section__(".arch.info.init"))) = {	\
.nr		= MACH_TYPE_AM335XEVM,		\
.name		= _name,
.atag_offset	= 0x100,
.map_io		= am335x_evm_map_io,
.init_irq	= ti816x_init_irq,
.init_early	= am335x_init_early,
.timer		= &omap3_am33xx_timer,
.init_machine	= am335x_evm_init,
};


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

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

struct machine_desc {
unsigned int		nr;		/* architecture number	*/
const char		*name;		/* architecture name	*/
unsigned long		boot_params;	/* tagged list		*/
unsigned long		atag_offset;	/* tagged list (relative) */
const char		**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 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	*/
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
};


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

接下来看看setup_arch():

void __init setup_arch(char **cmdline_p)
{
struct machine_desc *mdesc;
unwind_init();
setup_processor();
/*__atags_pointer是uboot传递的参数地址 0x80000100*/
mdesc = setup_machine_fdt(__atags_pointer);
/*由于参数非设备树结构,返回NULL*/
if (!mdesc)
mdesc = setup_machine_tags(machine_arch_type);
machine_desc = mdesc;
machine_name = mdesc->name
.........
}


首先使用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()中:

for_each_machine_desc(p)
if (nr == p->nr) {
printk("Machine: %s\n", p->name);
mdesc = p;
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。

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


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

//在setup_machine_fdt(__atags_pointer)中使用的__atags_pointer由此传递


uboot的参数传递给内核:

uboot的板级文件evm.c中定义了板级信息

int board_evm_init()
{
gd->bd->bi_arch_number=MACH_TYPE_TIAM335EVM;
gd->bd->bi_boot_params=PHYS_DRAM_1+0x100;  //PHYS_DRAM_1=0x80000000
}
当使用bootm启动内核的时候,调用了do_bootm_linux函数:

int do_bootm_linux(int flag ,int argc ,char *argv[] , bootm_headers_t *images)
{
bd_t *bd=gd->bd;
int machid=bd->bi_arch_number;
/*使用device tree 结构传递参数,我们没有使用这种方式*/
#ifdef CONFIG_OF_LIBFDT
if(images->ft_len)
return bootm_linux_fdt(machid,images);
#endif

#if defined (CONFIG_SETUP_MEMORY_TAGS) || defined (CONFIG_CMDLINE_TAG) || .........
setup_start_tag(bd);
#endif
#if  defined (CONFIG_CMDLINE_TAG)
setup_commandline_tag(bd,commandline);
#endif

kernel_entry(0,machid,bd->bi_arch_number);
//r0=0,
//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由此传递
// 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由此传递
}




通过以上分析,已经可以知道内核是如何找到__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 :

setup.c/arch_initcall(customize_machine);
static int __init customize_machine(void)
{
/* customizes platform devices, or adds new ones */
if (machine_desc->init_machine)
machine_desc->init_machine();
return 0;
}
arch_initcall(customize_machine);


调用先后顺序是:

map_io

init_early

init_irq

time_init

init_machine

全部是在start_kernel()和setup_arch()中完成的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: