uboot分析与概览

最近一段时间由于项目需求,又要再一次对uboot动刀实现快速启动以及一些前置的初始化工作。uboot这东西啊,常用不常动,每一次涉及到修改或移植uboot时大多要间隔一两个月的时间,甚至更久。所以为了方便大家不重复劳动,在这里记录下uboot的启动流程;同时希望能对初学者有所帮助。本文是对hisi3518ev200平台下的uboot-2010.06进行分析。由于个人水平有限,难免会对某些概念理解有所偏差,希望大家能指出修正;如有哪些地方没有解释清楚,欢迎留言,共同学习。

 

一、uboot的启动顺序

uboot的入口是start.S汇编文件中名为_start的标识符。它的执行流程是:

_start --> reset --> normal_start_flow --> start_armboot(完成初始化) --> main_loop(控制台循环检索命令与启动内核)

 

二、uboot执行流程概览

1、reset(start.S)

(1)设置cpu模式。(设置到SVC32模式)

(2)清除指令、数据高速缓存。

(3)关闭mmu和高速缓存。

(4)读取系统寄存器REG_SC_GEN2,检查ziju标志位。

  1. 自举启动就是冷启动。芯片上电启动一般都会执行由硬件厂商写入并锁死的启动程序,用这个程序去执行flash和sram地址分配等操作。而海思芯片的自举程序执行结束前应该把ziju标志设置到了相应的寄存器上。
  2. 冷启动时SOC上的所有外部都没被初始化,所以要初始化PLL、DDRC、引脚复用、消除ziju标志,随后跳到自举代码指定的地方执行操作(可能是热启动操作)。
  3. ziju标志没设置就是热启动。

(5)执行normal_start_flow。

 

2、normal_start_flow(start.S)

(1)初始化串口,打印启动信息System startup。执行了uart_early_init(uart.S),这个函数初始化了串口外设,操作如下:

  1. Disable UART
  2. Set baud rate to 115200, uart clock:24M
  3. Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled.
  4. Enable UART

(2)检查是否从fmc进行引导。

  1. 是,再检查是否从emmc引导。

(3)清除重映射,及重映射标志位。

(4)使能指令高速缓存。

(5)检查动态内存(DDR等)是否在工作。

  1. 否,重新初始化,重新引导。

(6)代码重定位到动态内存。执行relocate。相当于memcpy(起始地址,目标地址,大小)

adrl 	r0, _start		@ r0 stores current position of code
ldr	r1, _TEXT_BASE	@ r1 stores where we will copy uboot to
ldr	r2, _armboot_start
ldr	r3, _bss_start
sub	r2, r3, r2		@ r2 <- size of armboot
bl	memcpy
  1. 重定向涉及到位置无关码与位置有关码,位置无关码指的是不涉及链接脚本地址的代码段,位置无关码跳转时一般只会进行短跳转(短跳转是用当前地址来计算的相对偏移值,长跳转是链接地址的绝对值),位置有关码指的是涉及链接脚本地址的跳转代码。当链接地址与运行地址相同时,就没有这种区分了。
  2. 代码的第一行取的是当前运行代码的地址,第二行则是链接的地址,在代码编译链接时根据makefile的设置会将其链接到DDR对应的地址上。

(7)重定位异常代码。

(8)设置uboot堆栈。

(9)清除bss段。

  1. 综上,我们可以得出DDR上区间的分布,如图:

uboot分析与概览_第1张图片

(10)转跳到uboot第二阶段,C代码阶段start_armboot。

  1. 代码的跳转时,使用的是链接的地址进行的,代码链接时会根据makefile会把链接地址设置在DDR对应的地址,所以start_armboot的代码就是我们所说的位置有关码。这时开始正式在DDR运行了。

3、start_armboot(board.c)

(1)在uboot启动的第二个阶段涉及到几个重要的数据结构,先列出来。

(global_data.h)。

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
#ifdef CONFIG_FSL_ESDHC
	unsigned long	sdhc_clk;
#endif
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	phys_size_t	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table */
} gd_t;

(u-boot.h)

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 */uboot给kernel传参用的地址
    struct				/* RAM configuration */
    {
	ulong start;
	ulong size;
    }			bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;

(environment.h)

typedef	struct environment_s {
	uint32_t	crc;		/* CRC32 over data bytes	*/
#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
	unsigned char	flags;		/* active/obsolete flags	*/
#endif
	unsigned char	data[ENV_SIZE]; /* Environment data		*/
} env_t;

(2)在这一阶段中,可以看出DDR上的区间分布为:

uboot分析与概览_第2张图片

(3)start_armboot所做的工作

1)init_sequence的板载初始化

1)cpu初始化

2)定时器初始化

3)板载初始化

  • 1、选择串口时钟
  • 2、设置全局变量gd中的cpu以及引导参数
  • 3、确认引导方式(spi nor 、spi nand)

4)中断初始化,其时是定时器初始化,这个定时器主要是用来定时或延时的。由于没有中断处理,定时或延时只能使用查询的方法。

5)环境初始化,将环境变量设置成默认环境。

6)串口波特率初始化,从环境变量中打到 baudrate,将其转化成十进制并给全局变量gd中的波特率成员赋值。

7)串口初始化,再次初始化一次,所用的波特率并不是环境变量中的。

8)控制台首次初始化,设置全局变量have_console成员。

9)显示logo (display_banner),打印版本信息。

10)打印cpu信息

11)打印板信息 checkboard

12)i2c初始化

13)dram初始化,设置全局变量有关dram的成员(起始地址、空间大小)

14)pci初始化

15)打印dram信息

2)初始化内存堆栈,清除malloc空间,做好相关记录。

3)初始化nor flash,打印nor flash配置信息。VFD的配置或LCD配置。

4)初始化各种类型的储存器(flash、nand、onenand、mmc等)。检查是否SD、USB卡升级等。

5)环境变量重定位、VFD驱动、初始化其他串口。

6)设置全局变量的ip地址。

7)初始化标准输入输出设备,并将其写入链表。

8)控制台的第二次初始化,为控制台邦定输入输出,从输入输出链表中找出设备进行邦定。设置相应的控制台环境变量。

9)初始化杂散类设备。(空)

10)使能中断。(空)

11)初始化网卡。

 

4、main_loop(main.c)

(1)读取与更新启动次数。

(2)初始化自动补全功能。

(3)tftp自动更新。

(4)读取bootdelay。

(5)检查在bootdelay的时间里,是否有按键按下。

  1. 否,执行最后加载的命令,一般是bootcmd中的命令。

(6)运行命令监测程序。根据串口输入的命令行事。

 

 

你可能感兴趣的:(uboot)