2010年3月3日 星期三

學習u-boot

http://blog.chinaunix.net/u1/34474/showart.php?id=1877493
http://blog.chinaunix.net/u2/75270/showart_1779196.html
http://blog.chinaunix.net/u3/98913/article.html
這兩個連結算是我最近search到最棒的u-boot介紹:
以下內容便是轉載於第二個連結,由於這資料非常寶貴,因此我當然要post一份到自己的blog;以免萬一原文超連結遺失。
u-boot2008.10非nand_leagcy移植mini2440,支持yaffs,附源碼
這篇文章寫於2008.12.28日,主要記錄了我移植u-boot-2008.10的過程,並附上了移植好的patch檔。移植好的u-boot-2008.10適用友善公司的mini2440和陽初公司的yc2410。其他的開發板,可能要根據相應的電路配置做稍許修改。我的移植是使用非nand-leagcy方法的,移植好的u-boot-2008.10功能除了基本功能外,加上了yaffs1映射的寫入功能,加入了從nand flash啟動的功能,改善了一些操作感受,往nand寫入資料時,可以顯示進度。在使用上要注意的是使用nand wirte.yaffs 命令寫入yaffs1映射時,文件長度參數一定要與yaffs1映射的大小完全一致,否則有可能產生假壞塊。我的開發環境是vmware,kubuntu8.04。交叉編譯是用crosstool0.43編譯生成的arm-linux-gcc 4.1.0,libc 2.3.2。
(本人也成功移植了linux2.6.27.9到mini2440開發板上,有需要源碼的,可以和我聯繫。EMAIL:nanjinrat@sohu.com,映射文件在此下載http://blog.chinaunix.net/u2/75270/showart.php?id=1796658 映射的使用方法見我的另一篇文章。http://blog.chinaunix.net/u2/75270/showart.php?id=1836713)一直想自已移植一套u-boot,但因為工作忙,一直都沒有做,最近時間比較多,買了一套友善之臂的mini2440開發板,此板電路與該公司之前的QQ2440基本一至。而該開發板自帶的u-boot的移植的還不很完善,於是下決心自已移植u-boot。要移植就用最新版的u-boot移植,於是決定在u-boot.2008.10版上進行移植,此版是2008年10月的新版,於之前的版本有較大改動,所以版本號也沒有延續以前的編號方式,而改為2008.10。我的移植目的,是要能同時持S3C2440,S3C2410(手中還有一塊陽初公司出的S3C2410開發板),從nand flash啟動u-boot,因為目前大多數應用都是只有nand flash的,所以沒打算從nor flash啟動。支援tftp的使用,也就說要移植網卡的驅動,mini2440和陽初的s3c2410自帶的linux都是使用yaffs檔系統作為根檔系統的,因此,u-boot還要能支援yaffs映射的燒寫。在此我將移植過程記錄下來,以方便大家在移植此版u-boot時參考。為了方便整個移植過程中的調試,我把移植過程分為0~6共7個階段。每個階段完成時,u-boot都是可以正常運行的,因此,你可以根據自已的要求,決定移植工作做到哪一階段。為了同時支持S3C2440和S3C2410,我在移植時,同時加入兩種代碼,使用config_s3c2440,config_s3c2410這樣的巨集定義來決定編譯哪種代碼。如果你不需要同時支援兩個CPU,你可以只加入一種代碼。所有代碼不在此列出,大家可以看我上傳的移植好的u-boot。我在下面給出針對S3C2440移植的詳細說明,S3C2410的移植比較簡單,參考2440的移植即可,不另說明了。不同階段的詳細代碼可以閱讀patch檔。
第0階段:本階段任務,是在u-boot系統中,建立起自已的開發板體系。我先建立mini2440板的體系。方法如下。hugerat是我的網名,你可以根據需要更改。1 打開u-boot主目錄下的makefile,找到smdk2410_config,在其下,仿照它的格式加入如下語句rat2440_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t rat2440 hugerat s3c24x0
各項的意思如下:arm: CPU的架構(ARCH)arm920t: CPU的類型(CPU),其對應於cpu/arm920t子目錄。rat2440: 開發板的型號(BOARD),對應於board/hugerat/rat2440目錄。hugerat: 開發者/或經銷商(vender)。s3c24x0: 片上系統(SOC)。
此步是為了加入自已的開發板,非必須也可以在現有的開發板基礎上修改。
2修改CROSS_COMPILE為自已的arm gcc編譯器,我使用的是系統默認的arm-linux-gcc,故不必再修改相應的CROSS_COMPILE項。
3 在/board子目錄中建立自己的開發板rat2440目錄由於我在上一步板子的開發者/或經銷商(vender)中填了 hugerat ,所以開發板rat2440目錄一定要建在/board子目錄中的hugerat
目錄下 ,否則編譯會出錯。然後,將smdk2410目錄下的檔考入此目錄中。並將其中的smdk2410.c改名為rat2440.c 還要記得修改自己的開發板rat2440目錄下的Makefile檔,不然編譯時會出錯:
COBJS := rat2440.o flash.o
4 在include/configs/中建立配置頭檔將smdk2410的相應頭檔複製一份在相同目錄下。並改名為rat2440.h
5 回到u-boot主目錄,make rat2440_config,再make,編譯生成u-boot.bin成功。
建立S3C410板的方法同上,僅將2440改為2410即可。不重複了。
第0階段完成。
第1階段本版u-boot依然沒有提供對S3C2440的支援,因此本階段任務是加入S3C2440相關的代碼,使得u-boot可以在s3c2440上正常工作。但沒有增加任何附加功能。在下列文件中加入標注為/*by hugerat,phase 1---*/的代碼。其中,被注釋掉的代碼為原代碼。/cpu/arm920t/start.s (加入S3C2440的時鐘相關的寄存器定義,加入時鐘初始化代碼,以使S3C2440工作在405MHz)board/hugerat/rat2440/lowlevel_init.s(加入S3C2440記憶體控制寄存器的定義)board/hugerat/rat2440/rat2440.c (修改GPIO,PLL的設置,應注意GPBCON的設置,不要讓蜂鳴器響)include/configs/rat2440.h(設定環境變數)以下檔主要加入CONFIG_S3C2440巨集定義以使得編譯一些S3C2410的代碼,和加入led燈的控制。
以指示u-boot程式進程。/inlcude/s3c24x0.hcpu/arm920t/s3c24x0/interrupts.c(這裏還要加入CONFIG_rat2440和CONFIG_rat2410)/cpu/arm920t/s3c24x0/serial.ccpu/arm920t/s3c24x0/speed.ccpu/arm920t/s3c24x0/usb_ohci.c/cpu/arm920t/s3c24x0/usb.c cpu/arm920t/s3c24x0/i2c.cdrivers/usb/usb_ohci.cdrivers/rtc/s3c24x0_rtc.c/lib_arm/board.c
編譯成功。將u-boot.bin燒入nor-flash即可運行。但是為方便使用,同時,也是方便u-boot的調試因此,我要將此u-boot代碼再做一修改,使其可以在記憶體中運行。這樣,可以用開發板自帶的vivi將其下載到記憶體中,再在記憶體中運行u-boot。要想它在記憶體中運行,方法很簡單,將u-boot/cpu/arm920t中的start.s
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
此段代碼中的bl cpu_init_crit注釋掉,即不進行CPU的初始化工作(此工作,當前在板子上運行的vivi已完成,故不能再次進行)
,即改為
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
@bl cpu_init_crit
#endif
修改/board/hugerat/rat2440/config.mk中text_base 值為0x33000000
使用vivi命令load ram 0x33000000 0x17ea8 x(0x17ea8 是載入檔案的size單位byte , x表示xmodem u表示usb)將u-boot.bin裝入記憶體。再用go 0x33000000命令,即可。
至此,第1階段工作完成。
第2階段本階段任務,是給u-boot移植dm9000的網卡驅動。u-boot自帶網卡驅動,所以只要做些設置即可。在下列檔中加入標誌為/*by hugerat,phase 2----*/的代碼./include/configs/rat2440.h (加入dm9000定義,加入ping命令定義)此時,編譯通過,但ping時,報`ethaddr' not set錯誤。研究原代碼,發現#define CONFIG_ETHADDR 08:00:3e:26:0a:5b被注釋掉,恢復,並改變原來默認的IP位址。重新編譯後,可以ping通網路了。(也可以在u-boot啟動後,修改相關參數,但因為現階段還沒有支持nandflash,參數無法保存,故在此改變較為方便)又發現,ping是能ping通了,但報could not establish link(不能建立鏈結)的錯。不影響使用。參考網上的資料,發現這是因為在網卡驅動中,/home/lijin/u-boot-rat/drivers/net/dm9000.c,有一段程式試圖連接網卡的MII介面,而實際上MII介面並未使用,所以有十秒的等待時間,且報錯,將此段程式注釋掉即可。到此,本階段任務完成。
第3階段本階段任務,移植nand-flash驅動,注意此階段工作僅是讓u-boot可以操作讀寫nand flash。還不能讓它從nand flash啟動。
首先,要說明一下CFG_NAND_LEGACY的使用。在u-boot的/drivers/mtd/下有兩個目錄,分別是nand和nand_legacy。在nand目錄下的是nand的初始化函數和nand的操作讀寫函數,是使用linux的mtd構架的。此目錄下的檔,只有在定義了CFG_CMD_NAND宏和沒有定義CFG_NAND_LEGACY巨集的情況下才會被編譯。在nand_leagcy目錄下的檔也是是實現nand相關操作命令,如read,write等命令的功能,但不是使用linux的mtd構架。此目錄下的檔,只有在定義了CFG_CMD_NAND和定義了CFG_NAND_LEGACY巨集的情況下才會定義。此目錄下的檔u-boot組織已不推薦使用。事實上,此版中,S3C2410構架已不支持對nand_leagcy,因此,我在移植中,是用的不定義CFG_NAND_LEGACY的方式,即非nand_leagcy方式。
在/include/configs/rat2440.h中加標注為by hugerat,phase3的代碼段,這段代碼是讓u-boot啟用其自帶nand flash驅動,並設置相應的nand flash參數。此時,試編譯一下,通過。要說明的是,此版的u-boot已自帶board_nand_init(),此函數在/cpu/arm920t/s3c24x0/nand.c中實現。並且此版已不支援定義CFG_NAND_LEGACY,如定義此宏,則編譯是會報 #error "U-Boot legacy NAND support not available
for S3C2410"的錯誤。故此版已不能使用網上流傳非nand_leagcy方式的自加nand flash初始化函數的方法,只能用其自帶的初始化函數下載到記憶體中運行,報None nand devices!!!,這是當然的。因為S3C2410和S3C2440在FLASH控制器上,差別較大,必須改寫代碼。
改寫主要在/cpu/arm920t/s3c24x0/nand.c中進行。(此檔內是與晶片緊密相關的代碼),一是board_nand_init函數,一是s3c2410_hwcontrol,參照2440的手冊,改寫相關代碼。還要在此檔的開始部分加入S3C2440 nand flash控制器相關寄存器的定義。改寫的代碼標注同上。改寫完畢後,u-boot可以識別出nand flash晶片是64MB的,但還不能識別是什麼晶片。
在/driver/mtd/nand/nand_base.c中的nand_get_flash_type函數結尾,修改MTDDEBUG語句,改為printf,再編譯,可以正常顯示芯片了。但nand write功能不正常,即沒報錯,實際上也沒有寫進去。
探討原因後發現,原來是u-boot自帶的nand-flash驅動(不定義nand_leagcy),是基於mtd驅動的。在默認情況下,不進行寫入正確與否的校驗。要定義CONFIG_MTD_NAND_VERIFY_WRITE宏才能進行寫入校驗。關於ECC校驗,mtd驅動默認是用sotf_ecc的。加入宏定義後,u-boot報write error了。在此我卡了很久,最後才發現是u-boot.2008.10自帶的S3C2410的s3c2410_hwcontrol函數有錯。在此函數中,把chip->IO_ADDR_W值改寫了,導致在寫資料時出現錯誤。將此錯誤修正後,nand write正常了。修正方法是使用一總體變數替代chip->IO_ADDR_W。
接下來,在rat2440.h中加入#define CONFIG_ENV_IS_IN_NAND 1注掉原來的#define CONFIG_ENV_IS_IN_FLASH 1,加入
#define CONFIG_ENV_OFFSET 0x30000 注掉原來的#define CFG_ENV_OFFSET 0x30000。編譯。saveenv功能也正常了。至此,nand-flash驅動移植完成。
測試,nand write 0x30000000 0x40000 0x40000時,成功。用nand read也成功讀出。此處要說明的,如果用vivi燒寫資訊到nand
中,再用u-boot讀取,會報錯,應該是ECC校驗不是由同一軟體產生所至。此階段完成。
第4階段本階段任務是將u-boot改寫為從nand-flash啟動。首先,將/cpu/arm920t/start.s中第一階段中為了從記憶體中啟動而遮罩掉的語句恢復。加入標注為/*by hugerat,phase 4----*/
語句,為了相容S3C2410,同時也加入S3C2410 nand boot 相關代碼。
同時,在/board/hugerat/rat2440/lower_init.s中,根據開發板電路,對記憶體相關的幾個寄存器定義進行調整。整個啟動代碼參考了vivi的代碼。因此,將vivi的nand_read.c(支持S3C2440
的vivi,此檔中的讀nand函數是直接操作nand flash的,與u-boot自帶,適合用於啟動時用。)考入/board/hugerat/rat2440目錄下。並修改目錄下的makefile,使nand_read.c被編譯。編譯,成功,將u-boot燒入nand flash,能成功從nand啟動了。
第5階段本階段任務是實現u-boot通過nfs引導友善提供的linux2.6.13的內核。友善的linux並沒有提供make uImage命令,需要添加。將u-boot的tools目錄下的mkimage拷到開發機linux系統下的/usr/bin目錄下
。在linux的/arch/arm/makefile中和/arch/arm/boot/makefile中,可以找到zImage的項目,仿照它添加uImage項目。
這個問題解決後,就是要用u-boot引導linux內核了,我用的是揚創提供的linux2.6.13的內核,揚創提供的內核,loadaddress和entry都是30008000,我用u-boot1.2中的bootcmd參數,u-boot1.3.1 bootm卻不能引導,報bad magic number,看了bootm的相關資料,得知,如果我們沒用mkimage對內核進行處理的話,那直接把內核下載到0x30008000再運行就行,內核會自解壓運行(不過內核運行需要一個tag來傳遞參數,而這個tag建議是由bootloader提供的,在u-boot下默認是由bootm命令建立的)。 2)如果使用mkimage生成內核鏡像檔的話,會在內核的前頭加上了64byte的資訊,供建立tag之用。bootm命令會首先判斷bootm xxxx 這個指定的位址xxxx是否與-a指定的載入位址相同。(1)如果不同的話會從這個位址開始提取出這個64byte的頭部,對其進行分析,然後把去掉頭部的內核複製到-a指定的load地址中去運行之(2)如果相同的話那就讓其原封不同的放在那,但-e指定的入口地址會推後64byte,以跳過這64byte的頭部。
Bootm在沒有參數時,是採用rat2440.h中的#define CFG_LOAD_ADDR 的位址的,而我用bootm就是沒有使用參數,所以出錯了。正確的做法應該是用nand read命令將內核從nand flash中讀到記憶體的某一位址中(注意不要與其他已分配的記憶體衝突),然後再用bootm 加位址參數,即可引導,也可以在上述的檔中,將CFG_LOAD_ADDR的位址定義為此位址,再用bootm就可以了.我設定bootcmd環境變數為tftp 0x31000000 uImage; bootm 0x31000000,注意位址不能為0x30008000,否則報錯.
做完這此,內核可以引導了,但卻停在starting kernel不動了,好在我以前做過vivi+linux2.6.22的移植,知道此問題多半是由於mach_type不同而造成的。在u-boot中,此mach_type是由rat2440.c中的這段代碼定義的
#if defined(CONFIG_S3C2440)
/* arch number of S3C2440 -Board */
//gd->bd->bi_arch_number = 5244 ; //改為和內核的MACH_TYPE一至
gd->bd->bi_arch_number = MACH_TYPE_MINI2440 ;
#endif
你可以直接在這裏改數位,也可以在include/asm-arm/mach_types.h的文件中,改MACH_TYPE_S3C2440的數值。將數值改為和內核的
mach_type一至。至於內核的mach_type可以在內核linux源代碼下的arch/arm/tools中的mach_types檔查看到。
此時,又發現內核不能通過nfs引導。查資料後得知是因為u-boot沒有傳遞參數給內核。原來是rat2440.h中少定義了幾個宏。補上
。#define CONFIG_CMDLINE_TAG 1 /* enable passing of ATAGs */
#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_INITRD_TAG 1
至此,u-boot已能正常引導linux啟動了。第5階段完成。
第6階段本階段任務,是給u-boot加入燒寫yaffs映射檔的功能。網上有很多文章已經有介紹如何加入此功能,方法也不複雜。但我移植的u-boot.2008.10版,在nand flash的操作上與之前的版本
有了很大的區別。這些文章介紹的方法已不能在此版中應用。於是我只好自已根據u-boot的源代碼,yaffs映射檔的格式,自已編修改了u-boot.2008.10的代碼,讓它可以實現yaffs的燒寫,因為我用的開發板的nand flash是k9f1208,只能使用yaffs1,所以我的修改代碼暫時只能支援yaffs1格式的映射。(要支持yaffs2也不難,但因為無法驗證,所以就沒有做嘗試。)修改方法如下:在/common/com_nand.c中do_nand函數中,加入三段/*by hugerat,phase6---*/標注的代碼,實現對nand write.yaffs命令的支援。
此代碼中,要用到mtd_info結構中的兩個變數,這兩個變數本來是沒有的,所以要在include/linux/mtd/mtd.h的mtd_info結構體定
義中加入。在/drivers/mtd/nand/nand_util.c的nand_write_skip_bad函數中,兩段程式,一段是為了計算正常資料的長度,一段是為了在寫入一段資料後,資料指標能正常跳到下一段資料。在/drivers/mtd/nand/nand_base.c的nand_write函數中,加入一段把正常資料與oob資料分離的代碼,再加入頁寫時的模式設置為MTD_OOB_RAW,使頁寫時,不進行ECC的校驗和加入。(ECC的校驗在yaffs的oob資料中已自帶了,不能重寫。)此模式下,寫入正常資料後,會把oob資料緩存的資料寫入nand的oob區。至此,u-boot.2008.10的移植工作全部完成。
最後說明一下,關於陽初2410的移植,因為上面的代碼中已加入S3C2410相關代碼,移植時,只需參考S3C2440,新建一個開發板體系,新建時,將rat2440目錄下的檔拷貝到rat2410下,將重命名S3C2440.c為S3C2410.c,修改makefile,加上s3c2410.o 去掉s3c2440.o,拷貝rat2440.h為rat2410.h,將其中的CONFIG_S3C2440注掉,加上CONFIG_S3C2410。在u-boot總目錄下的makefile中rat2440_config下添加rat2410_config : unconfig @$(MKCONFIG) $(@:_config=) arm arm920t rat2410 hugerat s3c24x0因為陽初的板用的是cs8900,因此要在rat2410.h中注掉DM9000的定義,添加CS8900的。再make rat2410_config,再make,即可。
文章最後,為方便網友,我把patch檔附上。patch文件使用方法是在linux下建立u-boot-rat.patch檔,將patch檔的內容拷入u-boot-rat.patch文件中。下載u-boot-2008.10.tar.bz2,在這裏下載ftp://ftp.denx.de/pub/u-boot/,用tar -xvf u-bot-2008.19.tar.bz2解壓到u-boot-2008.10目錄,把u-boot-rat.patch檔拷貝到此目錄所在同級目錄下。執行patch -p0 小於符號 u-boot-rat.patch。完成後,進u-boot-2008.10目錄,執行make rat2440_config,再make即可生成u-boot.bin,如是2410,則執行make rat2410_config即可,我在mini2440,陽初的2410上試過,功能正常。其他開發板的也可一試。 附patch文件: 可能發貼字數有限制,下面的補丁檔不全。可以在此下載全部補丁。 文件:u-boot-rat.rar 大小:20KB 下載
--> 閱讀更多...