前期準備:
1.uboot下載地址 ftp://ftp.denx.de/pub/u-boot/
2.參照物開發板的選擇
我們開發板使用的CPU是S5PV210,所以要找uboot中針對S5PV210或者S5PC110進行移植的作爲參考。根據規律,我們應該參考include/configs/s5p_goni.h,對應的board在uboot/board/samsung/goni這個目錄。
3.刪除無關文件和文件夾,其實不刪除也可以,但是刪除更好。
4.建立SI工程並預解析
(1)參照物開發板爲:55p_goni make s5p_goni_config
(2)配置對應的cpu、board文件夾分別爲:
cpu: u-boot-2013.10\arch\arm\cpu\armv7
board: u-boot-2013.10\board\samsung\goni
開始移植
1.添加交叉編譯工具鏈
在主Makefile 中CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
2.配置,編譯,測試
(1)編譯過程:
make distclean
make s5p_goni_config
make
(2)結果:得到u-boot.bin即可
3.推薦linux下腳本燒入
移植原來的版本的uboot中的sd_fusing文件夾到官方uboot版本中,使用這個文件夾中的sd_fusing.sh腳本來進行燒錄
4.燒入後,串口現象;
(1)串口接串口2,串口有輸出。但是這個串口輸出不是uboot輸出的,而是內部iROM中的BL0運行時輸出的。
(2)輸出錯誤信息分析:
第一個SD checksum Error:是第一順序啓動設備SD0(iNand)啓動時校驗和失敗打印 出來的;
第二個SD checksum Error:是第二順序啓動設備SD2(外部SD卡)啓動時校驗和失敗 打印出來的;
剩下的是串口啓動和usb啓動的東西,可以不管。
總結:從兩個SD checksum Error,可以看出:外部SD卡校驗和失敗了。
分析:SD卡燒錄出錯了,導致SD卡校驗和會失敗。發現是mkbl1程序和start.S中前16個字節校驗和的處理上面不匹配造成的,解決方法是在start.S最前面加上16個字節的佔位。
5.上述問題的解決方法:
參考之前的start.S發現有16字節佔位。直接複製粘貼到本版本的start.S的相應位置。
\u-boot-2013.10\arch\arm\cpu\armv7\start.S
重新編譯燒錄運行,發現結果只顯示一個SD checksum Error。這一個就是內部SD0通道的inand啓動校驗和失敗打印出來的。剩下的沒有了說明外部SD卡校驗和成功了,只是SD卡上的uboot是錯誤的,沒有串口輸出內容,所以沒有輸出了。
3.繼續分析start.S
(1)#define CONFIG_SYS_TEXT_BASE 0x34800000 可以看出我們的uboot的連接地址是在0x34800000位置
(2)cpu_init_cp15這個函數功能是設置MMU、cache等。這個版本的uboot中未使用虛擬地址,因此MMU在這裏直接關掉。
(3)cpu_init_crit,這個函數裏只有一句跳轉指令,短跳轉到lowlevel_init函數。
Lowleve_init 分析:
lowlevel_init函數在board/samsung/goni目錄下,主要作用是時鐘設置、串口設置、復位狀態判斷···這個函數是S5PC100和S5PC110兩個CPU共用的。
經過瀏覽,發現lowlevel_init函數中做的有意義的事情有:關看門狗、調用uart_asm_init來初始化串口、並沒有做時鐘初始化(下面有時鐘初始化的函數,但是實際沒調用。如果uboot中沒有初始化時鐘,那麼時鐘就是iROM中初始化的那種配置)
7.添加開發板制鎖和串口打印字符"O"
(1)我們爲了調試uboot的第一階段,就要看到現象。爲了看到現象,我們向lowlevel_init函數中添加2個代碼,一個是開發板制鎖,在watchdog後
// 我們添加的開發板供電制鎖的代碼
ldr r0, =0xE010E81C
ldr r1, =0x301
str r1, [r0]
一個是串口打印"O"在串口初始化最後
// 串口2輸出字符'O'
ldr r1, =0x4f4f4f4f
ldr r2, =0xE2900820
str r1, [r2] @'O'
(2)這兩段代碼可以直接從ARM裸機全集課程中的代碼中來。其實也可以從三星移植版本的uboot中來,但是因爲三星移植版本中用到了很多寄存器定義,涉及到頭文件的, 所以移植過來不方便。
(3)實踐添加。
實踐結果及分析
(1)實驗結果是:沒看到開發板制鎖,串口也沒有輸出任何東西。實驗失敗。
(2)結論:因爲開發板制鎖沒有成功,所以我們判定,在開發板制鎖代碼運行之前uboot 就已經掛掉了。下面就是去跟蹤代碼運行,然後判定問題點再去解決
8.添加LED點亮代碼跟蹤程序運行
(1)在基礎代碼階段,串口還沒有運行,串口調試工具還無法使用時,使用LED點亮的方式來調試程序就是一個有力的手段。
(2)有些情況下可以用Jlink等調試工具來調試這種基礎代碼。
(3)從程序的基本運行路徑端出發,隔一段給他添加一個LED點亮代碼,然後運行時根據現象來觀察,判定哪裏執行了哪裏沒執行。從而去定位問題。
(4)從以前的裸機代碼中組織出一個標準的LED點亮然後延時一段的一個標準代碼段:
ldr r0, =0x11111111
ldr r1, =0xE0200240
str r0, [r1]
ldr r0, =((1<<3) | (0<<4) | (1<<5)) // 1是滅,0是亮
ldr r1, =0xE0200244
str r0, [r1]
ldr r2, =9000000 //延時函數
ldr r3, =0x0
delay_loop:
sub r2, r2, #1
cmp r2, r3
bne delay_loop
(5)之前做實驗時發現一個現象:我們的uboot運行時按住電源開關時所有4顆LED都是亮的。所以我們做實驗時給LED點亮是看不到現象的,所以我們的代碼關鍵是要熄滅某些LED來判斷。
(6)我們將熄滅LED的函數在start.S中隔一段的關鍵部位放上1個,然後運行時通過觀察LED的點亮熄滅狀態,就知道程序運行到哪裏了。
(7)經過判斷我們發現:start.S中工作一切正常,但是函數一旦放到lowlevel_init.S中就完全不工作了。通過分析得出結論:b lowlevel_init這句代碼出了問題。
9.解決問題
(1)問題分析:跳轉代碼出了問題。分析問題出在代碼的連接上。
(2)三星S5PV210要求BL1大小爲8KB,因此uboot第一階段代碼必須在整個uboot鏡像的前8KB內,否則跳轉不到。
(3)對比三星移植版本的uboot的u-boot.lds和官方版本uboot的連接腳本u-boot.lds(注意這兩個版本的uboot的連接腳本的位置是不同的),就發現lowlevel_init.S的代碼段沒有被放在前面。
(4)在u-boot.lds中start.o後面添加board/samsung/goni/lowlevel_init.o (.text*),這個就保證了lowlevel_init函數被連接到前面8kb中去。
(5)報錯,lowlevel_init重複定義了。
修改board/samsung/goni/Makefile解決編譯問題
(1)問題分析:爲什麼會重複定義。因爲lowlevel_init這個函數被連接時連接了2次。一次是board/samsung/goni這個目錄下生成libgoni.o時連接了1次,第2次是連接腳本最終在連接生成u-boot時又連接了一次,所以重複定義了。
(2)這個錯誤如何解決?思路是在libgoni.o中不要讓他連接進lowlevel_init,讓他只在最終連接u-boot時用1次,就可以避免重複定義。
(3)參考當前版本的uboot的start.S文件的處理技巧,解決了這個問題。
實踐驗證。
結果是開發板制鎖和串口輸出'O'都成功了
DDR初始化
分析下一步移植路線
(1)cpu_init_crit函數成功初始化串口、時鐘後,轉入_main函數,函數在arch/arm/lib/crt0.S文件中。
(2)在crt0.S中首先設置棧,將sp指向DDR中的棧地址;然後調用board_init_f函數進行板級初始化。函數在arch/arm/lib/board.c中。
(3)在這個版本的uboot中,把以前uboot的第二階段start_armboot函數分成了2部分:board_init_f和board_init_r。所以在這裏就和以前版本的uboot接軌上了,推測board_init_f中肯定是做了板級初始化,board_init_r中進入了uboot的命令行。
(4)分析到這裏,在uboot2013.10版本中思路已經很清晰了:uboot的第二階段就在crt0.
(5)分析到這裏,下一步工作方向就確定了。我們要先在cpu_init_crit函數中添加DDR初始化,然後在start.S中bl _main之前添加uboot的重定位,然後將bl _main改成ldr pc, __main(__main: .word _main)長跳轉。然後在crt0.S中board_init_f後刪除那些重定位代碼,至此uboot的第二階段就應該能啓動起來了。後續的移植就是第二階段了。
該版本沒有DDR初始化代碼需要從三星官方移植
動手移植
(1)添加cpu_init.S文件到uboot2013.10中。注意,這裏的代碼必須保證在前8kb內,所以必須和lowlevel_init.S文件一樣的鏈接處理。主要是在board/samsung/goni/Makefile中和arch/arm/cpu/u-boot.lds文件中做修改添加。
(2)Lds:
Makefile中:
(2)添加頭文件s5pc110.h到include目錄下。
(3)對cpu_init.S文件代碼進行修整,把一些無用的代碼去掉,把一些相關的條件編譯人工處理一下。
(4)在SourceInsigt工程中添加入這兩個文件。然後重新解析一遍。然後對新添加的代碼進行分析修整,把裏面一些明顯的宏定義缺失給補上。
(5)DDR配置參數,從三星版本的smdkv210single.h中複製到s5p_goni.h中。
在lowleve_init.S中,調用mem_ctrl_asm_init 然後在後面打印“K”
(6)s5pc110.h中進行修整。
(7)結果:看到了"OK"標誌,說明DDR添加實驗成功
DDR初始化:1複製三星的cpu_init.S到和lowleve_init.S在同一文件下,並進行修改刪除,再makefile中作爲依賴添加上;再在鏈接腳本u-boot.lds中鏈接到前面。2將所需要的配置宏定義從本來的.h文件中複製到本版本的配置頭文件.h中。3將cpu_init.S所需要的板級宏定義的頭文件s5pc110.h複製到相對位置一樣的文件夾中,並進行修改刪除。4在lowleve_init.S中,調用mem_ctrl_asm_init 然後在後面打印“K”
重定位
在bl cpu_init_crit(b lowlevel_init @ go setup pll,mux,memory裏面只有這一句)也可以說在b lowlevle後開始重定位相關代碼。
/重定位開始
/* get ready to call C functions設置棧 */
ldr sp, _TEXT_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 */
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 */
若相等則不需要重定位直接跳到after_copy
/* If BL1 was copied from SD/MMC CH2 *判斷通道2 sd卡啓動*/
ldr r0, =0xD0037488
ldr r1, [r0]
ldr r2, =0xEB200000
cmp r1, r2
beq mmcsd_boot
mmcsd_boot:
bl movi_bl2_copy /*跳轉重定位函數copy,在movi.c
after_copy:
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */
/*請bss段,注意鏈接地址,需要移植修改*/
/*
* These are defined in the board-specific linker script.
*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l
//bl _main 第一階段和第二階段的過度,分析得_mian函數爲uboot第二階段,做長跳轉
ldr pc, __main
__main:
.word _main
需要移植movi_bl2_cop函數,
將 所在的文件movi.c複製到\u-boot-2013.10\board\samsung\goni,和lowleve.S同樣的操作在Makefike和u-boot.lds中,刪除不需要的函數,再確保宏定義可用,在s5p_goni配置頭文件中添加修改。
複製所需要的頭文件到相應位置movi.h
後續:將_main(在crt0.S)中的有關重定位的代碼刪掉
編譯中出現問題解決
(1)movi.h中宏定義出錯,最後在s5p_goni.h中添加了CONFIG_EVT1這個宏解決了
(2)連接錯誤:u-boot contains relocations other thanR_ARM_RELATIVE
在uboot下用grep "R_ARM_RELATIVE" -nR *搜索,發現Makefile中有一個檢查重定位的規則,屏蔽掉這個規則後編譯連接成功。
結果驗證及下階段展望
(1)看到了uboot啓動打印出來的一系列信息,但是uboot沒有進入命令行。
(2)這說明uboot中的DDR初始化和重定位功能都已經完美實現,後面就是第二階段的繼續移植了。