芯片到uboot啟動(dòng)流程
ROM → SPL→ uboot.img
簡介
在335x 中ROM code是第一級(jí)的bootlader。mpu上電后將會(huì)自動(dòng)執(zhí)行這里的代碼,完成部分初始化和引導(dǎo)第二級(jí)的bootlader,第二級(jí)的bootlader引導(dǎo)第三級(jí)bootader,在ti官方上對(duì)于第二級(jí)和第三級(jí)的bootlader由uboot提供。
SPL
To unify all existing implementations for a secondary program loader (SPL) and to allow simply adding of new implementations this generic SPL framework has been created. With this framework almost all source files for a board can be reused. No code duplication or symlinking is necessary anymore.
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》 Bootloading real u-boot from the BootDevice and passing control to it.
uboot spl源代碼分析
一、makefile分析
打開spl文件夾只有一個(gè)makefile 可見spl都是復(fù)用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/drivers
LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot-spl.lds
這個(gè)為鏈接腳本
二、u-boot-spl.lds
__start 為程序開始
__image_copy_end
_end
三、代碼解析
__start 為程序開始 (arch/arm/cpu/armv7/start.S)
.globl _start 這是在定義u-boot的啟動(dòng)定義入口點(diǎn),匯編程序的缺省入口是 start標(biāo)號(hào),用戶也可以在連接腳本文件中用ENTRY標(biāo)志指明其它入口點(diǎn)。
.global是GNU ARM匯編的一個(gè)偽操作,聲明一個(gè)符號(hào)可被其他文檔引用,相當(dāng)于聲明了一個(gè)全局變量,.globl和.global相同。該部分為處理器的異常處理向量表。地址范圍為0x0000 0000 ~ 0x0000 0020,剛好8條指令。
為什么是8條指令呢?這里來算一算。首先,一條arm指令為32bit(位),0x0000 0020換算成十進(jìn)制為2^5=32B(字節(jié)),而32(B) = 4 * 8(B) = 4 * 8 * 8( bit),所以剛好8條指令(一個(gè)字節(jié)Byte包含8個(gè)位bit)。
下面是在匯編程序種經(jīng)常會(huì)遇到的異常向量表。Arm處理器一般包括復(fù)位、未定義指令、SWI、預(yù)取終止、數(shù)據(jù)終止、IRQ、FIQ等異常,其中U-Boot中關(guān)于異常向量的定義如下:
_start: b reset
_start 標(biāo)號(hào)表明oot程序從這里開始執(zhí)行。
b是不帶返回的跳轉(zhuǎn)(bl是帶返回的跳轉(zhuǎn)),意思是無條件直接跳轉(zhuǎn)到reset標(biāo)號(hào)出執(zhí)行程序。b是最簡單的分支,一旦遇到一個(gè) b 指令,ARM處理器將立即跳轉(zhuǎn)到給定的地址,從那里繼續(xù)執(zhí)行。注意存儲(chǔ)在分支指令中的實(shí)際的值是相對(duì)當(dāng)前的R15的值的一個(gè)偏移量;而不是一個(gè)絕對(duì)地址。它的值由匯編器來計(jì)算,它是 24 位有符號(hào)數(shù),左移兩位后有符號(hào)擴(kuò)展為32 位,表示的有效偏移為 26 位。
ldr pc, _undefined_instr tion //未定義指令
ldr pc, _software_interrupt //軟中斷SWI
ldr pc, _prefetch_abort //預(yù)取終止
ldr pc, _data_abort //數(shù)訪問終止
ldr pc, _not_used
ldr pc, _irq //中斷請(qǐng)求IRQ
ldr pc, _fiq //快速中斷FIQ
#ifdef CONFIG_SPL_BUILD //該階段為spl執(zhí)行下面代碼
_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 {,} …
作用:插入一個(gè)32-bit的數(shù)據(jù)隊(duì)列。(與armasm中的DCD功能相同)
.balignl 16,0xdeadbeef
.align偽操作用于表示對(duì)齊方式:通過添加填充字節(jié)使當(dāng)前位置滿足一定的對(duì)齊方式。
接下來是對(duì)各個(gè)段代碼的定義
略
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
//啟動(dòng)方式
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)
//設(shè)置cpu的工作模式設(shè)置CPU的狀態(tài)類型為SVC特權(quán)模式
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
//關(guān)閉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
//調(diào)用初始化函數(shù)
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
//設(shè)置堆棧指針
/* 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)
//設(shè)置堆棧指針,并調(diào)用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』
調(diào)用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)
跳轉(zhuǎn)到spl的第二階段
board_init_r:(u-boot-2011.09-psp04.06.00.03/arch/arm/cpu/armv7/omap-common/spl.c)
初始化時(shí)鐘: timer_init()
i2c 初始化: i2c_init();
獲取啟動(dòng)方式 omap_boot_device();
判斷啟動(dòng)方式從不同的地方裝載鏡像
從mmc 中裝載鏡像 spl_mmc_load_image();
從nand 中裝載鏡像 spl_nand_load_image();
從 uart 中裝載鏡像 spl_ymodem_load_image();
判斷鏡像類型
跳轉(zhuǎn)到鏡像中執(zhí)行鏡像 jump_to_image_no_args();
裝載鏡像 將會(huì)從配置的存儲(chǔ)介質(zhì)中讀取數(shù)據(jù) 及uboot鏡像
然后跳轉(zhuǎn)到uboot中執(zhí)行uboot
評(píng)論
查看更多