mini2440系统移植篇之u-boot第二阶段C语言

1. 第二阶段C语言

1.1. 初始化


由第一阶段汇编得知,最后跳到C语言的start_armboot,这个函数在lib_arm/board.c

1.1.1. 全局结构体

程序一开始申请两个全局结构体gdbdgd是全局相关的变量,主要有波特率,环境变量地址,帧缓冲地址,还有一个flag

typedef	struct	global_data {
	bd_t		*bd;
	unsigned long	flags;
	unsigned long	baudrate;
	unsigned long	have_console;		/* serial_init() was called */
	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
	void		**jt;					/* jump table */
} gd_t;

/*
 * Global Data Flags
 */
#define	GD_FLG_RELOC	0x00001		/* Code was relocated to RAM		*/
#define	GD_FLG_DEVINIT	0x00002		/* Devices have been initialized	*/
#define	GD_FLG_SILENT	0x00004		/* Silent mode				*/
#define	GD_FLG_POSTFAIL	0x00008		/* Critical POST test failed		*/
#define	GD_FLG_POSTSTOP	0x00010		/* POST seqeunce aborted		*/
#define	GD_FLG_LOGINIT	0x00020		/* Log Buffer has been initialized	*/
#define GD_FLG_DISABLE_CONSOLE	0x00040		/* Disable console (in & out)	 */

bd主要是存储开发板信息,重要的有机器码arch_number,启动参数boot_params和内存配置,这些信息等到启动内核时,会传递给内核。

typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    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];
} bd_t;

bd主要是存储开发板信息,重要的有机器码arch_number,启动参数boot_params和内存配置,这些信息等到启动内核时,会传递给内核。

typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    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];
} bd_t;


1.1.2. 硬件初始化

接下来是一个函数指针表,进行各种硬件初始化,其中比较重要的是板子初始化board_init、串口初始化serial_init。只要display_banner能打出信息,说明串口可以用了,这是为以后可以调试奠定了基础。除了这个函数指针数组,接下来还会有flash、网卡、环境变量等初始化。

init_fnc_t *init_sequence[] = {
#if defined(CONFIG_ARCH_CPU_INIT)
	arch_cpu_init,		/* basic arch cpu dependent setup */
#endif
	board_init,		/* basic board dependent setup */
#if defined(CONFIG_USE_IRQ)
	interrupt_init,		/* set up exceptions */
#endif
	timer_init,		/* initialize timer */
	env_init,		/* initialize environment */
	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SOFT_I2C)
	init_func_i2c,
#endif
	dram_init,		/* configure available RAM banks */
#if defined(CONFIG_CMD_PCI) || defined (CONFIG_PCI)
	arm_pci_init,
#endif
	display_dram_config,
	NULL,
};

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}

1.2. 主循环

完成了相关的初始化后,u-boot进入一个死循环。

/* main_loop() can return to retry autoboot, if so just run it again. */

for (;;) {

main_loop ();

}

这个死循环获取环境变量bootdelay的值,然后进行倒计时,在这段时间内控制台有按键响应,则进入等待命令输入模式,超时根据bootcmd启动内核。我在这里加了一个run_command("menu",0),即进入命令模式后,执行一个菜单选项,用于一键升级内核-u-boot等操作,方便开发。

main_loop()

{

配置自动完成

获取bootdelay

获取bootcmd

没有按键按下,执行bootcmd启动内核,否则继续向下执行

run_command("menu",0);  //==交互菜单

for()

{

len = readline (CONFIG_SYS_PROMPT); //==读输入

run_command (lastcommand, flag);

}

}

1.2.1. 加载内核

加载启动内核来至于run_command(bootcmd),首先是加载,把内核从flash拷贝到内存的指定位置。

 

加载内核

{

内核加载地址 image_header loader

内核运行地址 image_header ep

 

Flash拷贝kernel到内存 

nand read 内存地址(0x30007fc0) Flash偏移 大小

启动内核

bootm 内存地址(0x30008000)

}

1.2.2. 启动内核

启动内核,根据内核的编译地址和实际地址,决定要不要移动内核,启动内核之前,要设置给内核的参数,使用tag结构体。常用的保护5tag,开头setup_start_tag结尾setup_end_tag ,内存setup_memory_tags,命令行setup_commandline_tag (bd, commandline)setup_initrd_tag (bd, images->rd_start, images->rd_end)。最后启动内核是一个函数指针theKernel = (void (*)(int, int, uint))images->ep;//image_header的入口地址,第一个参数固定是0,第2个是机器码,保存在上面提到的bd全局结构体,第三个是内核参数tagbootloader巧妙地利用函数指针及传参规范将R0:0x0R1:机器号,R2:参数地址传递给内核.

 

do_bootm

{

bootm_start

{

boot_get_kernel

{

memmove

}

xxx

do_bootm_linux

}

}

 

do_bootm_linux

{

theKernel = (void (*)(int, int, uint))images->ep;//image_header的入口地址

 

获取machid

hyq2440.c board_init设置 gd->bd->bi_boot_params = 0x30000100;

这个就是tag起始地址

 

setup_start_tag (bd);

setup_memory_tags (bd);

setup_commandline_tag (bd, commandline); //根据bootargs设置tag

setup_initrd_tag (bd, images->rd_start, images->rd_end);

setup_end_tag (bd);

 

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

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值