簡(jiǎn)單說(shuō)說(shuō)U-boot的修改
簡(jiǎn)單說(shuō)說(shuō)U-boot的修改
uboot是一個(gè)通用的免費開(kāi)放源碼的boot程序,支持很多的處理器。
以下是現在網(wǎng)上下載一個(gè)u-boot-1.1.1版本,用于at91rm9200系統的修改的例子。最后在redhat8.0上,用gcc2.95編譯通過(guò)。
在網(wǎng)上下載了uboot-1.1.1版本。要用于自己的at91rm9200的系統,這個(gè)系統的情況是:
SDRAM: 32Mbytes NCS1
FLASH: 8Mbytes NCS0
涉及到的文件有四個(gè):
common.h
flash.c
flash.h
”./board/at91rm9200dk/config.mk”
以下簡(jiǎn)單的說(shuō)說(shuō)。
一、首先讀讀uboot自帶的readme文件,了解了一個(gè)大概。
二、看看common.h,這個(gè)文件定義了一些基本的東西,并包含了一些必要的頭文件。再看看flash.h,這個(gè)文件里面定義了flash_info_t為一個(gè)struct。包含了flash的一些屬性定義。并且定義了所有的flash的屬性,其中,AMD的有:AMD_ID_LV320B,定義為“#define AMD_ID_LV320B 0x22F922F9”。
三、對于“./borad/at91rm9200dk/flash.c”的修改,有以下的方面:
“void flash_identification(flash_info_t *info)”這個(gè)函數的目的是確認flash的型號。注意的是,這個(gè)函數里面有一些宏定義,直接讀寫(xiě)了flash。并獲得ID號。
四、修改:”./board/at91rm9200dk/config.mk”為
TEXT_BASE=0x21f80000 為T(mén)EXT_BASE=0x21f00000 (當然,你應該根據自己的板子來(lái)修改,和一級boot的定義的一致即可)。
五、再修改”./include/configs/at91rm9200dk.h”為
修改flash和SDRAM的大小。
六、另外一個(gè)要修改的文件是:
./borad/at91rm9200dk/flash.c。這個(gè)文件修改的部分比較的多。
1. 首先是OrgDef的定義,加上目前的flash。
2. 接下來(lái),修改”#define FLASH_BANK_SIZE 0x200000”為自己flash的容量
3. 在修改函數flash_identification(flash_info_t * info)里面的打印信息,這部分將在u-boot啟動(dòng)的時(shí)候顯示。
4. 然后修改函數flash_init(void)里面對一些變量的賦值。
5. 最后修改的是函數flash_print_info(flash_info_t * info)里面實(shí)際打印的函數信息。
6. 還有一個(gè)函數需要修改,就是:“flash_erase”,這個(gè)函數要檢測先前知道的flash類(lèi)型是否匹配,否則,直接就返回了。把這里給注釋掉。
七、接下來(lái)看看SDRAM的修改。
這個(gè)里面對于“SIZE”的定義都是基于字節計算的。
只要修改”./include/configs/at91rm9200dk.h”里面的
“#define PHYS_SDRAM_SIZE 0X200000”就可以了。注意,SIZE是以字節為單位的。
八、還有一個(gè)地方要注意
就是按照目前的設定,一級boot把u_boot加載到了SDRAM的空間為:21F00000 -> 21F16B10,這恰好是SDRAM的高端部分。另外,BSS為21F1AE34。
九、編譯后,可以寫(xiě)入flash了。
1. 壓縮這個(gè)u-boot.bin
“gzip –c u-boot.bin > u-boot.gz”
壓縮后的文件大小為:
43Kbytes
2. 接著(zhù)把boot.bin和u-boot.gz燒到flash里面去。
Boot.bin大約11kBytes,在flash的0x1000 0000 ~ 0x1000 3fff
免費參加,名額有限!2005DVTF;MP3 U盤(pán)禮物...
zlei 發(fā)表于 2005-1-16 12:31 ARM 論壇 ←返回版面
U-Boot 在44B0X 開(kāi)發(fā)板上的移植以及代碼分析(ZT)
armboot的原理
1、BIOS的源碼,其作用是初始化硬件,并COPY Boot到SDRAM中
2、在SDRAM中運行BOOT達到在線(xiàn)升級的目的。
3、此源代碼與硬件無(wú)關(guān),在44b0x上測試通過(guò)
4、串口通訊協(xié)議自己制定,很好理解。在線(xiàn)升級很快
5、目前只支持SST39LVF160,可以自己修改成相信的NOR FLASH
U-Boot 在44B0X 開(kāi)發(fā)板上的移植以及代碼分析
1. u-boot 介紹
u-boot是一個(gè)open source 的bootloader,目前版本是0.4.0。u-boot 是在ppcboot 以及armboot的基礎上發(fā)展而來(lái),雖然宣稱(chēng)是0.4.0版本,卻相當的成熟和穩定,已經(jīng)在許多嵌入式系統開(kāi)發(fā)過(guò)程中被采用。由于其開(kāi)發(fā)源代碼,其支持的開(kāi)發(fā)板眾多。唯一遺憾的是并不支持我們現在學(xué)習所用samsung 44B0X 的開(kāi)發(fā)板。
為什么我們需要u-boot?顯然可以將ucLinux 直接燒入flash,從而不需要額外的
引導裝載程序(bootloader)。但是從軟件升級的角度以及程序修補的來(lái)說(shuō),軟件的自
動(dòng)更新非常重要。事實(shí)上,引導裝載程序(bootloader)的用途不僅如此,但僅從軟件的自動(dòng)更新的需要就說(shuō)明我們的開(kāi)發(fā)是必要的。同時(shí),u-boot 移植的過(guò)程也是一個(gè)對嵌入式系統包括軟硬件以及操作系統加深理解的一個(gè)過(guò)程。
2. u-boot 移植的框架
移植u-boot 到新的開(kāi)發(fā)板上僅需要修改和硬件相關(guān)的部分。在代碼結構上:
1)在board 目錄下創(chuàng )建ev44b0ii 目錄,創(chuàng )建ev44b0ii.c以及flash.c,memsetup.S,u-boot.lds等。不需要從零開(kāi)始,可選擇一個(gè)相似的目錄,直接復制過(guò)來(lái),修改文件名以及內容。我在移植u-boot 過(guò)程中,選擇的是ep7312 目錄。由于u-boot 已經(jīng)包含基于s3c24b0 的開(kāi)發(fā)板目錄,作為參考,也可以復制相應的目錄。
2) 在cpu 目錄下創(chuàng )建arm7tdmi 目錄,主要包含start.S,interrupts.c 以及cpu.c,serial.c幾個(gè)文件。同樣不需要從零開(kāi)始建立文件,直接從arm720t 復制,然后修改相應內容。
3) 在include/configs 目錄下添加ev44b0ii.h,在這里放上全局的宏定義等。
4) 找到u-boot 根目錄下Makefile 修改加入
ev44b0ii_config : unconfig
@./mkconfig $(@:_config=) arm arm7tdmi ev44b0ii
5) 運行make ev44bii_config,如果沒(méi)有錯誤就可以開(kāi)始硬件相關(guān)代碼移植的工作
3. u-boot 的體系結構
1) 總體結構
u-boot是一個(gè)層次式結構。從上圖也可以看出,做移植工作的軟件人員應當提供串口驅動(dòng)(UART Driver),以太網(wǎng)驅動(dòng)(EthernetDriver),Flash 驅動(dòng)(Flash 驅動(dòng)),USB 驅動(dòng)(USB Driver)。目前,通過(guò)USB口下載程序顯得不是十分必要,所以暫時(shí)沒(méi)有移植USB 驅動(dòng)。驅動(dòng)層之上是u-boot 的應用,command通過(guò)串口提供人機界面。我們可以使用一些命令做一些常用的工作,比如內存查看命令md。
Kermit 應用主要用來(lái)支持使用串口通過(guò)超級終端下載應用程序。TFTP 則是通過(guò)網(wǎng)絡(luò )方式來(lái)下載應用程序,例如uclinux 操作系統。
2) 內存分布
在flashrom 中內存分布圖ev44b0ii 的flash 大小2M(8bits),現在將0-40000 共256k 作為u-boot的存儲空間。由于u-boot 中有一些環(huán)境變量,例如ip 地址,引導文件名等,可在命令行通過(guò)setenv 配置好,通過(guò)saveenv保存在40000-50000(共64k)這段空間里。如果存在保存好的環(huán)境變量,u-boot引導將直接使用這些環(huán)境變量。正如從代碼分析中可以看到,我們會(huì )把flash 引導代碼搬移到DRAM 中運行。下圖給出u-boot的代碼在DRAM中的位置。引導代碼u-boot 將從0x0000 0000 處搬移到0x0C700000 處。特別注意的由于ev44b0iiuclinux 中斷向量程序地址在0x0c00 0000 處,所以不能將程序下載到0x0c00 0000 出,通常下載到0x0c08 0000處。
4. start.S 代碼結構
1) 定義入口
一個(gè)可執行的Image 必須有一個(gè)入口點(diǎn)并且只能有一個(gè)唯一的全局入口,通常這個(gè)入口放在Rom(flash)的0x0 地址。例如start.S 中的
.globl _start
_start:
值得注意的是你必須告訴編譯器知道這個(gè)入口,這個(gè)工作主要是修改連接器腳本文件(lds)。
2) 設置異常向量(Exception Vector)
異常向量表,也可稱(chēng)為中斷向量表,必須是從0地址開(kāi)始,連續的存放。如下面的就包括了復位(reset),未定義處理(undef),軟件中斷(SWI),預去指令錯誤(Pabort),數據錯誤(Dabort),保留,以及IRQ,FIQ 等。注意這里的值必須與uclinux 的vector_base 一致。這就是說(shuō)如果uclinux中vector_base(include/armnommu/proc-armv/system.h)定義為0x0c000000,則HandleUndef 應該在
0x0c00 0004。
b reset //for debug
ldr pc,=HandleUndef
ldr pc,=HandleSWI
ldr pc,=HandlePabort
ldr pc,=HandleDabort
b .
ldr pc,=HandleIRQ
ldr pc,=HandleFIQ
ldr pc,=HandleEINT0 /*mGA H/W interrupt vector table*/
ldr pc,=HandleEINT1
ldr pc,=HandleEINT2
ldr pc,=HandleEINT3
ldr pc,=HandleEINT4567
ldr pc,=HandleTICK /*mGA*/
b .
b .
ldr pc,=HandleZDMA0 /*mGB*/
ldr pc,=HandleZDMA1
ldr pc,=HandleBDMA0
ldr pc,=HandleBDMA1
ldr pc,=HandleWDT
ldr pc,=HandleUERR01 /*mGB*/
b .
b .
ldr pc,=HandleTIMER0 /*mGC*/
ldr pc,=HandleTIMER1
ldr pc,=HandleTIMER2
ldr pc,=HandleTIMER3
ldr pc,=HandleTIMER4
ldr pc,=HandleTIMER5 /*mGC*/
b .
b .
ldr pc,=HandleURXD0 /*mGD*/
ldr pc,=HandleURXD1
ldr pc,=HandleIIC
ldr pc,=HandleSIO
ldr pc,=HandleUTXD0
ldr pc,=HandleUTXD1 /*mGD*/
b .
b .
ldr pc,=HandleRTC /*mGKA*/
b .
b .
b .
b .
b . /*mGKA*/
b .
b .
ldr pc,=HandleADC /*mGKB*/
b .
b .
b .
b .
b . /*mGKB*/
b .
b .
ldr pc,=EnterPWDN
作為對照:請看以上標記的值:
.equ HandleReset, 0xc000000
.equ HandleUndef,0xc000004
.equ HandleSWI, 0xc000008
.equ HandlePabort, 0xc00000c
.equ HandleDabort, 0xc000010
.equ HandleReserved, 0xc000014
.equ HandleIRQ, 0xc000018
.equ HandleFIQ, 0xc00001c
/*the value is different with an address you think it may be.
*IntVectorTable */
.equ HandleADC, 0xc000020
.equ HandleRTC, 0xc000024
.equ HandleUTXD1, 0xc000028
.equ HandleUTXD0, 0xc00002c
.equ HandleSIO, 0xc000030
.equ HandleIIC, 0xc000034
.equ HandleURXD1, 0xc000038
.equ HandleURXD0, 0xc00003c
.equ HandleTIMER5, 0xc000040
.equ HandleTIMER4, 0xc000044
.equ HandleTIMER3, 0xc000048
.equ HandleTIMER2, 0xc00004c
.equ HandleTIMER1, 0xc000050
.equ HandleTIMER0, 0xc000054
.equ HandleUERR01, 0xc000058
.equ HandleWDT, 0xc00005c
.equ HandleBDMA1, 0xc000060
.equ HandleBDMA0, 0xc000064
.equ HandleZDMA1, 0xc000068
.equ HandleZDMA0, 0xc00006c
.equ HandleTICK, 0xc000070
.equ HandleEINT4567, 0xc000074
.equ HandleEINT3, 0xc000078
.equ HandleEINT2, 0xc00007c
.equ HandleEINT1, 0xc000080
.equ HandleEINT0, 0xc000084
3) 初始化CPU 相關(guān)的pll,clock,中斷控制寄存器
依次為關(guān)閉watch dog timer,關(guān)閉中斷,設置LockTime,PLL(phase lock loop),以及時(shí)鐘。
這些值(除了LOCKTIME)都可從Samsung 44b0 的手冊中查到。
ldr r0,WTCON //watch dog disable
ldr r1,=0x0
str r1,[r0]
ldr r0,INTMSK
ldr r1,MASKALL //all interrupt disable
str r1,[r0]
/*****************************************************
* Set clock control registers *
*****************************************************/
ldr r0,LOCKTIME
ldr r1,=800 // count = t_lock * Fin (t_lock=200us, Fin=4MHz) = 800
str r1,[r0]
ldr r0,PLLCON /*temporary setting of PLL*/
ldr r1,PLLCON_DAT /*Fin=10MHz,Fout=40MHz or 60MHz*/
str r1,[r0]
ldr r0,CLKCON
ldr r1,=0x7ff8 //All unit block CLK enable
str r1,[r0]
4) 初始化內存控制器
內存控制器,主要通過(guò)設置13 個(gè)從1c80000 開(kāi)始的寄存器來(lái)設置,包括總線(xiàn)寬度,
8 個(gè)內存bank,bank 大小,sclk,以及兩個(gè)bank mode。
/*****************************************************
* Set memory control registers *
*****************************************************/
memsetup:
adr r0,SMRDATA
ldmia r0,{r1-r13}
ldr r0,=0x01c80000 //BWSCON Address
stmia r0,{r1-r13}
5) 將rom 中的程序復制到RAM 中
首先利用PC 取得bootloader 在flash 的起始地址,再通過(guò)標號之差計算出這個(gè)程序代
碼的大小。這些標號,編譯器會(huì )在連接(link)的時(shí)候生成正確的分布的值。取得正
確信息后,通過(guò)寄存器(r3 到r10)做為復制的中間媒介,將代碼復制到RAM 中。
relocate:
/*
* relocate armboot to RAM
*/
adr r0, _start /* r0 <- current position of code */
ldr r2, _armboot_start
ldr r3, _armboot_end
sub r2, r3, r2 /* r2 <- size of armboot */
ldr r1, _TEXT_BASE /* r1 <- destination address */
add r2, r0, r2 /* r2 <- source end address */
/*
* r0 = source address
* r1 = target address
* r2 = source end address
*/
copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble copy_loop
6) 初始化堆棧
進(jìn)入各種模式設置相應模式的堆棧。
InitStacks:
/*Don‘‘t use DRAM,such as stmfd,ldmfd......
SVCstack is initialized before*/
mrs r0,cpsr
bic r0,r0,#0X1F
orr r1,r0,#0xDB /*UNDEFMODE|NOINT*/
msr cpsr,r1 /*UndefMode*/
ldr sp,UndefStack
orr r1,r0,#0XD7 /*ABORTMODE|NOINT*/
msr cpsr,r1 /*AbortMode*/
ldr sp,AbortStack
orr r1,r0,#0XD2 /*IRQMODE|NOINT*/
msr cpsr,r1 /*IRQMode*/
ldr sp,IRQStack
orr r1,r0,#0XD1 /*FIQMODE|NOINT*/
msr cpsr,r1 /*FIQMode*/
ldr sp,FIQStack
bic r0,r0,#0XDF /*MODEMASK|NOINT*/
orr r1,r0,#0X13
msr cpsr,r1 /*SVCMode*/
ldr sp,SVCStack
7) 轉到RAM 中執行
使用指令ldr,pc,RAM 中C 函數地址就可以轉到RAM 中去執行。
5. 系統初始化部分
1. 串口部分
串口的設置主要包括初始化串口部分,值得注意的串口的Baudrate 與時(shí)鐘MCLK 有很大關(guān)系,是通過(guò):rUBRDIV0=((int)(MCLK/16./(gd ->baudrate) + 0.5) -1)計算得出。這可以在手冊中查到。其他的函數包括發(fā)送,接收。這個(gè)時(shí)候沒(méi)有中斷,是通過(guò)循環(huán)等待來(lái)判斷是否動(dòng)作完成。
例如,接收函數:
while(!(rUTRSTAT0 & 0x1)); //Receive data read
return RdURXH0();
2. 時(shí)鐘部分
實(shí)現了延時(shí)函數udelay。
這里的get_timer 由于沒(méi)有使用中斷,是使用全局變量來(lái)累加的。
3. flash 部分
flash 作為內存的一部分,讀肯定沒(méi)有問(wèn)題,關(guān)鍵是flash 的寫(xiě)部分。
Flash 的寫(xiě)必須先擦除,然后再寫(xiě)。
unsigned long flash_init (void)
{
int i;
u16 manId,devId;
//first we init it as unknown,even if you forget assign it below,it‘‘s not a problem
for (i=0; i < CFG_MAX_FLASH_BANKS; ++i){
flash_info[i].flash_id = FLASH_UNKNOWN;
flash_info[i].sector_count=CFG_MAX_FLASH_SECT;
}
/*check manId,devId*/
_RESET();
_WR(0x555,0xaa);
_WR(0x2aa,0x55);
_WR(0x555,0x90);
manId=_RD(0x0);
_WR(0x555,0xaa);
_WR(0x2aa,0x55);
_WR(0x555,0x90);
devId=_RD(0x1);
_RESET();
printf("flashn");
printf("Manufacture ID=%4x(0x0004), Device ID(0x22c4)=%4xn",manId,devId);
if(manId!=0x0004 && devId!=0x22c4){
printf("flash check faliluren");
return 0;
}else{
for (i=0; i < CFG_MAX_FLASH_BANKS; ++i){
flash_info[i].flash_id=FLASH_AM160T;/*In fact it is fujitu,I only don‘‘t want to
modify common files*/
}
}
/* Setup offsets */
flash_get_offsets (CFG_FLASH_BASE, &flash_info[0]);
/* zhangyy comment
#if CFG_MONITOR_BASE >= CFG_FLASH_BASE
//onitor protection ON by default
flash_protect(FLAG_PROTECT_SET,
CFG_MONITOR_BASE,
CFG_MONITOR_BASE+monitor_flash_len-1,
&flash_info[0]);
#endif
*/
flash_info[0].size =PHYS_FLASH_SIZE;
return (PHYS_FLASH_SIZE);
}
flash_init 完成初始化部分,這里的主要目的是檢驗flash 的型號是否正確。
int flash_erase (flash_info_t *info, int s_first, int s_last)
{
volatile unsigned char *addr = (volatile unsigned char *)(info->start[0]);
int flag, prot, sect, l_sect;
//ulong start, now, last;
u32 targetAddr;
u32 targetSize;
/*zyy note:It is required and can‘‘t be omitted*/
rNCACHBE0=( (0x2000000>>12)<<16 )|(0>>12); //flash area(Bank0) must be non-cachable
area.
rSYSCFG=rSYSCFG & (~0x8); //write buffer has to be off for proper timing.
if ((s_first < 0) || (s_first > s_last)) {
if (info->flash_id == FLASH_UNKNOWN) {
printf ("- missingn");
} else {
printf ("- no sectors to erasen");
}
return 1;
}
if ((info->flash_id == FLASH_UNKNOWN) ||
(info->flash_id > FLASH_AMD_COMP)) {
printf ("Can‘‘t erase unknown flash type - abortedn");
return 1;
}
prot = 0;
for (sect=s_first; sect<=s_last; ++sect) {
if (info->protect[sect]) {
prot++;
}
}
if (prot) {
printf ("- Warning: %d protected sectors will not be erased!n",
prot);
} else {
printf ("n");
}
l_sect = -1;
/* Disable interrupts which might cause a timeout here */
flag = disable_interrupts();
/* Start erase on unprotected sectors */
for (sect = s_first; sect<=s_last; sect++) {
if (info->protect[sect] == 0) {/* not protected */
targetAddr=0x10000*sect;
if(targetAddr<0x1F0000)
targetSize=0x10000;
else if(targetAddr<0x1F8000)
targetSize=0x8000;
else if(targetAddr<0x1FC000)
targetSize=0x2000;
else
targetSize=0x4000;
F29LV160_EraseSector(targetAddr);
l_sect = sect;
if(!BlankCheck(targetAddr, targetSize))
printf("BlankCheck Errorn");
}
}
/* re-enable interrupts if necessary */
if (flag)
enable_interrupts();
/* wait at least 80us - let‘‘s wait 1 ms */
udelay (1000);
/*
*We wait for the last triggered sector
*/
if (l_sect < 0)
goto DONE;
DONE:
printf (" donen");
return 0;
}
int BlankCheck(int targetAddr,int targetSize)
{
int i,j;
for(i=0;i{
j=*((u16 *)(i+targetAddr));
if( j!=0xffff)
{
printf("E:%x=%xn",(i+targetAddr),j);
return 0;
}
}
return 1;
}
flash_erase 擦除flash,BlankCheck 則檢查該部分內容是否擦除成功。
/*-----------------------------------------------------------------------
*Write a word to Flash, returns:
* 0 - OK
* 1 - write timeout
* 2 - Flash not erased
*/
static int write_word (flash_info_t *info, ulong dest, ulong data)
{
volatile u16 *tempPt;
/*zhangyy note:because of compatiblity of function,I use low & hi*/
u16 low = data & 0xffff;
u16 high = (data >> 16) & 0xffff;
low=swap_16(low);
high=swap_16(high);
tempPt=(volatile u16 *)dest;
_WR(0x555,0xaa);
_WR(0x2aa,0x55);
_WR(0x555,0xa0);
*tempPt=high;
_WAIT();
_WR(0x555,0xaa);
_WR(0x2aa,0x55);
_WR(0x555,0xa0);
*(tempPt+1)=low;
_WAIT();
return 0;
}
wirte_word 則想flash 里面寫(xiě)入unsigned long 類(lèi)型的data,因為flash 一次只能寫(xiě)入16bits,所以這里分兩次寫(xiě)入。
免費參加,名額有限!2005DVTF;MP3 U盤(pán)禮物...
zlei 發(fā)表于 2005-1-16 12:33 ARM 論壇 ←返回版面
MPC8xx的U-Boot移植體會(huì )(ZT)
BOOTLOADER(引導裝載器),是用于初始化目標板硬件,給嵌入式操作系統提供板上硬件資源信息,并進(jìn)一步裝載、引導嵌入式操作系統運行的固件。在嵌入式系統開(kāi)發(fā)過(guò)程中,很多情況都會(huì )涉及底層BOOT LOADER的移植問(wèn)題,即使在有些已有BOOTLOADER的參考開(kāi)發(fā)板上也存在這種可能。概括來(lái)說(shuō),如下情況會(huì )考慮進(jìn)行BOOT LOADER的移植工作:
A. 在自主設計的目標板上,用于引導嵌入式操作系統及其應用;
B. 在廠(chǎng)家未提供BOOT LOADER源碼的參考板上,遇有如下情形之一:
a. 在實(shí)際應用中需要添加或修改一些功能;
b. 為了給自行設計主板移植BOOT LOADER提供參考,先在參考板上進(jìn)行移植以積累經(jīng)驗;
另外,從嵌入式系統實(shí)際開(kāi)發(fā)角度講,嵌入式操作系統的引導、配置甚至應用程序的運行狀況都和BOOT LOADER有一定的關(guān)聯(lián),可以說(shuō),掌握BOOT LOADER移植是順利進(jìn)行嵌入式系統開(kāi)發(fā)的重要利器。
與常見(jiàn)的嵌入式操作系統板級支持包BSP相比,BOOT LOADER與底層硬件更為相關(guān),即每個(gè)不同配置的目標板基本都有不同的BOOTLOADER。因為BOOT LOADER往往更依據量體裁衣、定身制作的原則,以滿(mǎn)足要求的最小化代碼存放在啟動(dòng)ROM或FLASH中。
誠然,自行編寫(xiě)BOOT LOADER未嘗不可,但從可利用的資源和實(shí)際項目開(kāi)發(fā)考慮,采用移植已有的BOOT LOADER源碼來(lái)解決這一問(wèn)題更符合大多數項目開(kāi)發(fā)的要求。
1 U-Boot簡(jiǎn)介
U-Boot,全稱(chēng)Universal BootLoader,是遵循GPL條款的開(kāi)放源碼項目。從FADSROM、8xxROM、PPCBOOT逐步發(fā)展演化而來(lái)。其源碼目錄、編譯形式與Linux內核很相似,事實(shí)上,不少U-Boot源碼就是相應的Linux內核源程序的簡(jiǎn)化,尤其是一些設備的驅動(dòng)程序,這從U-Boot源碼的注釋中能體現這一點(diǎn)。但是U-Boot不僅僅支持嵌入式Linux系統的引導,當前,它還支持NetBSD, VxWorks, QNX, RTEMS, ARTOS,LynxOS嵌入式操作系統。其目前要支持的目標操作系統是OpenBSD, NetBSD, FreeBSD,4.4BSD, Linux,SVR4, Esix, Solaris, Irix, SCO, Dell, NCR, VxWorks, LynxOS, pSOS, QNX,RTEMS,ARTOS。這是U-Boot中Universal的一層含義,另外一層含義則是U-Boot除了支持PowerPC系列的處理器外,還能支持MIPS、x86、ARM、NIOS、XScale等諸多常用系列的處理器。這兩個(gè)特點(diǎn)正是U-Boot項目的開(kāi)發(fā)目標,即支持盡可能多的嵌入式處理器和嵌入式操作系統。就目前來(lái)看,U-Boot對PowerPC系列處理器支持最為豐富,對Linux的支持最完善。其它系列的處理器和操作系統基本是在2002年11月PPCBOOT改名為U-Boot后逐步擴充的。從PPCBOOT向U-Boot的順利過(guò)渡,很大程度上歸功于U-Boot的維護人德國DENX軟件工程中心WolfgangDenk[以下簡(jiǎn)稱(chēng)W.D]本人精湛專(zhuān)業(yè)水平和持著(zhù)不懈的努力。當前,U-Boot項目正在他的領(lǐng)軍之下,眾多有志于開(kāi)放源碼BOOTLOADER移植工作的嵌入式開(kāi)發(fā)人員正如火如荼地將各個(gè)不同系列嵌入式處理器的移植工作不斷展開(kāi)和深入,以支持更多的嵌入式操作系統的裝載與引導。
選擇U-Boot的理由:
① 開(kāi)放源碼;
② 支持多種嵌入式操作系統內核,如Linux、NetBSD, VxWorks, QNX, RTEMS, ARTOS, LynxOS;
③ 支持多個(gè)處理器系列,如PowerPC、ARM、x86、MIPS、XScale;
④ 較高的可靠性和穩定性;
④ 較高的可靠性和穩定性;
⑤ 高度靈活的功能設置,適合U-Boot調試、操作系統不同引導要求、產(chǎn)品發(fā)布等;
⑥ 豐富的設備驅動(dòng)源碼,如串口、以太網(wǎng)、SDRAM、FLASH、LCD、NVRAM、EEPROM、RTC、鍵盤(pán)等;
⑦ 較為豐富的開(kāi)發(fā)調試文檔與強大的網(wǎng)絡(luò )技術(shù)支持;
2 U-Boot主要目錄結構
- board 目標板相關(guān)文件,主要包含SDRAM、FLASH驅動(dòng);
- common 獨立于處理器體系結構的通用代碼,如內存大小探測與故障檢測;
- cpu 與處理器相關(guān)的文件。如mpc8xx子目錄下含串口、網(wǎng)口、LCD驅動(dòng)及中斷初始化等文件;
- driver 通用設備驅動(dòng),如CFI FLASH驅動(dòng)(目前對INTEL FLASH支持較好)
- doc U-Boot的說(shuō)明文檔;
- examples可在U-Boot下運行的示例程序;如hello_world.c,timer.c;
- include U-Boot頭文件;尤其configs子目錄下與目標板相關(guān)的配置頭文件是移植過(guò)程中經(jīng)常要修改的文件;
- lib_xxx 處理器體系相關(guān)的文件,如lib_ppc, lib_arm目錄分別包含與PowerPC、ARM體系結構相關(guān)的文件;
- net 與網(wǎng)絡(luò )功能相關(guān)的文件目錄,如bootp,nfs,tftp;
- post 上電自檢文件目錄。尚有待于進(jìn)一步完善;
- rtc RTC驅動(dòng)程序;
- tools 用于創(chuàng )建U-Boot S-RECORD和BIN鏡像文件的工具;
3 U-Boot支持的主要功能
U-Boot可支持的主要功能列表
系統引導 支持NFS掛載、RAMDISK(壓縮或非壓縮)形式的根文件系統
支持NFS掛載、從FLASH中引導壓縮或非壓縮系統內核;
基本輔助功能 強大的操作系統接口功能;可靈活設置、傳遞多個(gè)關(guān)鍵參數給操作系統,適合系統在不同開(kāi)發(fā)階段的調試要求與產(chǎn)品發(fā)布,尤對Linux支持最為強勁;
支持目標板環(huán)境參數多種存儲方式,如FLASH、NVRAM、EEPROM;
CRC32校驗,可校驗FLASH中內核、RAMDISK鏡像文件是否完好;
設備驅動(dòng) 串口、SDRAM、FLASH、以太網(wǎng)、LCD、NVRAM、EEPROM、鍵盤(pán)、USB、PCMCIA、PCI、RTC等驅動(dòng)支持;
上電自檢功能 SDRAM、FLASH大小自動(dòng)檢測;SDRAM故障檢測;CPU型號;
特殊功能 XIP內核引導;
4 U-Boot移植過(guò)程
① 獲得發(fā)布的最新版本U-Boot源碼,與Linux內核源碼類(lèi)似,也是 bzip2的壓縮格式??蓮腢-Boot的官方網(wǎng)站
http://sourceforge.net/projects/U-Boot上獲得;
② 閱讀相關(guān)文檔,主要是U-Boot源碼根目錄下的README文檔和U-Boot官方網(wǎng)站的DULG(The DENX U-Boot and Linux Guide)文檔
http://www.denx.de/twiki/bin/view/DULG/Manual。尤其是DULG文檔,從如何安裝建立交叉開(kāi)發(fā)環(huán)境和解決U-Boot移植中常見(jiàn)問(wèn)題都一一給出詳盡的說(shuō)明;
③ 訂閱U-Boot用戶(hù)郵件列表
http://lists.sourceforge.net/lists/listinfo/u-boot-users。在移植U-Boot過(guò)程中遇有問(wèn)題,在參考相關(guān)文檔和搜索U-Boot-User郵件檔案庫
http://sourceforge.net/mailarchive/forum.php?forum_id=12898仍不能解決的情況下,第一時(shí)間提交所遇到的這些問(wèn)題,眾多熱心的U-Boot開(kāi)發(fā)人員會(huì )樂(lè )于迅速排查問(wèn)題,而且很有可能,W.D本人會(huì )直接參與指導;
④ 在建立的開(kāi)發(fā)環(huán)境下進(jìn)行移植工作。絕大多數的開(kāi)發(fā)環(huán)境是交叉開(kāi)發(fā)環(huán)境。在這方面,DENX 和MontaVista均提供了完整的開(kāi)發(fā)工具集;
⑤在目標板與開(kāi)發(fā)主機間接入硬件調試器。這是進(jìn)行U-Boot移植應當具備且非常關(guān)鍵的調試工具。因為在整個(gè)U-Boot的移植工作中,尤其是初始階段,硬件調試器是我們了解目標板真實(shí)運行狀態(tài)的唯一途徑。在這方面,W.D本人和眾多嵌入式開(kāi)發(fā)人員傾向于使用BDI2000。一方面,其價(jià)格不如ICE調試器昂貴,同時(shí)其可靠性高,功能強大,完全能勝任移植和調試U-Boot。另外,網(wǎng)上也有不少關(guān)于BDI2000調試方面的參考文檔。
⑥如果在參考開(kāi)發(fā)板上移植U-Boot,可能需要移除目標板上已有的BOOT LOADER??梢愿鶕迳螧OOTLOADER的說(shuō)明文檔,先著(zhù)手解決在移除當前BOOT LOADER的情況下,如何進(jìn)行恢復。以便今后在需要場(chǎng)合能重新裝入原先的BOOTLOADER。
5 U-Boot移植方法
當前,對于U-Boot的移植方法,大致分為兩種。一種是先用BDI2000創(chuàng )建目標板初始運行環(huán)境,將U-Boot鏡像文件u-boot.bin下載到目標板RAM中的指定位置,然后,用BDI2000進(jìn)行跟蹤調試。其好處是不用將U-Boot鏡像文件燒寫(xiě)到FLASH中去。但弊端在于對移植開(kāi)發(fā)人員的移植調試技能要求較高,BDI2000的配置文件較為復雜。另外一種方法是用BDI2000先將U-Boot鏡像文件燒寫(xiě)到FLASH中去,然后利用GDB和BDI2000進(jìn)行調試。這種方法所用BDI2000的配置文件較為簡(jiǎn)單,調試過(guò)程與U-Boot移植后運行過(guò)程相吻合,即U-Boot先從FLASH中運行,再重載至RAM中相應位置,并從那里正式投入運行。唯一感到有些麻煩的就是需要不斷燒寫(xiě)FLASH。但考慮到FLASH常規擦寫(xiě)次數基本為10萬(wàn)次左右,作為移植U-Boot,不會(huì )占用太多的次數,應該不會(huì )為FLASH燒寫(xiě)有什么擔憂(yōu)。同時(shí),W. D本人也極力推薦使用后一種方法。筆者建議,除非U-Boot移植資深人士或有強有力的技術(shù)支持,建議采用第二種移植方法。
6 U-Boot移植主要修改的文件
從移植U-Boot最小要求-U-Boot能正常啟動(dòng)的角度出發(fā),主要考慮修改如下文件:
① <目標板>.h頭文件,如include/configs/RPXlite.h??梢允荱-Boot源碼中已有的目標板頭文件,也可以是新命名的配置頭文件;大多數的寄存器參數都是在這一文件中設置完成的;
② <目標板>.c文件,如board/RPXlite/RPXlite.c。它是SDRAM的驅動(dòng)程序,主要完成SDRAM的UPM表設置,上電初始化。
③ FLASH的驅動(dòng)程序,如board/RPXlite/flash.c,或common/cfi_flash.c??稍趨⒖家延蠪LASH驅動(dòng)的基礎上,結合目標板FLASH數據手冊,進(jìn)行適當修改;
④ 串口驅動(dòng),如修改cpu/mpc8xx/serial.c串口收發(fā)器芯片使能部分。
7 U-Boot移植要點(diǎn)
①BDI2000的配置文件。如果采用第二種移植方法,即先燒入FLASH的方法,配置項只需很少幾個(gè),就可以進(jìn)行U-Boot的燒寫(xiě)與調試了。對PPC8xx系列的主板,可參考DULG文檔中TQM8xx的配置文件進(jìn)行相應的修改。下面,筆者以美國Embedded Planet公司的RPXliteDW板為例,給出在嵌入式Linux交叉開(kāi)發(fā)環(huán)境下的BDI2000參考配置文件以作參考:
; bdiGDB configuration file for RPXlite DW or LITE_DW
; --------------------------------------------
[INIT]
; init core register
WSPR 149 0x2002000F ;DER : set debug enable register
; WSPR 149 0x2006000F ;DER : enable SYSIE for BDI flash program
WSPR 638 0xFA200000 ;IMMR : internal memory at 0xFA200000
WM32 0xFA200004 0xFFFFFF89 ;SYPCR
[TARGET]
CPUCLOCK 40000000 ;the CPU clock rate after processing the init list
BDIMODE AGENT ;the BDI working mode (LOADONLY | AGENT)
BREAKMODE HARD ;SOFT or HARD, HARD uses PPC hardware breakpoints
[HOST]
IP 173.60.120.5
FILE uImage.litedw
FORMAT BIN
LOAD MANUAL ;load code MANUAL or AUTO after reset
DEBUGPORT 2001
START 0x0100
[FLASH]
CHIPTYPE AM29BX8 ;;Flash type (AM29F | AM29BX8 | AM29BX16 | I28BX8 | I28BX16)
CHIPSIZE 0x400000 ;;The size of one flash chip in bytes
BUSWIDTH 32 ;The width of the flash memory bus in bits (8 | 16 | 32)
WORKSPACE 0xFA202000 ; RAM buffer for fast flash programming
FILE u-boot.bin ;The file to program
FORMAT BIN 0x00000000
ERASE 0x00000000 BLOCK
ERASE 0x00008000 BLOCK
ERASE 0x00010000 BLOCK
ERASE 0x00018000 BLOCK
[REGS]
DMM1 0xFA200000
FILE reg823.def
②U-Boot移植參考板。這是進(jìn)行U-Boot移植首先要明確的??梢愿鶕繕税迳螩PU、FLASH、SDRAM的情況,以盡可能相一致為原則,先找出一個(gè)與所移植目標板為同一個(gè)或同一系列處理器的U-Boot支持板為移植參考板。如RPXliteDW板可選擇U-Boot源碼中RPXlite板作為U-Boot移植參考板。對U-Boot移植新手,建議依照循序漸進(jìn)的原則,目標板文件名暫時(shí)先用移植參考板的名稱(chēng),在逐步熟悉U-Boot移植基礎上,再考慮給目標板重新命名。在實(shí)際移植過(guò)程中,可用Linux命令查找移植參考板的特定代碼,如grep –r RPXlite ./可確定出在U-Boot中與RPXlite板有關(guān)的代碼,依此對照目標板實(shí)際進(jìn)行屏蔽或修改。同時(shí)應不局限于移植參考板中的代碼,要廣泛借鑒U-Boot中已有的代碼更好地實(shí)現一些具體的功能。
③U-Boot燒寫(xiě)地址。不同目標板,對U-Boot在FLASH中存放地址要求不盡相同。事實(shí)上,這是由處理器中斷復位向量來(lái)決定的,與主板硬件相關(guān),對MPC8xx主板來(lái)講,就是由硬件配置字(HRCW)決定的。也就是說(shuō),U-Boot燒寫(xiě)具體位置是由硬件決定的,而不是程序設計來(lái)選擇的。程序中相應U-Boot起始地址必須與硬件所確定的硬件復位向量相吻合;如RPXlite DW板的中斷復位向量設置為0x00000100。因此, U-Boot的BIN鏡像文件必須燒寫(xiě)到FLASH的起始位置。事實(shí)上,大多數的PPC系列的處理器中斷復位向量是0x00000100和0xfff00100。這也是一般所說(shuō)的高位啟動(dòng)和低位啟動(dòng)的BOOTLOADER所在位置??赏ㄟ^(guò)修改U-Boot源碼<目標板>.h頭文件中CFG_MONITOR_BASE和board/<目標板>/config.mk中的TEXT_BASE的設置來(lái)與硬件配置相對應。
④CPU寄存器參數設置。根據處理器系列、類(lèi)型不同,寄存器名稱(chēng)與作用有一定差別。必須根據目標板的實(shí)際,進(jìn)行合理配置。一個(gè)較為可行和有效的方法,就是借鑒參考移植板的配置,再根據目標板實(shí)際,進(jìn)行合理修改。這是一個(gè)較費功夫和考驗耐力的過(guò)程,需要仔細對照處理器各寄存器定義、參考設置、目標板實(shí)際作出選擇并不斷測試。MPC8xx處理器較為關(guān)鍵的寄存器設置為SIUMCR、PLPRCR、SCCR、BRx、ORx。
⑤串口調試。能從串口輸出信息,即使是亂碼,也可以說(shuō)U-Boot移植取得了實(shí)質(zhì)性突破。依據筆者調試經(jīng)歷,串口是否有輸出,除了與串口驅動(dòng)相關(guān)外,還與FLASH相關(guān)的寄存器設置有關(guān)。因為U-Boot是從FLASH中被引導啟動(dòng)的,如果FLASH設置不正確,U-Boot代碼讀取和執行就會(huì )出現一些問(wèn)題。因此,還需要就FLASH的相關(guān)寄存器設置進(jìn)行一些參數調試。同時(shí),要注意串口收發(fā)芯片相關(guān)引腳工作波形。依據筆者調試情況,如果串口無(wú)輸出或出現亂碼,一種可能就是該芯片損壞或工作不正常。
⑥ 與啟動(dòng) FLASH相關(guān)的寄存器BR0、OR0的參數設置。應根據目標板FLASH的數據手冊與BR0和OR0的相關(guān)位含義進(jìn)行合理設置。這不僅關(guān)系到FLASH能否正常工作,而且與串口調試有直接的關(guān)聯(lián)。
⑦關(guān)于CPLD電路。目標板上是否有CPLD電路絲毫不會(huì )影響U-Boot的移植與嵌入式操作系統的正常運行。事實(shí)上,CPLD電路是一個(gè)集中將板上電路的一些邏輯關(guān)系可編程設置的一種實(shí)現方法。其本身所起的作用就是實(shí)現一些目標板所需的脈沖信號和電路邏輯,其功能完全可以用一些邏輯電路與CPU口線(xiàn)來(lái)實(shí)現。
⑧SDRAM的驅動(dòng)。串口能輸出以后,U-Boot移植是否順利基本取決于SDRAM的驅動(dòng)是否正確。與串口調試相比,這部分工作更為核心,難度更大。MPC8xx目標板SDRAM驅動(dòng)涉及三部分。一是相關(guān)寄存器的設置;二是UPM表;三是SDRAM上電初始化過(guò)程。任何一部分有問(wèn)題,都會(huì )影響U-Boot、嵌入式操作系統甚至應用程序的穩定、可靠運行。所以說(shuō),SDRAM的驅動(dòng)不僅關(guān)系到U-Boot本身能否正常運行,而且還與后續部分相關(guān),是相當關(guān)鍵的部分。
⑨補充功能的添加。在獲得一個(gè)能工作的U-Boot后,就可以根據目標板和實(shí)際開(kāi)發(fā)需要,添加一些其它功能支持。如以太網(wǎng)、LCD、NVRAM等。與串口和SDRAM調試相比,在已有基礎之上,這些功能添加還是較為容易的。大多只是在參考現有源碼的基礎上,進(jìn)行一些修改和配置。
另外,如果在自主設計的主板上移植U-Boot,那么除了考慮上述軟件因素以外,還需要排查目標板硬件可能存在的問(wèn)題。如原理設計、PCB布線(xiàn)、元件好壞。在移植過(guò)程中,敏銳判斷出故障態(tài)是硬件還是軟件問(wèn)題,往往是關(guān)系到項目進(jìn)度甚至移植成敗的關(guān)鍵,相應難度會(huì )增加許多。
完成一個(gè)目標板的移植工作后,可考慮將移植結果以補丁的形式發(fā)送到U-Boot用戶(hù)郵件列表,尤其是一些參考板的移植結果。這是使用GPL代碼并遵循GPL條款的體現??稍陂喿xREADME相關(guān)補丁說(shuō)明的基礎上,添加適當的注釋?zhuān)瑢⒆约毫腥牍鈽s榜(CREDITS)。如果愿意承擔所移植板的后續更新工作,可以考慮加入維護人員(MAINTAINERS)開(kāi)發(fā)隊伍行列。
誠然,在實(shí)際的U-Boot移植中無(wú)法避免地會(huì )遇到一些難以預料的問(wèn)題,甚至出現倒退,尤其U-Boot移植新手,更會(huì )平添諸多難度。但筆者相信,在逐步熟悉U-Boot移植方法、過(guò)程中,隨著(zhù)自身經(jīng)驗的不斷積累,加之有眾多熱衷于開(kāi)放源碼人士的鼎立相助,堅冰終會(huì )消融。