代码入口:_start
从链接脚本中可知,uboot的入口地址为_start
# u-boot.lds
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
_start
如下
// arch/arm/lib/vectors.S
.section ".vectors", "ax"
_start:
#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
.word CONFIG_SYS_DV_NOR_BOOT_CFG
#endif
ARM_VECTORS
#endif /* !defined(CONFIG_ENABLE_ARM_SOC_BOOT0_HOOK) */
/*
*************************************************************************
*
* Indirect vectors table
*
* Symbols referenced here must be defined somewhere else
*
*************************************************************************
*/
.globl _reset
.globl _undefined_instruction
.globl _software_interrupt
.globl _prefetch_abort
.globl _data_abort
.globl _not_used
.globl _irq
.globl _fiq
由上可知,这是arm32定义的规范的异常向量表,宏ARM_VECTORS
定义如下
// arch/arm/lib/vectors.S
/*
* A macro to allow insertion of an ARM exception vector either
* for the non-boot0 case or by a boot0-header.
*/
.macro ARM_VECTORS
#ifdef CONFIG_ARCH_K3
ldr pc, _reset
#else
b reset
#endif
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
.endm
查看reset
内容
// arch/arm/cpu/armv7/start.S
reset:
/* Allow the board to save important registers */
b save_boot_params
// arch/arm/cpu/armv7/start.S
ENTRY(save_boot_params)
b save_boot_params_ret @ back to my caller
ENDPROC(save_boot_params)
// arch/arm/cpu/armv7/start.S
save_boot_params_ret:
/*
* 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
save_boot_params_ret
内容如上,由cpsr寄存器内容可知,r1获取处理器的当前工作模式:M[4:0],并且设置SVC用户模式,同时屏幕FIQ和IRQ中断,写回cpsr寄存器
M[4:0]为10011表示SVC模式
设置SCTLR寄存器中的VBAR异常向量表基址
- V[13] = 0:异常向量表基址为0x0,该地址可以被re-mapped(重映射)
- V[13] = 1:异常向量表基址为0xffff0000,此时该地址不能被重映射
/*
* Setup vector:
* (OMAP4 spl TEXT_BASE is not 32 byte aligned.
* Continue to use ROM code vector only in OMAP4 spl)
*/
#if !(defined(CONFIG_OMAP44XX) && defined(CONFIG_SPL_BUILD))
/* Set V=0 in CP15 SCTLR register - for VBAR to point to vector */
mrc p15, 0, r0, c1, c0, 0 @ Read CP15 SCTLR Register
bic r0, #CR_V @ V = 0
mcr p15, 0, r0, c1, c0, 0 @ Write CP15 SCTLR Register
#ifdef CONFIG_HAS_VBAR
/* Set vector address in CP15 VBAR register */
ldr r0, =_start
mcr p15, 0, r0, c12, c0, 0 @Set VBAR
#endif
#endif
接着是cpu_init_cp15
和cpu_init_crit
两部分
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
#ifdef CONFIG_CPU_V7A
bl cpu_init_cp15
#endif
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit
#endif
#endif
cpu_init_cp15
干了什么?
- 关闭MMU和清理缓存
/*************************************************************************
*
* cpu_init_cp15
*
* Setup CP15 registers (cache, MMU, TLBs). The I-cache is turned on unless
* CONFIG_SYS_ICACHE_OFF is defined.
*
*************************************************************************/
ENTRY(cpu_init_cp15)
//
ENDPROC(cpu_init_cp15)
cpu_init_crit
呢?与具体开发板相关
/*************************************************************************
*
* CPU_init_critical registers
*
* setup important registers
* setup memory timing
*
*************************************************************************/
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
ENDPROC(cpu_init_crit)
环境准备:_main
主要作用是用于初始化C语言环境
// arch/arm/lib/crt0.S
/*
* entry point of crt0 sequence
*/
ENTRY(_main)
先来看前半段
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_TPL_BUILD) && defined(CONFIG_TPL_NEEDS_SEPARATE_STACK)
ldr r0, =(CONFIG_TPL_STACK)
#elif 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
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_EARLY_BSS)
CLEAR_BSS
#endif
mov r0, #0
bl board_init_f
设置sp寄存器指向CONFIG_SYS_INIT_SP_ADDR && 0x1000
(8字节对齐)
board_init_f_alloc_reserve
用于为早期malloc和GD全局数据区留出空间,如下,并且返回修改后的sp寄存器,并且在board_init_f_init_reserve
初始化GD的值
GD保存了uboot中用到的所有全局变量
ulong board_init_f_alloc_reserve(ulong top)
{
/* Reserve early malloc arena */
#if CONFIG_VAL(SYS_MALLOC_F_LEN)
top -= CONFIG_VAL(SYS_MALLOC_F_LEN);
#endif
/* LAST : reserve GD (rounded up to a multiple of 16 bytes) */
top = rounddown(top-sizeof(struct global_data), 16);
return top;
}
board_init_f
用于调用init_sequence_f
中的函数,如下,其作用是初始化uboot的一些功能以及填充GD表
void board_init_f(ulong boot_flags)
{
gd->flags = boot_flags;
gd->have_console = 0;
if (initcall_run_list(init_sequence_f))
hang();
#if !defined(CONFIG_ARM) && !defined(CONFIG_SANDBOX)