芯片到uboot启动流程
ROM → SPL→ uboot.img
简介
在335x 中ROM code是第一级的bootlader。mpu上电后将会自动执行这里的代码,完成部分初始化和引导第二级的bootlader,第二级的bootlader引导第三级bootader,在 TI 官方上对于第二级和第三级的bootlader由uboot提供。
SPL
To unify all exis TI ng implementa TI ons for a secondary program loader (SPL) and to allow simply adding of new implementa TI ons this generic SPL framework has been crea te d. With this framework almost all source files for a board can be reused. No code duplication or symlinking is necessary anymore.
1》 Basic ARM initialization
2》 UART console initialization
3》 Clocks and DPLL locking (minimal)
4》 SDRAM initialization
5》 Mux (minimal)
6》 BootDevice initialization(based on where we are booting from.MMC1/MMC2/Nand/Onenand)
7》 Bootlo adi ng real u-boot from the BootDevice and passing control to it.
uboot spl源代码分析
一、makefile分析
打开spl文件夹只有一个makefile 可见spl都是复用uboot原先的代码。
主要涉及的代码文件为u-boot-2011.09-psp04.06.00.03/arch/arm/ cpu /armv7
u-boot-2011.09-psp04.06.00.03/arch/arm/lib
u-boot-2011.09-psp04.06.00.03/drive rs
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds
这个为链接脚本
二、u-boot-spl.lds
__start 为程序开始
__image_copy_end
_end
三、代码解析
__start 为程序开始 (arch/arm/cpu/armv7/start.S)
.globl _start 这是在定义u-boot的启动定义入口点,汇编程序的缺省入口是 start标号,用户也可以在连接脚本文件中用ENTRY标志指明其它入口点。
.global是GNU ARM汇编的一个伪操作,声明一个符号可被其他文档引用,相当于声明了一个全局变量,.globl和.global相同。该部分为处理器的异常处理向量表。地址范围为0x0000 0000 ~ 0x0000 0020,刚好8条指令。
为什么是8条指令呢?这里来算一算。首先,一条arm指令为32bit(位),0x0000 0020换算成十进制为2^5=32B(字节),而32(B) = 4 * 8(B) = 4 * 8 * 8( bit),所以刚好8条指令(一个字节Byte包含8个位bit)。
下面是在汇编程序种经常会遇到的异常向量表。Arm处理器一般包括复位、未定义指令、SWI、预取终止、数据终止、IRQ、FIQ等异常,其中U-Boot中关于异常向量的定义如下:
_start: b reset
_start 标号表明oot程序从这里开始执行。
b是不带返回的跳转(bl是带返回的跳转),意思是无条件直接跳转到reset标号出执行程序。b是最简单的分支,一旦遇到一个 b 指令,ARM处理器将立即跳转到给定的地址,从那里继续执行。注意存储在分支指令中的实际的值是相对当前的R15的值的一个偏移量;而不是一个绝对地址。它的值由汇编器来计算,它是 24 位有符号数,左移两位后有符号扩展为32 位,表示的有效偏移为 26 位。
ldr pc, _undefined_instr tion //未定义指令
ldr pc, _software_interrupt //软中断SWI
ldr pc, _prefetch_abort //预取终止
ldr pc, _data_abort //数访问终止
ldr pc, _not_used
ldr pc, _irq //中断请求IRQ
ldr pc, _fiq //快速中断FIQ
#ifdef CONFIG_SPL_BUILD //该阶段为spl执行下面代码
_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 */
#else
_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 */
#endif /* CONFIG_SPL_BUILD */
.word为ARM汇编特有的伪操作符,语法如下:
.word {,} …
作用:插入一个32-bit的数据队列。(与armasm中的DCD功能相同)
.balignl 16,0xdeadbeef
.align伪操作用于表示对齐方式:通过添加填充字节使当前位置满足一定的对齐方式。
接下来是对各个段代码的定义
略
Rest: (arch/arm/cpu/armv7/start.S)
bl save_boot_params
save_boot_params: (arch/arm/cpu/armv7/ti81xx/lowlevel_init.S)
#ifdef CONFIG_SPL_BUILD
ldr r4, =ti81xx_boot_device
//ti81xx_boot_device = BOOT_DEVICE_NAND
//启动方式
ldr r5, [r0, #BOOT_DEVICE_OFFSET]
and r5, r5, #BOOT_DEVICE_MASK
str r5, [r4]
#endif
bx lr
回到reset:(arch/arm/cpu/armv7/start.S)
//设置cpu的工作模式设置CPU的状态类型为SVC特权模式
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
cpu_init_crit: (arch/arm/cpu/armv7/start.S)
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
mcr p15, 0, r0, c7, c5, 6 @ invalidate BP array
mcr p15, 0, r0, c7, c10, 4 @ DSB
mcr p15, 0, r0, c7, c5, 4 @ ISB
//关闭mmu 缓存
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 11 (Z---) BTB
#ifdef CONFIG_SYS_ICACHE_OFF
bic r0, r0, #0x00001000 @ clear bit 12 (I) I-cache
#else
orr r0, r0, #0x00001000 @ set bit 12 (I) I-cache
#endif
mcr p15, 0, r0, c1, c0, 0
//调用初始化函数
mov ip, lr @ persevere link reg across call
bl lowlevel_init @ go setup pll,mux,memory
lowlevel_init:(arch/arm/cpu/armv7/ti81xx/lowlevel.S)
/* The link register is saved in ip by start.S */
mov r6, ip
/* check if we are already running from RAM */
ldr r2, _lowlevel_init
_TEXT_BASE:
.word CONFIG_SYS_TEXT_BASE /* Load address (RAM) */
#define CONFIG_SYS_TEXT_BASE 0x80800000
SDRAM的前8MB作为spl的bss段然后前64bytes做为u-boot.img的头
ldr r3, _TEXT_BASE
sub r4, r2, r3
sub r0, pc, r4
//设置堆栈指针
/* require dummy instr or subtract pc by 4 instead i‘m doing stack init */
ldr sp, SRAM_STACK
mark1:
ldr r5, _mark1
sub r5, r5, r2 /* bytes between mark1 and lowlevel_init */
sub r0, r0, r5 /* r0 《- _start w.r.t current place of execution */
mov r10, #0x0 /* r10 has in_ddr used by s_init() */
ands r0, r0, #0xC0000000 /* MSB 2 bits 《》 0 then we are in ocmc or DDR */
cmp r0, #0x80000000
bne s_init_start
mov r10, #0x01
b s_init_start
s_init_start:(arch/arm/cpu/armv7/ti81xx/lowlevel.S)
mov r0, r10 /* passing in_ddr in r0 */
bl s_init
初始化pll mux memery
/* back to arch calling code */
mov pc, r6
call_board_init_f:(arch/arm/cpu/armv7/start.s)
//设置堆栈指针,并调用board_init_f
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
void board_init_f(ulong dummy)
『u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7/omap-common/spl.c』
调用relocate_code(CONFIG_SPL_STACK, &gdata, CONFIG_SPL_TEXT_BASE);
这里使用了 CONFIG_SPL_STACK
#define CONFIG_SPL_STACK LOW_LEVEL_SRAM_STACK
#define LOW_LEVEL_SRAM_STACK (SRAM0_START + SRAM0_SIZE – 4)
gdata 为.bss 前一段的空间描述镜像头
#define CONFIG_SPL_TEXT_BASE 0x402F0400
relocate_code: (arch/arm/cpu/armv7/start.s)
重载定位代码
jump_2_ram: (arch/arm/cpu/armv7/start.s)
跳转到spl的第二阶段
board_init_r:(u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7/omap-common/spl.c)
初始化 时钟 : timer_init()
i2c 初始化: i2c_init();
获取启动方式 omap_boot_device();
判断启动方式从不同的地方装载镜像
从mmc 中装载镜像 spl_mmc_load_image();
从nand 中装载镜像 spl_nand_load_image();
从 uart 中装载镜像 spl_ymodem_load_image();
判断镜像类型
跳转到镜像中执行镜像 jump_to_image_no_args();
装载镜像 将会从配置的存储介质中读取数据 及uboot镜像
然后跳转到uboot中执行uboot