系統移植之uboot源代碼簡要分析(1)

本次Linux系統移植是基於三星公司的S5PV210(又名Hummingbird)處理器的移植;

採用的BootLoader爲三星官方的uboot:android_uboot_smdkv210.tar.bz2
開發平臺爲Ubuntu12.04
交叉編譯工具爲arm-linux-gcc4.4.3

注:s5pv210屬於s5pc11x系列芯片,uboot中使用的是s5pc11x文件

重要文件文件目錄列表:

  1. Makefile
  2. cpu/s5pc11x/
  3. board/samsung/smdkc110/
  4. lib_arm/
  5. include/configs/smdkv210single.h
  6. board/samsung/smdkc110/u-boot.lds mkconfig.h

第一階段:嘗試燒錄原版uboot
配置步驟:
1.在uboot根目錄下執行
make smdkv210single_config
這裏寫圖片描述
2.完成第一步後,執行make all 命令進行全編譯,編譯成功截圖如下:
這裏寫圖片描述
編譯過程中可能會出現各種錯誤,這可能是Makefile中指定交叉編譯鏈出錯了,可以打開頂層Makefile進行修改。對於出現編譯版本錯誤可嘗試通過更改arm-Linux-gcc編譯鏈的版本解決(親測)。
3.燒錄
對於三星廠方uboot,Samsung公司提供了非常方便的燒錄腳本文件,可以直接進行SD卡(其他存儲器件沒試過)燒錄,方法如下:
a)先將SD卡連接到虛擬機(不會的自己到CSDN博客上搜),然後“cd”進入sd_fushing/,可見裏面有個sd_fusing.sh燒錄腳本。不過,爲了防止該腳本不匹配,我們先執行“make clean”清除編譯信息,再執行“make”從新編譯得到腳本文件
b)執行“sudo ./su_fushing /dev/sdb”將文件燒錄到SD卡,
c)然後就可以將SD卡插進開發板嘗試了,不過基本沒戲,畢竟這是別人Samsung對於它自己的公版定製的uboot,和我們大多數開發板並不匹配,我們需要一步步自己更改。

第二階段:uboot源代碼分析
1.Makefile分析請移步U-boot主Makefile分析,這位大哥講得非常詳細具體(膜拜),
2 我們知道,ARM系列芯片上電後是從0x00000000地址的片內IRAM處開始執行代碼,而有鏈接腳本board/samsung/smdkc110/u-boot.lds可知,代碼段第一個鏈接文件是cpu/s5pc11x/start.o,start.o對應的源文件爲cpu/s5pc11x/start.S,於是我們從start.S開始分析。
/*s5pv210處理器啓動過程:
*上電後CPU執行內部0x00000000處的IROM位置代碼(出廠固件),
*–>根據啓動位置,從啓動設備讀取啓動代碼BL1到CPU內部IRAM,(動態內存DRAM 成本低於靜態內存IRAM,故IRAM的size很小,不可能提供足夠的空間給系統運行,系統需要運行在DRAM中)
–>執行BL1,(初始化外部DRAM…)–>將所有代碼搬運到DRAM–>跳轉到外部DRAM運行/
/s5pv210對BL1啓動代碼的格式做了規定,前16個字節有特殊含義(.word表示一個字)/

if defined(CONFIG_EVT1) && !defined(CONFIG_FUSED)

.word 0x2000    /* 第一個字指定BL1的大小,即CPU讀0x2000(8K)大小的代碼到IRAM */
.word 0x0       /* 保留爲0 */
.word 0x0       /* 保留爲0 */
.word 0x0       /* 校驗和 */

endif


.globl _start
_start: breset/* 1.跳轉到reset */et位置處代碼如下,可知其作用爲將處理器設置爲管理模式,並關閉所reset:
/*將處理器設置爲管理模式,關閉中斷
 * set the cpu to SVC32 mode and IRQ & FIQ disable
 */
@;mrsr0,cpsr@ 註釋
@;bicr0,r0,#0x1f
@;orrr0,r0,#0xd3
@;msrcpsr,r0
msrcpsr_c, #0xd3@ I & F disable, Mode: 0x13 - SVC

接下來是設置CPU重要寄存器和存儲時序,完成CPU的設置後,是執行底層硬件的初始化lowlevel_init,

bllowlevel_init/* go setup pll,mux,memory 2. 跳轉到lowlevel_init 進行初始化 */

/*lowlevel_init.S的路徑爲board/samsung/smdkc110/lowlevel_init.S*此文件做了非常重要的底層硬件初始化,包括檢查復位狀態、關閉看門狗、初始化SDRAM、初始化電源管理芯片PMIC(若開發板沒有使用PMIC,可將該代碼段註釋掉)。*/


/* check reset status  */

    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
/* Disable Watchdog *//*關閉看門狗*/

ldr r0, =ELFIN_WATCHDOG_BASE    /* 0xE2700000 */
mov r1, #0
str r1, [r0]

