u-boot发展至今,版本已经很多,随着版本的升级,框架越来越复杂,不过其启动流程的核心过程都是一样的,本博文以当前最新u-boot-2017.05为例分析其启动过程,主要以框架为主。
u-boot的启动过程可以分为两个阶段,分别如下:
第一阶段:
.初始化硬件:如关看门狗、设置时钟、设置SDRAM、初始化NANFLASH等
.如果u-boot的代码量较大,将其u-boot代码加载到SDRAM,即重定位到SDRAM
.设置好栈
.跳转到第二阶段代码入口
第二阶段
.初始化本阶段使用的一些硬件设备
.检测系统内存映射
.将内核从FLASH读取到RAM中
.设置“要传给内核的参数”
.调用内核
由于内容较多,关于u-boot-2017.05的启动过程,分为两部分进行分析,本文分析u-boot-2017.05启动过程的第一阶段。本文以TQIMX6开发版为例。
第一部分 u-boot-2017.05启动过程的第一阶段
1 程序的入口
由链接文件u-boot-2017.05\arch\arm\cpu\u-boot.lds的ENTRY(_start)可知,程序的入口在_start。
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
......
. = 0x00000000;
. = ALIGN(4);
.text :
{
*(.__image_copy_start)
*(.vectors)
CPUDIR/start.o (.text*)
*(.text*)
}
在u-boot-2017.05版本中,入口_start在u-boot-2017.05\arch\arm\lib\vectors.S中,
_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq</span></code></pre><br /><br /><p><span style="font-size:12px;">在vectors.S中,可以看到,从_start入口进入后,立刻跳转到reset去执行。reset在</span><span style="font-size:12px;"><strong>u-boot-2017.05\arch\arm\cpu\armv7\start.S</strong></span><span style="font-size:12px;">中。</span></p>
在start.S中,顺序执行以下操作:
(1)单板保存一些boot重要参数(默认不保存)
reset:
/* Allow the board to save important registers */
b save_boot_params
</span>save_boot_params_ret:
#ifdef CONFIG_ARMV7_LPAE<span style="white-space:pre"> </span>/* 未定义,因此实际上什么也没做 */
/*
* check for Hypervisor support
*/
mrc p15, 0, r0, c0, c1, 1 @ read ID_PFR1
and r0, r0, #CPUID_ARM_VIRT_MASK @ mask virtualization bits
cmp r0, #(1 << CPUID_ARM_VIRT_SHIFT)
beq switch_to_hypervisor
switch_to_hypervisor_ret:
#endif
......
ENTRY(save_boot_params)
</span> b save_boot_params_ret @ back to my caller
ENDPROC(save_boot_params)
.weak save_boot_params
(2)屏蔽中断
/*
* disable interrupts (FIQ and IRQ), also set the cpu to SVC32 mode,
* except if in HYP mode already
*/
mrs r0, cpsr
and r1, r0, #0x1f @ mask mode bits
teq r1, #0x1a @ test for HYP mode
bicne r0, r0, #0x1f @ clear all mode bits
orrne r0, r0, #0x13 @ set SVC mode
orr r0, r0, #0xc0 @ disable FIQ and IRQ
msr cpsr,r0
(3)底层相关初始化,然后跳转到_main函数执行。
#ifndef CONFIG_SKIP_LOWLEVEL_INIT bl cpu_init_cp15 #ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY bl cpu_init_crit </span>#endif #endif
bl _main
</span> …
ENTRY(cpu_init_crit)
/*
* Jump to board specific initialization…
* The Mask ROM will have already initialized
* basic memory. Go here to bump up clock rate and handle
* wake up conditions.
*/
b lowlevel_init @ go setup pll,mux,memory
</span>ENDPROC(cpu_init_crit)
2 板级的操作
_main函数在u-boot-2017.05\arch\arm\lib\crt0.S中,顺序呢执行如下操作:
ENTRY(_main)
/*
- Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK)
ldr r0, =(CONFIG_SPL_STACK)
#else
ldr r0, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
bic r0, r0, #7 /* 8-byte alignment for ABI compliance /
mov sp, r0
bl board_init_f_alloc_reserve
mov sp, r0
/ set up gd here, outside any C code */
mov r9, r0
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f /* u-boot-2017.05\common\board_f.c */
......
ldr r0, [r9, #GD_RELOCADDR] /* r0 = gd->relocaddr */
b relocate_code /* u-boot-2017.05\arch\arm\lib\relocate.S */
......
#if ! defined(CONFIG_SPL_BUILD)
bl coloured_LED_init
bl red_led_on
#endif
/* call board_init_r(gd_t *id, ulong dest_addr) /
mov r0, r9 / gd_t /
ldr r1, [r9, #GD_RELOCADDR] / dest_addr /
/ call board_init_r /
#if CONFIG_IS_ENABLED(SYS_THUMB_BUILD)
ldr lr, =board_init_r / this is auto-relocated! /
bx lr
#else
ldr pc, =board_init_r / u-boot-2017.05\common\board_r.c:this is auto-relocated! /
#endif
/ we should not return here. */
#endif
.board_init_f:u-boot-2017.05\common\board_f.c -> 通过initcall_run_list(init_sequence_f)执行一系列前半部分板级的初始化函数
.relocate_code:u-boot-2017.05\arch\arm\lib\relocate.S -> 重定位u-boot代码,包括复制u-boot代码到SDRAM的过程
.board_init_r:u-boot-2017.05\common\board_r.c -> 通过initcall_run_list(init_sequence_r)执行一系列后半部分的板级初始化函数,并最终调用run_main_loop函数 -> main_loop函数后不再返回,从而完成u-boot第一阶段的启动过程。