基于友善之臂tiny4412開發(fā)板,uboot版本是2010.12:
一般我們將UBOOT分為2個階段,第一階段主要為匯編代碼,用于初始化必要的硬件并將UBOOT copy到SDRAM中并跳轉(zhuǎn)到SDRAM執(zhí)行,第二階段主要為c代碼,主要作用是加載kernel到SDRAM,準(zhǔn)備啟動kernel的參數(shù)最后跳轉(zhuǎn)到kernel處執(zhí)行,當(dāng)然uboot里也可以有許多擴展功能,比如下載功能,實現(xiàn)各種驅(qū)動程序等.
第一階段:
1.首先就是uboot的入口的地址是arch/arm/cpu/armv7/start.S, 這可以從相同路徑下的連接腳本u-boot.lds 中知道,如下:
----------------------------------------------------------------------------------------------------------------
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
arch/arm/cpu/armv7/start.o (.text)
*(.text)
}
----------------------------------------------------------------------------------------------------------------
2.下面開始結(jié)合代碼分析啟動流程,一開始就會無條件跳轉(zhuǎn)到reset 處執(zhí)行:
----------------------------------------------------------------------------------------------------------------
.globl _start
_start: b reset //直接跳到reset處執(zhí)行
ldr pc, _undefined_instruction // 設(shè)置異常向量表
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
----------------------------------------------------------------------------------------------------------------
3.然后找到reset 處,先關(guān)中斷,進SVC32模式:
----------------------------------------------------------------------------------------------------------------
// the actual reset code
reset:
// set the cpu to SVC32 mode
mrs r0, cpsr
bic r0, r0, #0x1f //cpsr的低五位被清零
orr r0, r0, #0xd3 //關(guān)中斷(irq, fiq),并進入SVC32模式
msr cpsr,r0
----------------------------------------------------------------------------------------------------------------
4.然后跳轉(zhuǎn)到cpu_init_crit 處執(zhí)行:
----------------------------------------------------------------------------------------------------------------
// the mask ROM code should have PLL and others stable
ifndef CONFIG_SKIP_LOWLEVEL_INIT //not define
bl cpu_init_crit //跳轉(zhuǎn)到cpu_init_crit,初始化內(nèi)存,時鐘等關(guān)鍵寄存器 ,就在本文件內(nèi),在稍后的地方
endif
----------------------------------------------------------------------------------------------------------------
5.cpu_init_crit,主要工作就是對cache,MMU的操作,另一個非常重要的事情就是會調(diào)用執(zhí)行板級初始化的文件,具體看注釋吧
----------------------------------------------------------------------------------------------------------------
// CPU_init_critical registers
//
// setup important registers
// setup memory timing
cpu_init_crit:
bl cache_init // 在本版本中此函數(shù)為空函數(shù),什么也不做,直接返回
//初始化cache,位置在 ./board/samsung/tiny4412/lowlevel_init.S:cache_init:
// Invalidate L1 I/D
mov r0, #0 @ set up for MCR
mcr p15, 0, r0, c8, c7, 0 @ invalidate TLBs
//armv7手冊P1374 //清頁表
//ARM最多可支持16個協(xié)處理器p0-p15
mcr p15, 0, r0, c7, c5, 0 @ invalidate icache
// 看注釋應(yīng)該是關(guān)指令cache,armv7手冊P1730,未定義此處的命令,
//不知道什么意思,期待大神現(xiàn)身說法,fix me
// disable MMU stuff and caches
// cp15 c1寄存器的操作在armv7手冊p1334
mrc p15, 0, r0, c1, c0, 0 // 讀cp15 c1寄存器到r0
bic r0, r0, #0x00002000 @ clear bits 13 (--V-)
//設(shè)置異常向量表基地址為0x00000000?<==此地址不是IROM地址碼?
//記得好像此地址應(yīng)該設(shè)置為0xffff0000,fixme
bic r0, r0, #0x00000007 @ clear bits 2:0 (-CAM) // 關(guān)數(shù)據(jù) cache,關(guān) MMU
orr r0, r0, #0x00000002 @ set bit 1 (--A-) Align //strict alignment fault checking enabled.
orr r0, r0, #0x00000800 @ set bit 12 (Z---) BTB //打開指令cache
mcr p15, 0, r0, c1, c0, 0
// 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.
mov ip, lr @ persevere link reg across call
bl lowlevel_init @ go setup pll,mux,memory,
// 進行板級的初始化,主要是時鐘,內(nèi)存,串口,nand等,位置在:
// /board/samsung/tiny4412/lowlevel_init.S lowlevel_init:
mov lr, ip @ restore link
mov pc, lr @ back to my caller // 返回
----------------------------------------------------------------------------------------------------------------
6.下面進入lowlevel_init.S的 lowlevel_init() 進行板級相關(guān)的初始化,其位置在/board/samsung/tiny4412/lowlevel_init.S中
這里面先進行的是一些設(shè)置:設(shè)置棧指針,判斷啟動方式,點亮一個LED等
----------------------------------------------------------------------------------------------------------------
.globl lowlevel_init
lowlevel_init: //主要對PLL及memory初始化,此函數(shù)需要移植來完成
// use iROM stack in bl2
ldr sp, =0x02060000 //設(shè)置棧指針,Iram的最高地址
push {lr}
// check reset status
// INF_REG_BASE的值為0x10020800,為power management info 寄存器的基地址
// 此處INF_REG1_OFFSET的值為4
// 故此處為取INFORM1 寄存器的值
// 此處的意思為判斷系統(tǒng)是否為從sleep狀態(tài)喚醒而來
ldr r0, =(INF_REG_BASE + INF_REG1_OFFSET)
ldr r1, [r0]
// Sleep wakeup reset
ldr r2, =S5P_CHECK_SLEEP
cmp r1, r2
beq wakeup_reset
// set CP reset to low
ldr r0, =0x11000C60
ldr r1, [r0]
ldr r2, =0xFFFFFF0F
and r1, r1, r2
orr r1, r1, #0x10
str r1, [r0]
//此處0x11000C60 為寄存器GPX3CON的地址,此處將此寄存器[4:7]置1,即將GPX3DAT_1 設(shè)為output
ldr r2, =0xFFFFFFF3
and r1, r1, r2
orr r1, r1, #0x4
str r1, [r0]
//此處0x11000C68 為寄存器 GPX3PUD的地址,
//此處將此寄存器[2]置1,即enable GPX3PUD_1 pull_down
ldr r0, =0x11000C64
ldr r1, [r0]
ldr r2, =0xFFFFFFFD
and r1, r1, r2
str r1, [r0]
// 此處0x11000C64 為寄存器 GPX3DAT的地址,
// 此處將此寄存器[2]置1,即enable GPX3DAT_1 置0
// 經(jīng)查電路發(fā)現(xiàn),GPX3DAT_1的信號為XEINT25,外部連的是Gsensor MMA7660的中斷信號
// 啟動系統(tǒng)時為何將此引腳設(shè)為GPIO output 并clear to 0?? fixme!!
// led (GPM4_0~3) on
// 0x110002E0 為寄存器GPM4CON的地址,將GPM4DAT 0~3設(shè)為output,GPM4DATA 4~7
// 設(shè)為input
// 最后兩句將GPM4DATA0設(shè)為0,查看電路圖發(fā)現(xiàn)就是點亮LED1
ldr r0, =0x110002E0
ldr r1, =0x00001111
str r1, [r0]
ldr r1, =0x0e
str r1, [r0, #0x04]
// During sleep/wakeup or AFTR mode, pmic_init function is not available
// and it causes delays. So except for sleep/wakeup and AFTR mode,
// the below function is needed
#if defined(CONFIG_HAS_PMIC)
// 未定義此宏,即開發(fā)板上沒有PMIC,都是分立元件產(chǎn)生的power,
//tiny4412.h中已顯性取消此宏的定義,#undef CONFIG_HAS_PMIC
bl pmic_init
#endif
#if defined(CONFIG_ONENAND) // 未定義此宏
bl onenandcon_init
#endif
#if defined(NAND_BOOTING) // 未定義此宏
bl nand_asm_init
#endif
----------------------------------------------------------------------------------------------------------------
7.下面就會去判斷啟動的位置,
bl read_om // 讀取啟動設(shè)備,在本文件的稍后面
這個函數(shù)的實現(xiàn)由興趣的可以看一次下,看這里:
----------------------------------------------------------------------------------------------------------------
read_om:// 讀取啟動設(shè)備
// Read booting information
ldr r0, =S5PV310_POWER_BASE // power management 寄存器的基地址
ldr r1, [r0,#OMR_OFFSET] // 0x0,讀 OM_STAT 寄存器的值
bic r2, r1, #0xffffffc1 // 除[1:5] 位外,其他位清零,并存入r2
// 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
//真正的決定硬件連接的啟動方式有下面的與r2做比較的常數(shù)決定,本開發(fā)板中的啟動選擇
//開關(guān)只能選擇從EMMC or SD卡啟動,而此處EMMC啟動的寄存器數(shù)字為0x6,SD卡啟動為
//0x4,故啟動選擇開關(guān)只會影響XOM1的值
cmp r2, #0xA
moveq r3, #BOOT_ONENAND
cmp r2, #0x10 @ 2KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND
// SD/MMC BOOT
cmp r2, #0x4
moveq r3, #BOOT_MMCSD
// eMMC BOOT
cmp r2, #0x6
moveq r3, #BOOT_EMMC
// eMMC 4.4 BOOT
cmp r2, #0x8
moveq r3, #BOOT_EMMC_4_4
cmp r2, #0x28
moveq r3, #BOOT_EMMC_4_4
ldr r0, =INF_REG_BASE
str r3, [r0, #INF_REG3_OFFSET] // 將讀到的啟動設(shè)備的結(jié)果寫入INFORM3 寄存器
mov pc, lr // 返回
----------------------------------------------------------------------------------------------------------------
8.回來接著主程序往下看,下面會判斷一下程序是否已經(jīng)運行在RAM里,顯然這是公版uboot里的代碼,友善之臂并沒有刪減掉
----------------------------------------------------------------------------------------------------------------
// when we already run in ram, we don't need to relocate U-Boot.
// and actually, memory controller must be configured before U-Boot
// is running in ram.
// 此處比較PC與0xc3e00000中間3位的值,如果相等則判斷現(xiàn)在已經(jīng)運行在SDRAM里
// 就會跳過SDRAM的初始化,但此時程序還運行在IRAM里,PC的值顯然不可能指向SDRAM
ldr r0, =0xff000fff
bic r1, pc, r0 // r0 <- current base addr of code
ldr r2, _TEXT_BASE // r1 <- original base addr in ram ,值為0xc3e00000,在本文件開始處定義
bic r2, r2, r0 // r0 <- current base addr of code
cmp r1, r2 // compare r0, r1
beq after_copy // r0 == r1 then skip sdram init and u-boot.bin loading
----------------------------------------------------------------------------------------------------------------
9.既然程序還未運行在SDRAM里,那么系統(tǒng)肯定還處于“遠(yuǎn)古時代”,接著就要進行三個最重要的硬件初始化,
----------------------------------------------------------------------------------------------------------------
// init system clock
bl system_clock_init
// 看名字就知道是系統(tǒng)時鐘初始化,定義在./board/samsung/tiny4412/clock_init_tiny4412.S
//Memory initialize
bl mem_ctrl_asm_init // 內(nèi)存初始化,在/board/samsung/tiny4412/mem_init_tiny4412.S
// init uart for debug
bl uart_asm_init // 串口初始化,定義在本文件稍后的地方
----------------------------------------------------------------------------------------------------------------
這三個初始化程序相對過于復(fù)雜,本文重點在于理清uboot的啟動流程,這里不再贅述,有興趣的童鞋可以另尋時間study.
10.下面uboot還貼心的給出了一段測試的代碼
----------------------------------------------------------------------------------------------------------------
// 至此PLL, SDRAM, UART已全部初始化OK, 啟動時要用的最基本的硬件已準(zhǔn)備就緒
// 下面一段代碼是對上面硬件初始化的測試,經(jīng)驗證后已OK,表示到此CLK, SDRAM, UART都已初始化OK
#if CONFIG_LL_DEBUG
mov r4, #0x4000
.L0:
sub r4, r4, #1
cmp r4, #0
bne .L0
mov r0, #'\r'
bl uart_asm_putc
mov r0, #'\n'
bl uart_asm_putc
ldr r1, =0x40000000 //內(nèi)存首地址
ldr r2, =0x87654321
str r2, [r1]
str r2, [r1, #0x04]
str r2, [r1, #0x08]
ldr r2, =0x55aaaa55
str r2, [r1, #0x10]
nop
mov r4, #0xC0000
.L1:
subs r4, r4, #1
bne .L1
ldr r0, [r1]
bl uart_asm_putx
mov r0, #'.'
bl uart_asm_putc
ldr r0, [r1, #0x04]
bl uart_asm_putx
mov r0, #'.'
bl uart_asm_putc
ldr r0, [r1, #0x08]
bl uart_asm_putx
mov r0, #'.'
bl uart_asm_putc
ldr r0, [r1, #0x10]
bl uart_asm_putx
mov r0, #'>'
bl uart_asm_putc
#endif // CONFIG_LL_DEBUG
----------------------------------------------------------------------------------------------------------------
11.繼續(xù)走起,trustzone 這東西真心不懂...,之前有一次編譯內(nèi)核沒把trustzone disable 掉,啟動kernel時會卡住.
bl tzpc_init // 初始化trust zone protection controller,定義在本文件稍后位置
b load_uboot // 將u-boot完整代碼copy到內(nèi)存0x43e00000開始的SDRAM地址上,定義在本文件稍后位置
不過這個load_uboot要看一次下,他就是將uboot完整源碼copy到SDRAM的函數(shù), 調(diào)試的時候一般從sd卡啟動的多,故以SD卡啟動為例:
----------------------------------------------------------------------------------------------------------------
load_uboot:
// 根據(jù)啟動設(shè)備跳轉(zhuǎn)到相應(yīng)處執(zhí)行
ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET] ////read_om將判斷結(jié)果放在寄存器INF_REG3_OFFSET
cmp r1, #BOOT_NAND
beq nand_boot
cmp r1, #BOOT_ONENAND
beq onenand_boot
cmp r1, #BOOT_MMCSD // SD卡啟動
beq mmcsd_boot
cmp r1, #BOOT_EMMC
beq emmc_boot
cmp r1, #BOOT_EMMC_4_4
beq emmc_boot_4_4
cmp r1, #BOOT_NOR
beq nor_boot
cmp r1, #BOOT_SEC_DEV
beq mmcsd_boot
nand_boot:
mov r0, #0x1000
bl copy_uboot_to_ram
b after_copy
onenand_boot:
bl onenand_bl2_copy // goto 0x1010
b after_copy
mmcsd_boot:
#ifdef CONFIG_SMDKC220 // tiny4412.h 中已定義
//#ifdef CONFIG_CLK_BUS_DMC_200_400
ldr r0, =ELFIN_CLOCK_BASE //CLK寄存器首地址,0x10030000
ldr r2, =CLK_DIV_FSYS2_OFFSET //Sets clock divider ratio for FSYS_BLK
ldr r1, [r0, r2]
orr r1, r1, #0xf
// DIVMMC2 Clock Divider Ratio
// DOUTMMC2 = MOUTMMC2/(MMC2_RATIO + 1)設(shè)置分頻系數(shù)為16
//查看電路圖發(fā)現(xiàn)SD卡用的即為第2路MMC總線
str r1, [r0, r2] // 設(shè)置時鐘,此處將SCLK_MMC2的時鐘設(shè)為EPLL/16
//#endif
#else
// 下面幾個宏都未設(shè)置,不會執(zhí)行下面的代碼
#if defined(CONFIG_CLK_1000_400_200) || defined(CONFIG_CLK_1000_200_200) || \
defined(CONFIG_CLK_800_400_200)
ldr r0, =ELFIN_CLOCK_BASE
ldr r2, =CLK_DIV_FSYS2_OFFSET
ldr r1, [r0, r2]
orr r1, r1, #0xf
str r1, [r0, r2]
#endif
#endif
bl movi_uboot_copy // 將uboot copy到SDRAM中,定義在arch/arm/cpu/armv7/exynos/Irom_copy.c
b after_copy
----------------------------------------------------------------------------------------------------------------
12.下面進movi_uboot_copy看一下,定義在定義在arch/arm/cpu/armv7/exynos/Irom_copy.c中:
----------------------------------------------------------------------------------------------------------------
void movi_uboot_copy(void)
{
#ifdef CONFIG_RAM_TEST // 已定義此宏
uboot_mem_test(); // 測試初始化的CLK, SDRAM, UART
#endif
#ifdef CONFIG_CORTEXA5_ENABLE // 未定義
SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, 0x40000000);
#endif
//此函數(shù)即是將uboot完整程序復(fù)制到SDRAM 0x43e0000開始的內(nèi)存中,此函數(shù)實際調(diào)用的是放在IRAM 0x02023030處的一個函數(shù)指針
// 函數(shù)的實現(xiàn)代碼是在IROM里,函數(shù)的功能為將SD卡中的數(shù)據(jù)復(fù)制到SDRAM中,詳見Android_Exynos4412_iROM_Secure_Booting_Guide_Ver.1.00.00 P21
// 三個參數(shù)分別為開始塊,要copy的塊數(shù),copy到內(nèi)存的起始地址,故此處傳入的參數(shù)為17,32,0x43e00000
// 此處的內(nèi)存地址是物理地址,當(dāng)開啟MMU后對應(yīng)的地址的0XC3E00000, 與uboot的鏈接地址一致
SDMMC_ReadBlocks(MOVI_UBOOT_POS, MOVI_UBOOT_BLKCNT, CONFIG_PHY_UBOOT_BASE);
#ifdef CONFIG_SECURE_BOOT // 未定義
if (Check_Signature((SB20_CONTEXT *)SECURE_CONTEXT_BASE,
(unsigned char*)CONFIG_PHY_UBOOT_BASE, PART_SIZE_UBOOT-256,
(unsigned char*)(CONFIG_PHY_UBOOT_BASE+PART_SIZE_UBOOT-256), 256) != 0)
{
while(1);
}
#endif
}
----------------------------------------------------------------------------------------------------------------
13.接下來就是after_copy了,即將進入第二階段:
----------------------------------------------------------------------------------------------------------------
after_copy:
// led (GPM4_0~3) on
ldr r0, =0x110002E0
ldr r1, =0x0c
str r1, [r0, #0x04] //LED1~LED2 on
#ifdef CONFIG_SMDKC220 //tiny4412.h中已定義
// set up C2C
ldr r0, =S5PV310_SYSREG_BASE
ldr r2, =GENERAL_CTRL_C2C_OFFSET
ldr r1, [r0, r2]
ldr r3, =0x4000
orr r1, r1, r3
str r1, [r0, r2] //將GENERAL_CTRL_C2C的bit[14]置1,dram_init_done signal for wake up sequence
#endif
#ifdef CONFIG_ENABLE_MMU //tiny4412中已定義
bl enable_mmu //打開MMU
#endif
// store second boot information in u-boot C level variable
ldr r0, =CONFIG_PHY_UBOOT_BASE //0X43E00000
sub r0, r0, #8
ldr r1, [r0]
ldr r0, _second_boot_info // 在tiny4412.c里定義的全局變量unsigned int second_boot_info = 0xffffffff
str r1, [r0] // 不知為何意,fix me
// Print 'K'
ldr r0, =S5PV310_UART_CONSOLE_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET] // 打印字符'K',與UART初始化時最后顯示的'O'組成UBOOT最開始顯示的"OK"
ldr r0, _board_init_f
// 取函數(shù)board_init_f 的地址,該函數(shù)在\arch\arm\lib\board.c中實現(xiàn),
// 主要實現(xiàn)gd全局結(jié)構(gòu)體的填充及SDRAM的空間分配
mov pc, r0 // 跳轉(zhuǎn)到函數(shù)board_init_f處執(zhí)行,從此處開始在SDRAM中執(zhí)行
// uboot第一階段 結(jié)束,將進入第二階段C代碼的執(zhí)行
_board_init_f:
.word board_init_f
_second_boot_info:
.word second_boot_info
----------------------------------------------------------------------------------------------------------------
上一篇:Tiny4412的MMU解析
下一篇:Tiny4412和PC傳文件(含掛載NFS文件系統(tǒng))方法
推薦閱讀
史海拾趣
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦
- 藍(lán)牙Mesh賦能歐司朗,開啟智能照明無線新時代
- Mobileye聯(lián)手福特,共同更先進的高級駕駛輔助系統(tǒng)
- Imperas Software宣布成立OpenHW Group
- Arduino Portenta系列開發(fā)板,助力低代碼工業(yè)物聯(lián)網(wǎng)開發(fā)
- 優(yōu)派榮獲中國質(zhì)量檢驗協(xié)會雙重榮譽
- stm32f4使用Systick實現(xiàn)延時
- STM32F4 Discovery USB HID 用到的文件圖解
- STM32 延時函數(shù)高級用法分析
- STM32F429 Discovery FMC驅(qū)動原子4.3寸LCD
- STM32精確延時(非中斷,非ST庫函數(shù))