/* SRAM(2MB) init for SMDKC110 初始化 SRAM*/
/* GPJ1 SROM_ADDR_16to21 */
ldr r0, =ELFIN_GPIO_BASE
/* init PMIC chip *//* 電源管理芯片初始化,
 *GEC210開發板沒有使用到PMIC,可將此段代碼註釋掉 
 */
bl PMIC_InitIp

/* init system clock  初始化系統時鐘 */
bl system_clock_init

/* Memory initialize  外部DRAM初始化 */
bl mem_ctrl_asm_init

1:
/* for UART 串口初始化 */
bl uart_asm_init

bl tzpc_init

if defined(CONFIG_ONENAND)

bl onenandcon_init

endif

if defined(CONFIG_NAND)

/* simple init for NAND   NAND初始化 */
bl nand_asm_init

endif

……

pop {pc}
/最後,將文件一開始入棧的ld寄存器保持的地址出棧賦值給程序計數器pc,以返回到start.s中的lowlevel_init,/

至此已完成了底層硬件的初始化,可將代碼拷貝到外部DRAM上運行了。


----------


    回到cpu/s5pc11x/start.S文件,


1.設置堆棧,爲調用C函數做準備

/* To hold max8698 output before releasing power on switch,
 * set PS_HOLD signal to high
 */
ldr r0, =0xE010E81C  /* PS_HOLD_CONTROL register */
ldr r1, =0x00005301  /* PS_HOLD output high */
str r1, [r0]

/* get ready to call C functions */
ldr sp, _TEXT_PHY_BASE  /* setup temp stack pointer */
sub sp, sp, #12
mov fp, #0          /* no previous frame, so fp=0 */

/* 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.
 */
ldr r0, =0xff000fff
bic r1, pc, r0      /* r0 <- current base addr of code  將當前代碼基地址0xff000fff賦值給r0 */
ldr r2, _TEXT_BASE      /* r2 <- original base addr in ram  將RAM中原有的基地址賦值到r2 */
bic r2, r2, r0      /* r0 <- current base addr of code */
cmp     r1, r2                  /* compare r0, r1           r1和r2的值如果相等,
                                表示已經完成過uboot的複製到外部DRAM的操作,若不相等,執行復制    */
beq     after_copy      /* r0 == r1 then skip flash copy   */

/* 選擇系統啓動方式(從哪裏加載) */

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

ldr r0, =INF_REG_BASE
ldr r1, [r0, #INF_REG3_OFFSET]
cmp r1, #BOOT_NAND      /* 0x0 => boot device is nand *//*從NAND啓動 */
beq nand_boot
cmp r1, #BOOT_ONENAND   /* 0x1 => boot device is onenand *//*從ONENAND啓動 */
beq onenand_boot
cmp     r1, #BOOT_MMCSD /*從MMCSD啓動 */
beq     mmcsd_boot
cmp     r1, #BOOT_NOR   /*從NOR啓動 */
beq     nor_boot
cmp     r1, #BOOT_SEC_DEV   /*從SEC_DEV啓動 */
beq     mmcsd_boot


----------
我們以從nand_flash啓動爲例進行分析:

nand_boot:
mov r0, #0x1000
bl copy_from_nand /調用copy_flam_nand函數將uboot/
b after_copy



----------
根據跳轉,我們查看copy_from_nand

.globl copy_from_n
copy_from_nand:
push{lr} /* save return address */
mov r9, r0

mov r9, #0x100 /* Compare about 8KB */

bl copy_uboot_to_ram /再調用copy_uboot_to_ram函數將uboot拷貝到RAM中,(copy_uboot_to_ram代碼不再累贅)/
tst r0, #0x0
bne copy_failed



----------


成功執行copy_from_nand後,返回“nand_boot:”代碼段繼續執行“b after_copy”以跳轉到“after_copy”代碼段,完成:啓動MMU、設置堆棧、清除bss段

after_copy:

if defined(CONFIG_ENABLE_MMU)

/啓動MMU/
enable_mmu:
/* enable domain access */
ldr r5, =0x0000ffff
mcr p15, 0, r5, c3, c0, 0 @load domain access register

/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0
    /* Enable the MMU */

mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0
nop
nop
nop
nop

endif

/設置堆棧/
skip_hw_init:
/* Set up the stack */
stack_setup:
……
/清除bss段/
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */



----------
    之後,使用絕對跳轉指令ldr使得程序跳轉到_start_armboot(即BL2)處執行。
ldr pc, _start_armboot

“`
至此BL1啓動完成,內部SRAM工作完成,爲程序在外部DRAM執行設置好了環境


uboot的BL1啓動階段總結

  1. 關中斷,設置爲管理模式(SVC);
  2. 調用lowlevel_init初始化底層硬件(看門狗、系統時鐘、串口、內存、nand等)
  3. 將uboot搬運到外部DRAM
  4. 開啓MMU(至此,內存物理地址不能再訪問,只能訪問虛擬地址)
  5. 初始化堆棧,爲調用C函數做準備
  6. 清空bss段
  7. 使用“ldr pc, _start_armboot”跳轉到外部DRAM中運行BL2階段代碼。

`

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章