最近一段时间由于项目需求,又要再一次对uboot动刀实现快速启动以及一些前置的初始化工作。uboot这东西啊,常用不常动,每一次涉及到修改或移植uboot时大多要间隔一两个月的时间,甚至更久。所以为了方便大家不重复劳动,在这里记录下uboot的启动流程;同时希望能对初学者有所帮助。本文是对hisi3518ev200平台下的uboot-2010.06进行分析。由于个人水平有限,难免会对某些概念理解有所偏差,希望大家能指出修正;如有哪些地方没有解释清楚,欢迎留言,共同学习。
uboot的入口是start.S汇编文件中名为_start的标识符。它的执行流程是:
_start --> reset --> normal_start_flow --> start_armboot(完成初始化) --> main_loop(控制台循环检索命令与启动内核)
(1)设置cpu模式。(设置到SVC32模式)
(2)清除指令、数据高速缓存。
(3)关闭mmu和高速缓存。
(4)读取系统寄存器REG_SC_GEN2,检查ziju标志位。
(5)执行normal_start_flow。
(1)初始化串口,打印启动信息System startup。执行了uart_early_init(uart.S),这个函数初始化了串口外设,操作如下:
(2)检查是否从fmc进行引导。
(3)清除重映射,及重映射标志位。
(4)使能指令高速缓存。
(5)检查动态内存(DDR等)是否在工作。
(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
(7)重定位异常代码。
(8)设置uboot堆栈。
(9)清除bss段。
(10)转跳到uboot第二阶段,C代码阶段start_armboot。
(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上的区间分布为:
(3)start_armboot所做的工作
1)init_sequence的板载初始化
1)cpu初始化
2)定时器初始化
3)板载初始化
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)初始化网卡。
(1)读取与更新启动次数。
(2)初始化自动补全功能。
(3)tftp自动更新。
(4)读取bootdelay。
(5)检查在bootdelay的时间里,是否有按键按下。
(6)运行命令监测程序。根据串口输入的命令行事。