吳 磊 皮 智 袁宗勝
(北方工業(yè)大學(xué)計(jì)算機(jī)學(xué)院 北京 100144)
?
一種基于S3C6410的BootLoader的設(shè)計(jì)與實(shí)現(xiàn)
吳磊皮智袁宗勝
(北方工業(yè)大學(xué)計(jì)算機(jī)學(xué)院北京 100144)
引導(dǎo)加載程序(BootLoader)是嵌入式系統(tǒng)開(kāi)發(fā)的關(guān)鍵技術(shù)之一,主要用于建立操作系統(tǒng)的運(yùn)行環(huán)境。針對(duì)BootLoader嚴(yán)重依賴于硬件實(shí)現(xiàn)的問(wèn)題,提出一種基于“NAND Flash+TFTP”存儲(chǔ)下載方式的BootLoader設(shè)計(jì)方法,并采用OK6410開(kāi)發(fā)板對(duì)該BootLoader進(jìn)行實(shí)驗(yàn)驗(yàn)證。實(shí)驗(yàn)結(jié)果表明該BootLoader運(yùn)行良好且穩(wěn)定。該設(shè)計(jì)方法可以廣泛地應(yīng)用到嵌入式系統(tǒng)和其他的處理器中。
引導(dǎo)加載程序嵌入式系統(tǒng)S3C6410
嵌入式系統(tǒng)是以應(yīng)用為中心,以計(jì)算機(jī)技術(shù)為基礎(chǔ),軟硬件可裁剪,適應(yīng)于對(duì)功能、可靠性、成本、體積和功耗等嚴(yán)格要求的專用計(jì)算機(jī)系統(tǒng)[1]。在工業(yè)控制、智能儀器、醫(yī)療設(shè)備和機(jī)器人等方面得到廣泛的應(yīng)用,而在嵌入式系統(tǒng)開(kāi)發(fā)設(shè)計(jì)當(dāng)中,尤為重要的就是引導(dǎo)加載程序的設(shè)計(jì)。
嵌入式系統(tǒng)從軟件操作方面分析,一般分為四個(gè)層次: 引導(dǎo)加載程序、系統(tǒng)內(nèi)核、文件系統(tǒng)和應(yīng)用程序。其中引導(dǎo)加載程序就是BootLoader,它是嵌入式系統(tǒng)開(kāi)發(fā)的難點(diǎn)之一,同時(shí)也是嵌入式系統(tǒng)運(yùn)行的一個(gè)基本前提,沒(méi)有這段與硬件緊密相連的代碼,再?gòu)?qiáng)大的內(nèi)核也發(fā)揮不了作用[3]。
1.1硬件結(jié)構(gòu)簡(jiǎn)介
本BootLoader硬件實(shí)驗(yàn)環(huán)境采用飛凌公司的OK6410開(kāi)發(fā)板,它采用了三星公司的ARM11處理器S3C6410。S3C6410是一款高性價(jià)比和低功耗的RSIC處理器,具備視頻圖像處理能力。并且能夠穩(wěn)定地運(yùn)行于667MHz的主頻以上,支持Mobile DDR和多種NAND Flash。OK6410開(kāi)發(fā)板上集成了多種高端接口,如USB、SD卡、液晶屏和以太網(wǎng)等,主要硬件構(gòu)成如圖1所示。
圖1 主要硬件構(gòu)成
1.2BootLoader開(kāi)發(fā)方法與工具
采用交叉開(kāi)發(fā)模式,即程序的編寫(xiě)和編譯在裝有Red Hat Enterprise Linux6.3的PC宿主機(jī)上完成,而交叉編譯產(chǎn)生的bin文件在OK6410目標(biāo)板上運(yùn)行。其中選用arm-linux-gcc-4.3.2工具鏈作為開(kāi)發(fā)工具,它包括了編譯器、鏈接器和匯編器等開(kāi)發(fā)工具[5-7],使用Makefile文件來(lái)管理整個(gè)工程,并選用JTAG進(jìn)行下載并調(diào)試BootLoader,另外選用交叉網(wǎng)線來(lái)下載嵌入式linux內(nèi)核映像文件(zImage),系統(tǒng)開(kāi)發(fā)框圖如圖2所示。
圖2 系統(tǒng)開(kāi)發(fā)框圖
2.1S3C6410啟動(dòng)流程
S3C6410的啟動(dòng)流程如圖3所示。
圖3 S3C6410啟動(dòng)流程
S3C6410的啟動(dòng)流程是IROM初始化,IROM中固化了軟件,稱為BootLoader0,是0階段的BootLoader,該BL0 執(zhí)行初始化時(shí)鐘,D-TCM,設(shè)備特殊控制器,引導(dǎo)設(shè)備;加載BL1到Stepping Stone(墊腳石),將放在nandflash中的BootLoader1(即 BootLoader最前面的8K)拷貝到Stepping Stone中;執(zhí)行BL1:BL1初始化系統(tǒng)時(shí)鐘,UART,SDRAM,Stepping Stone執(zhí)行完8K BootLoader后,將剩余的BootLoader(BL2)拷貝到SDRAM中運(yùn)行;執(zhí)行BL2:跳轉(zhuǎn)到SDRAM中執(zhí)行BL2,加載內(nèi)核。
2.2BootLoader的總體設(shè)計(jì)
在嵌入式操作系統(tǒng)中,BootLoader運(yùn)行在操作系統(tǒng)內(nèi)核之前。主要可以初始化一些相關(guān)的硬件設(shè)備、建立內(nèi)存空間的映射圖,將系統(tǒng)的軟硬件環(huán)境帶到一個(gè)合適狀態(tài),為最終調(diào)用操作系統(tǒng)內(nèi)核準(zhǔn)備好正確的環(huán)境[2-4]。
BootLoader的啟動(dòng)通??梢苑譃榈谝浑A段和第二階段,第一個(gè)階段主要包含依賴于CPU的系統(tǒng)結(jié)構(gòu),比如設(shè)備初始化代碼等,通常都用匯編語(yǔ)言來(lái)實(shí)現(xiàn)。第二階段通常用C語(yǔ)言來(lái)實(shí)現(xiàn),以便實(shí)現(xiàn)更復(fù)雜的功能,也能使程序有更好的可讀性和可移植性,主要任務(wù)有一些相關(guān)硬件初始化,檢測(cè)系統(tǒng)的內(nèi)存映射和加載linux內(nèi)核等工作。BootLoader的總體設(shè)計(jì)流程如圖4所示。
圖4 BootLoader的總體設(shè)計(jì)流程圖
3.1核心初始化
核心初始化階段的任務(wù)主要包括異常向量表,設(shè)置svc模式,關(guān)閉看門(mén)狗,關(guān)閉中斷和外設(shè)基地址初始化。在ARM體系結(jié)構(gòu)中,異常向量表放在上電后映射在從0x00000000開(kāi)始的32個(gè)字節(jié)的連續(xù)物理地址上,它的作用是指定了各種異常處理程序的入口地址[2]。因?yàn)槊總€(gè)異常只對(duì)應(yīng)4個(gè)字節(jié),不能放下整個(gè)處理程序,用來(lái)跳轉(zhuǎn)到相應(yīng)程序。具體代碼如下:
b reset
//復(fù)位異常向量,地址為0x00000000
ldr pc,_undefined_instruction
//未定義指令異常,跳轉(zhuǎn)至未定義異常服務(wù)程序
ldr pc,_software_interrupt
//軟中斷異常,跳轉(zhuǎn)至軟中斷異常服務(wù)程序
ldr pc,_prefetch_interrupt
//指令預(yù)取中止異常,跳轉(zhuǎn)至指令異常預(yù)取中止異常服務(wù)程序
ldr pc,_data_abort
//數(shù)據(jù)訪問(wèn)中止異常,跳轉(zhuǎn)至數(shù)據(jù)訪問(wèn)中止異常服務(wù)程序
ldr pc,_not_used
//保留,占用4個(gè)字節(jié)
ldr pc,_irq
//IRQ異常,跳轉(zhuǎn)至普通中斷服務(wù)程序
ldr pc,_fiq
//FIQ異常,跳轉(zhuǎn)至快速中斷異常服務(wù)程序
svc模式屬于特權(quán)模式,可以訪問(wèn)一些受控資源,并且比sys模式還多了些自己模式下的影子寄存器。相對(duì)sys模式來(lái)說(shuō),可以訪問(wèn)資源的能力相同,但是擁有更多的硬件資源。從BootLoader方面考慮,設(shè)置svv模式為了初始化系統(tǒng)相關(guān)硬件資源和獲取盡量多的權(quán)限。具體代碼如下:
set_svc:
//設(shè)置svc模式
mrs r0,cpsr
bic r0,r0,#0x1f
//清除低5位
orr r0,r0,#0xd3
//設(shè)置為svc模式,并且屏蔽irq和fiq中斷
msr cpsr,r0
mov pc,lr
//關(guān)閉看門(mén)狗
#define pwatchdog 0x7e004000
disable_watchdog:
ldr r0,=pwatchdog
//ldr這里是偽指令,將地址保存到r0中
mov r1,#0x0
str r1,[r0]
mov pc,lr
//關(guān)閉中斷,將以下2個(gè)地址全部置1
disable_interrupt:
mvn r1,#0x0
ldr r0,=0x71200014
str r1,[r0]
ldr r0,=0x71300014
str r1,[r0]
mov pc,lr
//關(guān)閉mmu和cache
disable_mmu:
mcr p15,0,r0,c7,c7,0
//使Icache和Dcache失效
mrc p15,0,r0,c1,c0,0
//關(guān)閉Icache,Dcache和mmu
bic r0,r0,#0x00000007
mcr p15,0,r0,c1,c0,0
mov pc,lr
//外設(shè)基地址初始化
set_peri_port:
ldr r0, =0x70000000
orr r0, r0, #0x13
mcr p15,0,r0,c15,c2,4
mov pc, lr
3.2點(diǎn)亮LED
點(diǎn)亮LED是為了調(diào)試代碼用。具體代碼如下:
#define GPMCON 0x7F008820
//這里的地址根據(jù)開(kāi)發(fā)板硬件資源的不同而設(shè)置不同
#define GPMDAT 0x7F008824
light_led:
ldr r1,=GPMCON
//控制寄存器
ldr r0,=0x1111
str r0,[r1]
ldr r1,=GPMDAT
//數(shù)據(jù)寄存器
ldr r0,=0xe
//點(diǎn)亮一個(gè)led燈,觀察調(diào)試使用
str r0,[r1]
mov pc,lr
3.3時(shí)鐘初始化
S3C6410可以使用外部晶振和外部時(shí)鐘兩種方式輸入時(shí)鐘信號(hào),默認(rèn)的工作主頻為12 MHz(晶振頻率),S3C6410有三個(gè)PLL,分別為APLL、MPLL和EPLL。其中APLL產(chǎn)生ACLK,給ARM core使用。MPLL產(chǎn)生HCLK和PCLK。EPLL產(chǎn)生特殊的時(shí)鐘,比如為USB提供48MHz時(shí)鐘。時(shí)鐘初始化流程:(1)設(shè)置lock time(不需要設(shè)置,保持默認(rèn)值即可);(2)設(shè)置分頻系數(shù);(3)設(shè)置CPU到異步工作模式;(4)設(shè)置FCLK。具體代碼如下:
//設(shè)置分頻系數(shù)
#define CLK_DIV 0 0x7e00f020
#define DIV_VAL (0x1<<0)|(0x1<<9)|(0x1<<8)|(0x3<<12)
//設(shè)置為66MHz
clock_init:
ldr r0,=CLK_DIV0
ldr r1,= DIV_VAL
str r1,[r0]
mov pc,lr
//設(shè)置CPU為異步模式
//這里可以直接設(shè)置OTHERS寄存器來(lái)完成設(shè)置異步模式
#define OTHERS 0x7e00f900
ldr r0,=OTHERS
ldr r1,[r0]
bic r1,r1,#0xc0 //這里將第六位也設(shè)置為0的主要目的是當(dāng)
//選擇為異步模式的時(shí)候,應(yīng)選取MPLL的輸出
str r1,[r0]
//設(shè)置FCL
#define APLL_CON 0x7e00f00c
#define MPLL_CON 0x7e00f010
#define PLL_VAL ((1<<31)|(266<<16)|(3<<8)|(1<<0))
ldr r0,=APLL_CON
ldr r1,=PLL_VAL
str r1,[r0]
ldr r0,=MPLL_CON
ldr r1,=PLL_VAL
str r1,[r0]
//為了必須保證設(shè)置APLL和MPLL作為輸出,這里還需要設(shè)置
//CLK_SRC的低2位為1
#define CLK_SRC 0x7e00f01c
ldr r0,=CLK_SRC
mov r1,#0x3
str r1,[r0]
3.4內(nèi)存初始化
S3C6410處理器擁有32位地址總線,其尋址空間為4 GB。其中高2 GB為保留區(qū),低2 GB區(qū)域又可劃分為2部分:主存儲(chǔ)區(qū)和外設(shè)區(qū)。其地址空間和主存儲(chǔ)區(qū)如圖5所示。
圖5 地址空間和主存儲(chǔ)區(qū)
內(nèi)存初始化的這一過(guò)程主要是指對(duì) DRAM、FLASH 的存儲(chǔ)設(shè)備的地址范圍、數(shù)據(jù)寬度以及 DRAM 的刷新率進(jìn)行設(shè)備,芯片不同,設(shè)置也不同[8-10]。
3.5將nandflash中的BootLoader復(fù)制至內(nèi)存
OK6410開(kāi)發(fā)板上電之后,會(huì)運(yùn)行SROM中的BootLoader0(由三星公司出廠設(shè)置),由S3C6410啟動(dòng)流程圖3可以看出,S3C6410的Stepping Stone(墊腳石)只有8 KB,由于8 KB容量太小,不足以完成第二階段的任務(wù),因此需要借助這8 KB的BootLoader1將nandflash中的所有的BootLoader復(fù)制到內(nèi)存運(yùn)行。將nandflash中的BootLoader復(fù)制至內(nèi)存的具體代碼如下:
copy_to_ram:
ldr r0,=0x0c000000
//起點(diǎn)
ldr r1,=0x50008000
//終點(diǎn)
add r3,r0,#1024*8
//復(fù)制8KB
copy_loop:
//循環(huán)復(fù)制至0x50008000
ldr r2,[r0],#4
str r2,[r1],#4
cmp r0,r3
bne copy_loop
mov pc,lr
3.6C語(yǔ)言環(huán)境初始化
OK6410的內(nèi)存大小是256 MB,64 MB的內(nèi)存對(duì)于一個(gè)精簡(jiǎn)通用的BootLoader足夠使用,即設(shè)置堆棧寄存器(SP)的地址為0x50000000+64 MB = 0x54000000,棧初始化的代碼如下:
init_stack:
ldr sp,=0x54000000
mov pc,lr
BSS(Block Started by Symbol)通常是指用來(lái)存放程序的未初始化的全局變量和靜態(tài)變量的一塊內(nèi)存區(qū)域。BSS段初始化就是給該段清零,方便以后使用BSS段的數(shù)據(jù),當(dāng)定義變量時(shí),就會(huì)初始化該變量為零。具體代碼如下:
//初始化BSS段
clear_bss:
ldr r0,=bss_start
//BSS起始地址
ldr r1,=bss_end
//BSS終止地址
cmp r0,r1
moveq pc,lr
clean_loop:
//循環(huán)清除
mov r2,#0;
str r2,[r0],#4
cmp r0,r1
bne clean_loop
mov pc,lr
//跳轉(zhuǎn)至C代碼
從SRAM調(diào)到內(nèi)存中,直接使用絕對(duì)跳轉(zhuǎn)方式。需要在myboot工程下面新建一個(gè)main.c文件,具體代碼如下:
int myboot_main()
//main函數(shù)
{
return 0;
}
修改匯編start.S和Makefile文件,在原start.S里面的reset下添加ldr pc,=mymain 用來(lái)跳轉(zhuǎn)至C語(yǔ)言環(huán)境,myboot_main是一個(gè)函數(shù)地址,在原Makefile文件的依賴文件里面添加main.o即可,通過(guò)在myboot_main中添加點(diǎn)亮LED的代碼,測(cè)試LED點(diǎn)亮,說(shuō)明程序已經(jīng)跳轉(zhuǎn)至myboot_main。
4.1MMU初始化
在BootLoader第一階段的設(shè)計(jì)中關(guān)閉了MMU,因此物理地址和虛擬地址是相等的,在Linux系統(tǒng)中不管是內(nèi)核還是應(yīng)用程序,都是使用的虛擬地址,而MMU的作用是自動(dòng)進(jìn)行虛擬地址到物理地址的轉(zhuǎn)化,需要找到一級(jí)頁(yè)表,而一級(jí)頁(yè)表的基地址保存在CP15的C2寄存器中。本BootLoader按照段式方式來(lái)進(jìn)行映射,即一級(jí)頁(yè)表項(xiàng)中最后兩位為‘10’。段式方式轉(zhuǎn)換如圖6所示,由高12位的段基址和低20位的偏移地址組成。
圖6 段式方式轉(zhuǎn)換
MMU的初始化具體代碼如下:
void enable_mmu()
//使能MMU
void creat_page_table()
//創(chuàng)建頁(yè)表和內(nèi)存映射
{
unsigned long* ttb = (unsigned long*)0x50000000;
//頁(yè)表存放在內(nèi)存起始地址
unsigned long vaddr,paddr;
vaddr = 0xA0000000;
//虛擬地址
paddr = 0x7F000000;
//物理地址
*(ttb + (vaddr>>20)) = (paddr&0xfff00000) | (MMU_SECDESC);
vaddr = 0x50000000;
paddr = 0x50000000;
while(vaddr < 0x54000000) //內(nèi)存映射64MB,地址范圍是
//(0x50000000-0x54000000)
{
*(ttb + (vaddr>>20)) = (paddr&0xfff00000) | (MMU_SECDESC_WB);
vaddr += 0x100000;
paddr += 0x100000;
}
}
由于MMU初始化后,對(duì)應(yīng)需要修改LED的控制寄存器和數(shù)據(jù)寄存器的地址,具體代碼如下:
#define GPKCON (volatile unsigned long*)0xA0008820
//使用的虛擬地址
#define GPKDAT (volatile unsigned long*)0xA0008824
//使用的虛擬地址
*(GPKCON) = 0x1111;
*(GPKDAT) = 0xe;
通過(guò)觀察LED來(lái)驗(yàn)證MMU初始化的代碼。如果LED能亮起來(lái),說(shuō)明MMU這部分代碼沒(méi)有問(wèn)題;否則,MMU不起作用。
4.2相關(guān)硬件初始化
在BootLoader第一階段中,ARM設(shè)置在svc的模式下,如果在相關(guān)硬件初始化的過(guò)程中需要用到中斷的時(shí)候,須將ARM設(shè)置為irq模式,因此需要重新設(shè)置堆棧。具體代碼如下:
//設(shè)置堆棧
init_stack:
msr cpsr_c, #0xd2
ldr sp, =0x53000000
//初始化r13_irq 中斷響應(yīng)的地址
msr cpsr_c, #0xd3
ldr sp, =0x54000000
//初始化r13_svc
mov pc,lr
針對(duì)硬件資源不同的開(kāi)發(fā)板,針對(duì)性地做一些硬件的初始化,這里主要包括以下幾點(diǎn)。
(1) 串口控制臺(tái)建立,在本BootLoader中,需要用戶自己手動(dòng)在串口控制臺(tái)輸入選擇項(xiàng)來(lái)下載Linux內(nèi)核,通過(guò)串口來(lái)交互,移植printf和scanf函數(shù)等。
(2) DMA解決了CPU每次從內(nèi)存當(dāng)中拷貝很大的數(shù)據(jù)到串口,提高CPU的效率,可以初始化DMA。
(3) 硬件資源還包括有LCD(OK6410用的TFT液晶屏)和觸摸屏(OK6410用的電阻屏),根據(jù)不同的硬件資源做一些適當(dāng)?shù)男薷摹?/p>
4.3網(wǎng)卡搭建
根據(jù)硬件資源的不同,初始化DM9000的代碼也有所不同,本BootLoader需要通過(guò)交叉網(wǎng)線來(lái)下載Linux內(nèi)核,通過(guò)ARP協(xié)議的實(shí)現(xiàn)來(lái)測(cè)試DM9000是否正常工作。
聲明以太網(wǎng)包和ARP包的結(jié)構(gòu)體代碼如下:
typedef struct eth_hdr
//以太網(wǎng)包
{
u8 d_mac[6];
//目的MAC地址
u8 s_mac[6];
//源MAC地址
u16 type;
//類型
}ETH_HDR;
typedef struct arp_hdr
//ARP包
{
ETH_HDR ethhdr;
//以太網(wǎng)包
u16 hwtype;
//硬件類型
u16 protocol;
//協(xié)議類型
u8 hwlen;
//硬件地址長(zhǎng)度
u8 protolen;
//協(xié)議地址長(zhǎng)度
u16 opcode;
//OP=1 表示ARP請(qǐng)求 OP=2 表示ARP應(yīng)答
u8 smac[6];
//發(fā)送端以太網(wǎng)地址
u8 sipaddr[4];
//發(fā)送端IP地址
u8 dmac[6];
//目的以太網(wǎng)地址
u8 dipaddr[4];
//目的IP地址
}ARP_HDR;
主要的函數(shù)有2個(gè)如下:
void arp_request(); //發(fā)送ARP請(qǐng)求包,注意網(wǎng)絡(luò)中的字節(jié)序問(wèn)
//題,網(wǎng)絡(luò)字節(jié)序是大端傳輸
u8 arp_process(u8 *buf, u32 len);
//解析ARP應(yīng)答包,提取MAC地址
測(cè)試網(wǎng)卡的搭建如下,開(kāi)發(fā)板OK6410通過(guò)向宿主機(jī)發(fā)送ARP請(qǐng)求,宿主機(jī)回復(fù)一個(gè)ARP應(yīng)答包,開(kāi)發(fā)板即能知道宿主機(jī)的MAC地址,流程如圖7所示。
圖7 ARP通信流程
開(kāi)發(fā)板OK6410的IP地址設(shè)置為10.5.114.107,MAC地址設(shè)置為09:08:07:06:05:04,宿主機(jī)的IP地址和物理地址通過(guò)ifconfig命令可以查看如圖8所示:IP地址為10.5.114.109,MAC地址為00:0C:29:45:FC:6A。
圖8 宿主機(jī)PC的IP地址和MAC地址
實(shí)驗(yàn)下載該BootLoader,從nandflash啟動(dòng),OK6410循環(huán)發(fā)送ARP請(qǐng)求,顯示數(shù)據(jù)如圖9所示:MAC地址的顯示和圖7中SecureCRT打印的結(jié)果一致,實(shí)驗(yàn)說(shuō)明OK6410開(kāi)發(fā)板可以正確獲取到宿主機(jī)的MAC地址。
圖9 SecureCRT串口顯示宿主機(jī)PC的IP和MAC
通過(guò)Wireshark抓包如圖10所示:Wireshark正確抓到ARP的包正確,說(shuō)明OK6410能正確獲取到宿主機(jī)PC的MAC地址,驗(yàn)證了網(wǎng)卡搭建的正確性。
圖10 Wireshark抓取的ARP包
4.4移植TFTP客戶端
通過(guò)TFTP客戶端下載linux內(nèi)核至開(kāi)發(fā)板OK6410,在開(kāi)發(fā)板下載之前發(fā)送一個(gè)ARP請(qǐng)求來(lái)獲取宿主機(jī)PC的MAC地址。TFTP的通信流程如圖11所示。
圖11 TFTP通信流程
聲明IP報(bào)文、UDP包以及TFTP包的結(jié)構(gòu)體代碼如下:
typedef struct ip_hdr
//IP報(bào)文
{
ETH_HDR ethhdr;
//以太網(wǎng)包
u8 vhl;
//版本和首部長(zhǎng)度
u8 tos;
//服務(wù)級(jí)別
u16 len;
//報(bào)文長(zhǎng)度
u16 ipid;
//標(biāo)識(shí)
u16 ipoffset;
//片位移
u8 ttl;
//生存時(shí)間
u8 proto;
//上一層協(xié)議類型
u16 ipchksum;
//校驗(yàn)和
u8 srcipaddr[4];
//源IP地址
u8 destipaddr[4];
//目的IP地址
}IP_HDR;
typedef struct udp_hdr
//UDP包
{
IP_HDR iphdr;
//IP報(bào)文
u16 sport;
//源端口號(hào)
u16 dport;
//目的端口號(hào)
u16 len;
//長(zhǎng)度
u16 udpchksum;
//校驗(yàn)和
}UDP_HDR;
typedef struct tftp_package
{
u16 opcode;
//操作碼
u16 blocknum;
//塊編號(hào)
u8 data[0];
//數(shù)據(jù)
}TFTP_PAK;
主要的函數(shù)有:
void tftp_send_request(const char *filename);
//用來(lái)發(fā)送TFTP請(qǐng)求
void tftp_send_ack(u16 blocknum);
//用來(lái)發(fā)送TFTP ACK
void tftp_process(u8 *buf, u32 len, u16 port);
//處理TFTP請(qǐng)求
TFTP測(cè)試結(jié)果如下:在Linux宿主機(jī)上面配置好TFTP服務(wù)器,OK6410開(kāi)發(fā)板通過(guò)交叉網(wǎng)線下載zImage(zImage存放在linux宿主機(jī)上面配置好的TFTP服務(wù)器的目錄下)文件,SecureCRT串口顯示如圖12所示和 Wireshark抓包如圖13所示。
圖12 SecureCRT串口顯示TFTP下載完成
圖13 Wireshark抓取的TFTP包
通過(guò)SecureCRT串口顯示和wireshark抓包顯示可以看出OK6410開(kāi)發(fā)板能正確發(fā)送TFTP請(qǐng)求,并且能正確解析和下載zImage文件,實(shí)驗(yàn)說(shuō)明OK6410的TFTP客戶端正確將Linux內(nèi)核下載至nandflash。
4.5移植bootm命令
TFTP客戶端下載完Linux內(nèi)核后,需要啟動(dòng)該內(nèi)核,實(shí)現(xiàn)一個(gè)命令來(lái)啟動(dòng)該Linux內(nèi)核。這個(gè)bootm命令用于啟動(dòng)一個(gè)操作系統(tǒng)映像。它會(huì)從映像文件的頭部取得一些信息,這些信息包括:映像文件的基于的CPU架構(gòu)、其操作系統(tǒng)類型、映像的類型、壓縮方式、映像文件在內(nèi)存中的加載地址、映像文件運(yùn)行的入口地址、映像文件名等。緊接著bootm將映像加載到指定的地址,跳轉(zhuǎn)至入口地址進(jìn)入Linux內(nèi)核。主要的函數(shù)實(shí)現(xiàn)如下:
#define SDRAM_KERNEL_START 0x51000000 //linux內(nèi)核起始地址
theKernel = (void (*)(int, int, unsigned int ))SDRAM_KERNEL_START;
//指向起始地址
void boot_linux();
//用來(lái)處理啟動(dòng)linux內(nèi)核,這一過(guò)程需要設(shè)計(jì)
//啟動(dòng)參數(shù),包括核心啟動(dòng)參數(shù),內(nèi)存參數(shù),命令行參數(shù)和結(jié)束標(biāo)志等
setup_core_tag();
//設(shè)置核心啟動(dòng)參數(shù)
setup_mem_tag();
//設(shè)置內(nèi)存參數(shù)
setup_cmdline_tag();
//設(shè)置命令行參數(shù)
setup_end_tag();
//設(shè)置結(jié)束標(biāo)志
4.6BootLoader測(cè)試
燒寫(xiě)B(tài)ootLoader,然后從nandflash啟動(dòng),TFTP客戶端下載完Linux內(nèi)核后,通過(guò)SecureCRT串口輸入數(shù)字3,即可正確引導(dǎo)Linux內(nèi)核和根文件系統(tǒng)。實(shí)驗(yàn)效果如圖14、圖15和圖16所示。
圖14 SecureCRT串口顯示完成加載Linux
圖15 SecureCRT串口顯示獲取MAC和TFTP下載正常
圖16 SecureCRT串口顯示正在啟動(dòng)Linux內(nèi)核
通過(guò)圖14、圖15和圖16顯示,實(shí)驗(yàn)結(jié)果說(shuō)明該BootLoader能正確引導(dǎo)Linux內(nèi)核和根文件系統(tǒng),并且運(yùn)行穩(wěn)定,為后續(xù)的嵌入式系統(tǒng)開(kāi)發(fā)奠定了基礎(chǔ)。
BootLoader是嚴(yán)重依賴于硬件而實(shí)現(xiàn)的,每種不同體系結(jié)構(gòu)的處理器都有不同的BootLoader,因此BootLoader的設(shè)計(jì)在嵌入式系統(tǒng)開(kāi)發(fā)中非常關(guān)鍵,如何設(shè)計(jì)出一個(gè)比較通用的BootLoader更是困難。本文提出了一種基于“NAND Flash+TFTP”存儲(chǔ)下載方式的BootLoader設(shè)計(jì)方法,實(shí)驗(yàn)結(jié)果表明該BootLoader運(yùn)行穩(wěn)定,只需要根據(jù)硬件資源的不同,稍作一些代碼上的修改,即可移植至嵌入式系統(tǒng)和其他的處理器中。同時(shí)該設(shè)計(jì)方法為BootLoader系統(tǒng)設(shè)計(jì)提供了實(shí)用價(jià)值。
[1] 鄭靈翔. 嵌入式系統(tǒng)設(shè)計(jì)與應(yīng)用開(kāi)發(fā)[M]. 北京: 北京航空航天大學(xué)出版社, 2006:201-219.
[2] 孫瓊. 嵌入式Linux應(yīng)用程序開(kāi)發(fā)詳解[M]. 北京:人民郵電出版社,2006:172-175.
[3] 田會(huì)峰. 基于S3C2440的BootLoader設(shè)計(jì)與實(shí)現(xiàn)[J]. 自動(dòng)化技術(shù)與應(yīng)用, 2010,29(7):29-32.
[4] 杜春雷. ARM體系結(jié)構(gòu)與編程[M]. 北京:清華大學(xué)出版社, 2003:22-223.
[5] 袁磊,朱怡安,蘭婧. 嵌入式系統(tǒng)BootLoader設(shè)計(jì)與實(shí)現(xiàn)[J]. 計(jì)算機(jī)測(cè)量與控制,2009,17(2):389-391.
[6] 張群忠,沈建華. ARM&Linux嵌入式系統(tǒng)BootLoader的研究與設(shè)計(jì)[J]. 計(jì)算機(jī)應(yīng)用與軟件,2006,23(12):97-99.
[6] 葉茂,李智,任和. Cortex-A8的Bootloader設(shè)計(jì)與實(shí)現(xiàn)[J].單片機(jī)與嵌入式系統(tǒng)應(yīng)用,2015,2(1):17-20.
[7] 馮林琳,耿恒山. 基于S3C6410的Uboot分析與移植[J]. 計(jì)算機(jī)與現(xiàn)代化,2013,3(1):119-121.
[9] 梁超,楊峰,雷鳴,等. U-Boot SD卡啟動(dòng)方式的移植分析與功能擴(kuò)展[J]. 現(xiàn)代電子技術(shù),2013,36(20):84-86,90.
[10] 吳偉,周延周. 基于S3C2440的嵌入式系統(tǒng)小型U-Boot的研究[J]. 廣東工業(yè)大學(xué)學(xué)報(bào),2014,31(4):85-89.
DESIGN AND REALISATION OF AN S3C6410-BASED BOOTLOADER
Wu LeiPi ZhiYuan Zongsheng
(College of Computer, North China University of Technology, Beijing 100144, China)
BootLoader is one of the key technologies in embedded system development, and is mainly used for establishing operating system environment. To address the problem of BootLoader in seriously relying on the hardware implementation, in this paper we propose a BootLoader design method which is based on “NAND Flash+TFTP” storage download mode, and verify this BootLoader by an experiment with OK6410 development board. Experimental result shows that the newly designed BootLoader operates good and stably. The design method can be widely applied to embedded system and other processors.
BootLoaderEmbedded systemS3C6410
2015-06-08。北京市自然科學(xué)基金項(xiàng)目(4131001);中央支持地方專項(xiàng)(PXM2014_014212_000097);北京市屬高等學(xué)校創(chuàng)新團(tuán)隊(duì)建設(shè)與教師職業(yè)發(fā)展計(jì)劃項(xiàng)目(IDHT20130502);北京市自然科學(xué)基金項(xiàng)目(4132026)。吳磊,副教授,主研領(lǐng)域:嵌入式技術(shù),無(wú)線通信。皮智,碩士生。袁宗勝,碩士生。
TP311.52
A
10.3969/j.issn.1000-386x.2016.09.057