內核獲得u-boot傳遞的TAG的方式

uboot在完成所有工作之後使用theKernel()啓動內核

theKernel (0, machid, bd->bi_boot_params); 

傳遞三個參數0、machid、TAG的首地址,分別存入r0,r1,r2,之後啓動內核。

 

內核中獲取TAG首地址則是在arch/arm/kernel/setup.c文件的setup_arch()函數中(內核版本:linux-2.6.22.6)

void __init setup_arch(char **cmdline_p)
{
	struct tag *tags = (struct tag *)&init_tags;
	struct machine_desc *mdesc;
	char *from = default_command_line;

	setup_processor();
	mdesc = setup_machine(machine_arch_type); //獲得開發板對應的machine_desc結構體 
	machine_name = mdesc->name;

	if (mdesc->soft_reboot)
		reboot_setup("s");

	if (mdesc->boot_params)   //如果定義了bootloader傳入的TAG地址
		tags = phys_to_virt(mdesc->boot_params); //得到傳入的TAG虛擬地址
    ......
}

setup_machine()函數:獲得開發板對應的machine_desc結構體

static struct machine_desc * __init setup_machine(unsigned int nr)
{
	struct machine_desc *list;

	/*
	 * locate machine in the list of supported machines.
	 */
	list = lookup_machine_type(nr);
	if (!list) {
		printk("Machine configuration botched (nr %d), unable "
		       "to continue.\n", nr);
		while (1);
	}

	printk("Machine: %s\n", list->name);

	return list;
}

lookup_machine_type()定義在arch/arm/kernel/head-common.S中

具體作用就是通過u-boot傳入的機器id在.arch.info.init段中找到匹配的machine_desc結構體。

 

 

 

	.long	__proc_info_begin
	.long	__proc_info_end
3:	.long	.
	.long	__arch_info_begin
	.long	__arch_info_end
 
__lookup_machine_type:
	adr	r3, 3b                      @得到3標號的物理地址            
	ldmia	r3, {r4, r5, r6}  @r4=r3 r5=__arch_info_begin r6=__arch_info_end
	sub	r3, r3, r4			@ r3 = r3 - r4 得到虛擬地址與物理地址的差
	add	r5, r5, r3			@ r5 = __arch_info_begin的物理地址
	add	r6, r6, r3			@ r6 = __arch_info_end的物理地址
1:	ldr	r3, [r5, #MACHINFO_TYPE]	@ @ r5 =machine_desc r3=machine_desc 中的nr即機器id
	teq	r3, r1			@ r1爲bootloader傳入的機器id 比較兩者
	beq	2f				@ 如果相等跳轉到2forward標號
	add	r5, r5, #SIZEOF_MACHINE_DESC	@ 得到下個machine_desc結構體
	cmp	r5, r6                        @比較是否到段的結尾
	blo	1b                             @如果不是跳轉到1back標號
	mov	r5, #0			 @ unknown machine
2:	mov	pc, lr
 

那machine_desc結構體是由什麼定義的呢?

內核對應每一種能支持開發板都會使用宏MACHINE_START和MACHINE_END來定義一個

machine_desc結構,它定義了開發板相關的一些屬性及函數,比如機器類型id,起始I/O物理地址、bootloader傳入的參數地址等等。

定義如下:
 

#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	

 

對於SMDK2440開發板,定義如下:(位於arch/arm/mach-s3c2440/mach-smdk2440.c)
 

MACHINE_START(S3C2440, "SMDK2440")
	/* Maintainer: Ben Dooks <[email protected]> */
	.phys_io	= S3C2410_PA_UART,
	.io_pg_offst	= (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
	.boot_params	= S3C2410_SDRAM_PA + 0x100, //S3C2410_SDRAM_PA = 0x30000000
     //所以得到bootloader傳入的TAG首地址爲0x30000100
	.init_irq	= s3c24xx_init_irq,
	.map_io		= smdk2440_map_io,
	.init_machine	= smdk2440_machine_init,
	.timer		= &s3c24xx_timer,
MACHINE_END

 

 

分析到這裏其實不難看出,內核並沒有使用theKernel()傳入的TAG首地址,而是通過machine_desc的boot_params項獲得了TAG首地址。

如果u-boot設置的TAG首地址與內核中boot_params參數不一致時,可能會出現問題。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章