Sam Fei (email: [email protected])
(1) 事情來由 幾個月前從朋友那裡拿到了一塊參考Micetek EV44b0-II開發板設計的板子,對其bootloader MBL感覺很不錯. 朋友說可能是移植u-boot的.但Micetek並沒有提供MBL的源代碼, 因此當時沒有仔細去研究. 最近公司准備想做基於S3C44B0X CPU的產品,因此購買了杭州立宇泰公司(www.hzlitai.com.cn)的armsys-c及armsys-b開發板和.armsys提供的bootloader是其公司自己開發的bootloader,覺得其USB這一塊做的還可以,但利用USB下載調試uclinux是非常麻煩的,操作很不爽,其bootloader也不提供網絡下載調試.因此自己計劃移植u-boot.
(2) 開始 由於沒有接觸過u-boot,因此第一步要做的就是google一些資料. u-boot官方網站:http://sourceforge.net/projects/u-boot(比較慢) http://u-boot.sourceforge.net/這個快一些.
DENX U-Boot及Linux使用手冊: http://coosign.blogchina.com/coosign/1318487.html, 這是一遍翻譯的文檔.主要介紹了u-boot編譯及使用的命令.但沒有涉及新板子的移植流程.
根據上面手冊中的說明,下載了最新的u-boot代碼,命令: #cvs -d:pserver:[email protected]:/cvsroot/u-boot login #cvs -z6 -d:pserver:[email protected]:/cvsroot/u-boot co -P u-boot
到board目錄查了一下: #cd u-boot #cd board #find . -exec grep -l 44B0 {} \; 結果是: ./dave/B2/B2.c B2網站是: http://www.dave-tech.it,初初看了B2開發板的介紹,但不詳細.包括使用的網絡芯片等都沒有介紹.
google "u-boot 移植"後查到一篇文章: "收集了一些關於U-BOOT的文章" http://www.bloghome.cn/index.php?op=ViewArticle&articleId=2111&blogId=390
裡面搜集了不少關於u-boot移植的問題. 裡面介紹了"U-Boot 在44B0X 開發板上的移植以及代碼分析"的內容,仔細看了看.發現其移植的版本比較低,但對了解u-boot結構是滿不錯的,因為這個版本不支持44B0X,因此完全是支持新CPU的移植.了解到make XX_config是在Makefile中定義的. 另外"MPC8xx的U-Boot移植體會(ZT) "這一篇對u-boot介紹滿詳細的.但對移植工作只做了理論性和經驗性介紹,沒有具體的操作步驟.
"基於Atmel at91rm9200的armlinux的bootloader啟動代碼分析 " http://www.linuxfans.org/nuke/modules.php?name=News&file=print&sid=2765 裡面介紹了u-boot移植到at91rm9200上的情況,可以參考一下.
另外就是仔細閱讀u-boot下的README文件.
(3) 編譯一把 看了相關的資料,心動不如行動.先編譯一把看看情況.既然只有B2開發板是S3C44B0X CPU的,因此先編譯一下B2開發板看看. 具體: #cd u-boot #make B2_config #make 結果順利,成功編譯.
(4) 開始動手移植 我以B2板子的程序做為模板來做. #cd board #cp -r dave wx (自己取個公司名wx) #cd wx #mv B2 wx20 (自己取個板子名wx20) #cd wx20 # mv B2.c wx20.c 修改Makefile及wx20.c, 主要是B2改成wx20.
增加配置文件: #cd include/configs #cp B2.h wx20.h 修改Makefile配置文件,增加wx20_config. 1432 wx20_config : unconfig 1433 @./mkconfig $(@:_config=) arm s3c44b0 wx20 wx [注:前面的數字是文件行號,以下一樣]. 將board/wx目錄下和wx20.h文件中的B2改成wx20或WX20.
這裡其實是最重要的步驟,就是根據硬件的情況來修改相關的參數.由於對硬件板子的情況不是太了解,因此此時最需要的就是耐心地看看硬件資料.主要修改的地方有: include/configs/wx20.h ---- 配置文件,大部分參數是這裡配置的. board/wx/wx20/lowlevel_init.S -- 內存參數配置 cpu/s3c44b0/serial.c -- 串口配置 cpu/s3c44b0/start.S -- 程序入口
如果此時配置全部正確了,那麼我們就簡單的很了.(如果你用我的patch的話,就是如此了!)那麼我也就不會仔細再去研究u-boot其他部分了. 困難就是你學習的最好機會!
(5) 開始編譯 經過簡單的參數修改,編譯成功.然後下載u-boot.bin(二進制格式). 此時你可以用nm看一下u-boot(elf格式)的內容,會有所收獲的.
然後用armsys的bootloader將u-boot.bin調入到內存0xc100000運行.結果可想而知,串口沒有任何顯示,而且死機.bootloader也必須斷電重起.
(6) u-boot流程 原因是比較明顯的,就是參數和硬件沒有符合.因此接下來做的事情就是仔細閱讀S3C44B0 CPU的硬件資料,包括內存配置,串口配置這些.我覺得要讓串口出信息,最主要的就是CPU的初始化,內存配置和串口配置.另外就是了解u-boot程序運行流程,這個對了解需要設置的參數是非常有幫助的.我這裡大致說一下u-boot運行流程.
入口: cpu/s3c44b0/start.S 主要是CPU初始化( cpu_init_crit ), 調內存配置函數( lowlevel_init ), 然後判斷u-boot是否從flash運行,如果是就把u-boot代碼拷貝到TEXT_BASE定義的地方.然後轉到start_armboot.
start_armboot: lib_arm/board.c 進行各種初始化設置,主要有: cpu_init CPU相關的設置, 具體在./cpu/s3c44b0/cpu.c中. board_init 板子相關的設置, 具體在board/wx/wx20/wx20.c 中 interrupt_init中斷設置,我們沒有用,具體在./cpu/s3c44b0/interrupts.c中 env_init 初始化環境變量, 具體要看用什麼介質來存儲環境變量,如果用flash來存貯, 程序在common/env_flash.c中. init_baudrate 設置baud參數 serial_init 串口初始化, 具體在cpu/s3c44b0/serial.c. console_init_f 控制台設置, 具體在./common/console.c
display_banner 顯示標題. dram_init 可用內存配置, 具體在./board/wx/wx20/wx20.c. flash_init flash初始化,具體./drivers/cfi_flash.c.
接下來就是環境變量初始化, 網絡初始化,最後到main_loop,可以運行各種命令. (7) 主要參數修改 經過一段時間調試,終於串口出東西了,這段時間犯了一個小錯誤,走了一段冤枉路.其實配置參數可能早已正確,但串口老是亂碼,原因是自己的u-boot.bin傳下來時目錄搞錯了,結果老是運行錯誤的u-boot.bin.這段時間裡主要改的參數有:
include/configs/wx20.h: #define CONFIG_S3C44B0_CLOCK_SPEED 64 CPU主頻,armsys板的是64M #define PHYS_SDRAM_1 0x0c000000 /* SDRAM Bank #1 */ B2板子裡的定義是錯誤的.還有RAM大小,flash大小需要修改,跟B2板不同.
#define CONFIG_DRIVER_RTL8019 #define RTL8019_BASE 0x08000000 配置rtl8019AS網絡芯片.
#define CFG_LOAD_ADDR 0x0c008000 /* default load address */ uclinux運行入口地址
lowlevel_init.S: MEMORY_CONFIG: .long 0x11010102 .long 0x600 .long 0x7ffc .long 0x7ffc .long 0x7ffc .long 0x7ffc .long 0x2610 .long 0x18000 .long 0x18000 .long 0x960459 .long 0x10 .long 0x20 .long 0x20 由於對armsys硬件不是太了解,沒有辦法,只得看armsys bootloader程序,但每個版本又有差別.因此是用AXD調試看bootlaoder啟動後0x1c80000中的值定的.
cpu/s3c44b0/serial.c: #elif CONFIG_S3C44B0_CLOCK_SPEED==64 divisor = 34; 串口設置,這個也是根據bootloader裡的公式計算出來的.這裡只定義了115200得值,其他沒有去設置.
cpu/s3c44b0/start.S: ldr r1, =PLLCON
#if CONFIG_S3C44B0_CLOCK_SPEED==66 ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */ #elif CONFIG_S3C44B0_CLOCK_SPEED==75 ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */ #elif CONFIG_S3C44B0_CLOCK_SPEED==64 ldr r0, =((M_DIV saveenv Saving Environment to Flash... Un-Protected 1 sectors Erasing Flash... done Erased 1 sectors Writing to Flash... done Protected 1 sectors ð printenv
但重新啟動機器後,參數沒有起作用,還是缺省的.仔細看了環境變量的程序,發現是由於ENV_IS_EMBEDDED定義造成的,而此變量定義是在./tools/envcrc.c中: # if (CFG_ENV_ADDR >= CFG_MONITOR_BASE) && \ ((CFG_ENV_ADDR + CFG_ENV_SIZE) 0C117DA0 BSS: -> 0C11C0F0 RAM Configuration: Bank #0: 0c000000 8 MB env_init flash_addr=20000 flash_addr=20000 env_ptr=20000 env_ptr->data=bootargs=setenv bootargs root=/dev/ram ip=192.168.1.100:::::eth0:off ether=25,0,0,0,eth0 ethaddr=00:50:c2:1e:af:fb envptr->crc=1470de2 1470de2 buffer->crc=1470de2 [flash_get_size, 224] Entering ... [flash_get_size, 232] value=bf [flash_get_size, 255] value=234b Flash: 2 MB env_ptr=20000 gd->env_addr=20004 gd->env_valid=1 env_relocate[211] offset = 0x0 env_relocate[229] malloced ENV at 00000000 In: Out: Err:
死機!!!
然後改回arm-elf編譯: U-Boot 1.1.3 (Jul 3 2005 - 07:04:48)
U-Boot code: 0C100000 -> 0C119B98 BSS: -> 0C11DCD8 RAM Configuration: Bank #0: 0c000000 8 MB env_init flash_addr=20000 flash_addr=20000 env_ptr=20000 env_ptr->data=bootargs=setenv bootargs root=/dev/ram ip=192.168.1.100:::::eth0:off ether=25,0,0,0,eth0 ethaddr=00:50:c2:1e:af:fb envptr->crc=1470de2 1470de2 buffer->crc=1470de2 [flash_get_size, 224] Entering ... [flash_get_size, 232] value=bf [flash_get_size, 255] value=234b Flash: 2 MB env_ptr=20000 gd->env_addr=20004 gd->env_valid=1 env_relocate[211] offset = 0x0 env_relocate[229] malloced ENV at 0c0dfc08 In: serial Out: serial Err: serial rtl8019 MAC: 2a:2a:2a:2a:2a:2a Hit any key to stop autoboot: 0 =>
正常!因此最好是用arm-elf編譯. 我在看網上查資料時記得有人說過"用arm-linux編譯時,malloc返回0,而改成arm-elf編譯時就好了".有個印象,具體帖子不記得在哪裡了.所以後來我就一直使用arm-elf編譯,沒有再去試arm-linux編譯.
(12) 網卡調試 剩下來的事情就是調網絡了.根據上面配置rtl8019as後,網絡仍然不同,然後參考uclinux驅動中的寄存器定義修改,網絡就可以了.具體修改是: drivers/rtl8019.h 36 #define ETH_ADDR_SFT (8) 37 #define EI_SHIFT(x) ((x) setenv bootcmd "tftpboot; go 0xc008000" ==》設置錯誤 ## Starting application at 0x0C008000 ... => setenv bootcmd "tftpboot\; go 0xc008000" ==》需要有個\ => saveenv
重新開機運行u-boot: Hit any key to stop autoboot: 0 Unknown command '"tftpboot' - try 'help' ## Starting application at 0x0C008000 ... 結果還是不能自動下載uclinux和運行.經過調試才發現在設置bootcmd時多加了引號造成的!正確的設法是: => setenv bootcmd tftpboot \; go 0xc008000 ==》正確的設置
此時可以成功自動下載uclinux和運行了.
(15) flash運行 刻錄到flash後,運行uclinux出現問題,運行到:uclinux 開中斷後就死機,提示: Linux version 2.4.24-uc0 (root@samfei) (gcc version 2.95.3 20010315 (release)(ColdFire patches - 20010318 from http://fiddes.net/coldfire/)(uClinux XIP and shared lib patches from http://www.snapgear.com/)) #46 Áù 7ÔÂ 2 15:52:55 CST 2005 Processor: Samsung S3C44B0X revision 0 Architecture: S3C44B0X On node 0 totalpages: 2048 zone(0): 0 pages. zone(1): 2048 pages. zone(2): 0 pages. Kernel command line: root=/dev/rom0 init=/linuxrc
前面一直用armsys的bootloader,將u-boot下載到0xc300000運行,然後再load linux到0xc0080000運行,正常.而將u-boot刻錄到flash後運行不正常,經過調試uclinux,到init/main.c中sti()函數後出現死機.因此懷疑中斷向量設置問題.
將cpu/s3c44b0/start.S中代碼修改成; 40 .globl _start 41 _start: b reset 42 /* 43 add pc, pc, #0x0c000000 44 add pc, pc, #0x0c000000 45 add pc, pc, #0x0c000000 46 add pc, pc, #0x0c000000 47 add pc, pc, #0x0c000000 48 add pc, pc, #0x0c000000 49 add pc, pc, #0x0c000000 50 */ 51 LDR PC, Undefined_Addr 52 LDR PC, SWI_Addr 53 LDR PC, Prefetch_Addr 54 LDR PC, Abort_Addr 55 LDR PC,RESERVE_Addr 56 LDR PC, IRQ_Addr 57 /* subs pc,lr,#4*/ 58 LDR PC, IRQ_Addr 59 /* subs pc,lr,#4*/
114 Undefined_Addr: 115 .word 0x0c000004 116 SWI_Addr: 117 .word 0x0c000008 118 Prefetch_Addr: 119 .word 0x0c00000C 120 Abort_Addr: 121 .word 0x0c000010 122 RESERVE_Addr: 123 .word 0x0c000014 124 IRQ_Addr: 125 .word 0x0c000018 126 FIQ_Addr: 127 .word 0x0c00001C 128 129 /* 130 * the actual reset code 131 */ 132 133 reset: 後編譯,刻錄,然後運行.正常了!!!
(16) 補丁制作和測試 [root@samfei u-boot]# make distclean [root@samfei 44b0]# mv u-boot u-boot.wx [root@samfei 44b0]# cvs -d:pserver:[email protected]:/cvsroot/u-boot login Logging in to server:[email protected]:2401/cvsroot/u-boot CVS password: [root@samfei 44b0]# cvs -z3 -d:pserver:[email protected]:/cvsroot/u-boot co -P u-boot cvs checkout: Updating u-boot U u-boot/CHANGELOG U u-boot/COPYING U u-boot/CREDITS U u-boot/MAINTAINERS 。。。。。。
[root@samfei 44b0]# diff -Naur u-boot u-boot.wx > uboot-wx-20050703.patch [root@samfei 44b0]# vi uboot-wx-20050703.patch 去掉沒有用的文件.做補丁的好處就是自己可以很清楚的知道哪些文件修改了!做完了,別忘了測試一下.
[root@samfei 44b0]# cd u-boot [root@samfei u-boot]# patch -p1 < ../uboot-wx-20050703.patch [root@samfei u-boot]# make wx20_config [root@samfei u-boot]# make
(17) 後記 寫這份材料化了不少時間.由於在調試的時候記錄了大部分的調試信息,因此不用費腦筋去回憶.寫完了這個經歷,非常開心..一則自己可以溫故而知新,二則就是與人共享啊.在開源的世界裡,與人共享應該是件很快樂的一件事情. 目前micetek的板子壞了,手上沒有,等我拿到板子再將u-boot移植上去.那時就不用那麼麻煩了.呵呵.
摘自:linuxforum.net