总结于朱有鹏老师的嵌入式课程,感谢朱老师
uboot中因为有汇编阶段参与,因此不能直接找main.c。整个程序的入口取决于链接脚本中ENTRY声明的地方。ENTRY(_start)因此_start符号所在的文件就是整个程序的起始文件
#include //里面是#include 包括配置文件的宏
#include //包含了include/version_autogenerated.h,版本号信息
#if defined(CONFIG_ENABLE_MMU)
#include //里面是include/asm-arm/proc-armv/domain.h
#endif
#include
提前占位16字节保证正式的image的头部确实有16字节,SD卡启动/Nand启动等整个镜像开头需要16字节的校验头。
#if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)
.word 0x2000 //.word相当于c中的int
.word 0x0
.word 0x0
.word 0x0
#endif
异常向量表
.globl _start
_start: 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
_undefined_instruction: //异常处理函数
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_used:
.word not_used
_irq:
.word irq
_fiq:
.word fiq
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef //当前地址对齐排布如果不对齐则自动向后走,向后走的那些内存要用0xdeadbeef来填充
//对齐访问有时候是效率的要求,有时候是硬件的特殊要求。
其中复位异常处的代码
reset:
/*
* set the cpu to SVC32 mode and IRQ & FIQ disable
*/
@;mrs r0,cpsr
@;bic r0,r0,#0x1f
@;orr r0,r0,#0xd3
@;msr cpsr,r0
msr cpsr_c, #0xd3 @ 将CPU设置为禁止FIQ IRQ,ARM状态,SVC模式。
_TEXT_BASE:
.word TEXT_BASE //Makefile时配置阶段的TEXT_BASE,是我们链接时指定的uboot的链接地址。(值就是c3e00000)
_TEXT_PHY_BASE:
.word CFG_PHY_UBOOT_BASE //33e00000 uboot在DDR中的物理地址
如果用中断进行处理
#if defined(CONFIG_USE_IRQ)
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
bl disable_l2cache // 禁止L2 cache
bl set_l2cache_auxctrl_cycle // l2 cache相关初始化
bl enable_l2cache // 使能l2 cache
刷新L1 cache的icache和dcache。
/*
* Invalidate L1 I/D
*/
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
关闭MMU
/*
* disable MMU stuff and caches
*/
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM)
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB
mcr p15, 0, r0, c1, c0, 0
识别并暂存启动介质选择,启动是由SoC的OM5:OM0这6个引脚的高低电平决定的
/* Read booting information */
ldr r0, =PRO_ID_BASE
ldr r1, [r0,#OMR_OFFSET]
bic r2, r1, #0xffffffc1
/* NAND BOOT */
cmp r2, #0x0 @ 512B 4-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x2 @ 2KB 5-cycle
moveq r3, #BOOT_NAND
cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND
cmp r2, #0x8 @ OneNAND Mux
moveq r3, #BOOT_ONENAND
/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD //r3中赋值#BOOT_MMCSD(0x03)以后备用
/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR
/* Uart BOOTONG failed */
cmp r2, #(0x1<<4)
moveq r3, #BOOT_SEC_DEV
ldr r0, =INF_REG_BASE
str r3, [r0, #INF_REG3_OFFSET] //将#BOOT_MMCSD写入了INF_REG3寄存器中存储
ldr sp, =0xd0036000 /* end of sram dedicated to u-boot */
sub sp, sp, #12 /* set stack设置栈 */
mov fp, #0
bl lowlevel_init /* go setup pll,mux,memory底层初始化 */
检查复位状态,直接冷上电、热启动、睡眠(低功耗)状态下的唤醒这些情况都属于复位
ldr r0, =(ELFIN_CLOCK_POWER_BASE+RST_STAT_OFFSET)
ldr r1, [r0]
bic r1, r1, #0xfff6ffff
cmp r1, #0x10000
beq wakeup_reset_pre
cmp r1, #0x80000
beq wakeup_reset_from_didle
IO状态恢复
ldr r0, =(ELFIN_CLOCK_POWER_BASE + OTHERS_OFFSET)
ldr r1, [r0]
ldr r2, =IO_RET_REL
orr r1, r1, r2
str r1, [r0]
关看门狗
ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */
mov r1, #0
str r1, [r0]
供电锁存
ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
ldr r1, [r0]
orr r1, r1, #0x300
orr r1, r1, #0x1
str r1, [r0]
判断当前代码执行位置,是否重定位
ldr r0, =(ELFIN_CLOCK_POWER_BASE + PS_HOLD_CONTROL_OFFSET)
ldr r1, [r0]
orr r1, r1, #0x300
orr r1, r1, #0x1
str r1, [r0]
判定当前代码执行的位置在SRAM中还是在DDR中
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 //相等则在DDR中
beq 1f /* r0 == r1 then skip sdram init */
//如果当前代码是在SRAM中,说明冷启动,那么时钟和DDR都需要初始化.否则跳过
/* init system clock */
bl system_clock_init //初始化时钟
/* Memory initialize */
bl mem_ctrl_asm_init //初始化内存
1: //相等跳到这里
/* for UART */
bl uart_asm_init //初始化串口
bl tzpc_init //
再次供电锁存,但其实前面已经执行过了,这里可能是保险
ldr r0, =0xE010E81C /* PS_HOLD_CONTROL register */
ldr r1, =0x00005301 /* PS_HOLD output high */
str r1, [r0]
因为上一次设置栈DDR尚未初始化,因此程序执行都是在SRAM中,所以在SRAM中分配了一部分内存作为栈。本次因为DDR已经被初始化了,因此要把栈挪移到DDR中,所以要重新设置栈,这是第二次设置
ldr sp, _TEXT_PHY_BASE /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0 /* no previous frame, so fp=0 */
再次用相同的代码判断运行地址是在SRAM中还是DDR中,这次判断是为了决定是否进行uboot的relocate。
ldr r0, =0xff000fff
bic r1, pc, r0 /* r0 <- current base addr of code */
ldr r2, _TEXT_BASE /* r1 <- original base addr in ram */
bic r2, r2, r0 /* r0 <- current base addr of code */
cmp r1, r2 /* compare r0, r1 */
beq after_copy /* r0 == r1 then skip flash copy */
D0037488这个内存地址在SRAM中,这个地址中的值是被硬件自动设置的。硬件根据我们实际电路中SD卡在哪个通道中,会将这个地址中的值设置为相应的数字。
#if defined(CONFIG_EVT1)
/* If BL1 was copied from SD/MMC CH2 */
ldr r0, =0xD0037488
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
#endif
INF_REG3寄存器中的#BOOT_MMCSD和#BOOT_MMCSD去比较确定是从MMCSD启动
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND /* 0x0 => boot device is nand */
beq nand_boot
cmp r1, #BOOT_ONENAND /* 0x1 => boot device is onenand */
beq onenand_boot
cmp r1, #BOOT_MMCSD
beq mmcsd_boot
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot