U-boot引导流程分析二

本文深入分析了U-boot的Stage II过程,涉及gd_t数据结构、全局数据区、db_t结构体在内核参数传递中的作用,以及init_sequence函数指针数组。此外,详细讲解了start_armboot函数、main_loop函数和bootm命令的执行流程,特别是如何通过bootm启动内核并传递参数给Linux kernel。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Stage II过程分析

在Stage II中使用到了一些比较重要的数据结构,这里先对这些数据结构来进行下分析:
typedef	struct	global_data {
	bd_t		*bd;
	unsigned long	flags;
	unsigned long	baudrate;
	unsigned long	have_console;	/* serial_init() was called */
	unsigned long	reloc_off;	/* Relocation Offset */
	unsigned long	env_addr;	/* Address  of Environment struct */
	unsigned long	env_valid;	/* Checksum of Environment valid? */
	unsigned long	fb_base;	/* base address of frame buffer */
#ifdef CONFIG_VFD
	unsigned char	vfd_type;	/* display type */
#endif
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	unsigned long	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table */
} gd_t;

gd_t数据结构在include/asm-arm/global_data.h中定义,它用来存储全局数据区的数据。

#define DECLARE_GLOBAL_DATA_PTR     register volatile gd_t *gd asm ("r8")

U-Boot中使用了一个存储在寄存器中的指针gd来记录全局数据区的地址。DECLARE_GLOBAL_DATA_PTR定义了一个gd_t全局数据结构的指针,这个指针存放在寄存器r8中。这个声明也避免编译器把r8分配各其他变量。任何想要访问全局数据区的代码,只要开头加入"DECLARE_GLOBAL_DATA_PTR"这一行代码,然后就可以使用gd指针来访问全局数据区了。

根据U-Boot内存使用图可以计算gd的值: gd = TEXT_BASE - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t)。

typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    unsigned char	bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/* unique id for this board */
    ulong	        bi_boot_params;	/* where this board expects params */
    struct				/* RAM configuration */
    {
	ulong start;
	ulong size;
    } 			bi_dram[CONFIG_NR_DRAM_BANKS];
#ifdef CONFIG_HAS_ETH1
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t;

db_t数据结构在include/asm-arm/u-boot.h中定义。U-Boot启动内核时要给内核传递参数,这时就要使用gd_t,db_t结构体中的信息来设置标记列表。

init_fnc_t *init_sequence[] = {
	cpu_init,		/* basic cpu dependent setup 基本的处理器相关配置 --cpu/arm920t/cpu.c */
	board_init,		/* basic board dependent setup 基本的板级相关配置 --board/smdk2410/smdk2410.c */
	interrupt_init,	/* set up exceptions 初始化中断处理 --cpu/arm920t/s3c24x0/interrupts.c */
	env_init,		/* initialize environment 初始化环境变量 --common/env_flash.c */

	init_baudrate,		/* initialze baudrate settings 初始化波特率设置 --lib_arm/board.c */
	serial_init,		/* serial communications setup 串口通讯设置 --cpu/arm920t/serial.c */
	console_init_f,		/* stage 1 init of console 控制台初始化阶段1 -- common/console.c */
	display_banner,		/* say that we are here 打印U-Boot版本、编译的时间 --lib_arm/board.c */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,			/* display board info */
#endif
	dram_init,			/* configure available RAM banks 配置可用的RAM --board/smdk2410/smdk2410.c */
	/*
	 * 在这里开始进行配置SDRAM信息,用到结构体	bd->bi_dram[BANK_NR].start	bd->bi_dram[BANK_NR].size                                                                                                       bd->bi_dram[BANK_NR].size
	 */
	display_dram_config,	/* 显示SDRAM的配置信息 --lib_arm/board.c */

	NULL,
};

U-Boot使用一个数组init_sequence来存储对于大多数开发板都要执行的函数指针。

int cpu_init (void)
{
	/*
	 * setup up stacks if necessary
	 */
#ifdef CONFIG_USE_IRQ
	IRQ_STACK_START = _armboot_start - CFG_MALLOC_LEN - CFG_GBL_DATA_SIZE - 4;
	FIQ_STACK_START = IRQ_STACK_START - CONFIG_STACKSIZE_IRQ;
#endif
	return 0;
}

其中的cpu_init函数在cpu/arm920t/cpu.c中定义。

int board_init (void)
{
	..............
	/* arch number of SMDK2410-Board */
	gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;	/* SMDK2410开发板的机器码(板子ID) */

	/* adress of boot parameters */
	gd->bd->bi_boot_params = 0x30000100;		/* 内核启动参数地址(绝对地址) */
	.............
}

board_init设置了U-Boot机器码和内核启动参数地址。

/* 初始化内存RAM的信息,其实就是给gd->bd中内存信息表赋值而已 */
int dram_init (void)
{
	/* 设置板级数据中的SDRAM开始地址和大小 */
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

	return 0;
}

分析完上述数据结构,下面接着来分析Stage II入口函数start_armboot(实现在lib-arm/board.c中):


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值