小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Porting uClinux to Samsung S3C44B0X Board|uClinux, uCGUI, ARM7, S3C44B0, bootloader

 Archangel 2007-04-29
Porting uClinux to Samsung S3C44B0X Board    一.Bootloader

理 論上,uClinux引導(dǎo)時(shí)并非一定需要一個(gè)獨(dú)立于Kernel Image的Bootloader Image。然而,將Bootloader與Kernel分開(kāi)設(shè)計(jì)能夠使軟件架構(gòu)更加清晰,也有助于靈活地支持多種引導(dǎo)方式,實(shí)現(xiàn)一些有用的輔助功能。 Bootloader的主要任務(wù)可以概括如下:

1.硬件初始化和系統(tǒng)引導(dǎo);
2.加載uClinux Kernel Image (如果需要);
3.設(shè)置需要傳遞給Kernel的啟動(dòng)參數(shù)(如果需要);
4.調(diào)用uClinux Kernel;
5.輔助功能:從主機(jī)下載新的Image;
6.輔助功能:燒寫(xiě)Flash Memory;
7.輔助功能:支持功能5和6所需的人機(jī)界面,如串行終端上的命令行接口。

對(duì) 于常見(jiàn)的幾類(lèi)處理器內(nèi)核,現(xiàn)在一般都找得到現(xiàn)成的Bootloader可用,不過(guò)需要針對(duì)具體的Board做些移植。在實(shí)現(xiàn)上述功能的前提下,也可以選擇 自行開(kāi)發(fā)。由于Bootloader Image在物理上獨(dú)立于Kernel Image,因此不一定選擇GNU作為開(kāi)發(fā)工具。對(duì)于以ARM7TDMI為內(nèi)核的S3C44B0X處理器,完全可以使用ADS來(lái)開(kāi)發(fā) Bootloader。

1.硬件初始化和系統(tǒng)引導(dǎo)

完整的Bootloader引導(dǎo)流程可描述如下:

硬 件初始化階段一 -> 復(fù)制二級(jí)Exception Vector Table -> 初始化各種處理器模式 -> 復(fù)制RO和RW,清零ZI -> (跳轉(zhuǎn)到C代碼入口函數(shù)) -> 初始化Exception/Interrupt Handler Entry Table -> 初始化Device Drivers -> 硬件初始化階段二 -> 建立人機(jī)界面

下面對(duì)上述各步驟逐一加以說(shuō)明。

1.1 硬件初始化階段一

板 子上電或復(fù)位后,程序從位于地址0x0的Reset Exception Vector處開(kāi)始執(zhí)行,因此需要在這里放置Bootloader的第一條指令:b ResetHandler,跳轉(zhuǎn)到標(biāo)號(hào)為ResetHandler處進(jìn)行第一階段的硬件初始化,主要內(nèi)容為:關(guān)Watchdog Timer,關(guān)中斷,初始化PLL和時(shí)鐘,初始化Memory Controller。比較重要的是PLL的輸出頻率要算正確,這里把它設(shè)置為50MHz;后面在計(jì)算SDRAM的Refresh Count和UART的Baud Rate等參數(shù)時(shí)還要用到。

1.2 復(fù)制二級(jí)Exception Vector Table

Exception Vector Table是Bootloader與uClinux Kernel發(fā)生聯(lián)系的地方之一(另兩處是加載and/or調(diào)用Kernel,以及向Kernel傳遞啟動(dòng)參數(shù))。ARM7規(guī)定Exception Vector Table的基地址是0x0,所以Flash Memory的基地址也必須是0x0;而S3C44B0X處理器又不支持Memory Remap,這意味著無(wú)論運(yùn)行什么樣的上層軟件,一旦發(fā)生中斷,程序就得到Flash Memory中的Exception Vector Table里去打個(gè)轉(zhuǎn)(中斷Interrupt是異常Exception的一種)。對(duì)于uClinux而言,它會(huì)在RAM中建立自己的二級(jí) Exception Vector Table(后面將提到基地址被設(shè)為0x0C000000),所以在編寫(xiě)B(tài)ootloader時(shí),地址0x0處的一級(jí)Exception Vector Table只需簡(jiǎn)單地包含向二級(jí)Exception Vector Table跳轉(zhuǎn)的內(nèi)容:

b ResetHandler ;Reset Handler
ldr pc,=0x0c000004 ;Undefined Instruction Handler
ldr pc,=0x0c000008 ;Software Interrupt Handler
ldr pc,=0x0c00000c ;Prefetch Abort Handler
ldr pc,=0x0c000010 ;Data Abort Handler
b .
ldr pc,=0x0c000018 ;IRQ Handler
ldr pc,=0x0c00001c ;FIQ Handler
LTORG

如 果在Bootloader執(zhí)行的全過(guò)程中都不必響應(yīng)中斷,那么上面的設(shè)置已能滿足要求。但如果某些Bootloader功能要求使用中斷(例如用 Timer Interrupt實(shí)現(xiàn)精確定時(shí),或利用External Interrupt支持Ethernet Driver以實(shí)現(xiàn)TFTP下載),那么Bootloader必須在同樣的地址處配置自己的二級(jí)Exception Vector Table,以便同uClinux兼容。這張表事先存放在Flash Memory里,引導(dǎo)過(guò)程中由Bootloader將其復(fù)制到RAM地址0x0C000000:

存放:

RelocatedExceptionVectorStart
mov pc,#0
b HandlerUndef
b HandlerSWI
b HandlerPAbort
b HandlerDAbort
b .
b HandlerIRQ
b HandlerFIQ
HandlerUndef HANDLER HandleUndef
HandlerSWI HANDLER HandleSWI
HandlerPAbort HANDLER HandlePAbort
HandlerDAbort HANDLER HandleDAbort
HandlerIRQ HANDLER HandleIRQ
HandlerFIQ HANDLER HandleFIQ
LTORG
RelocatedExceptionVectorEnd

復(fù)制:

adr r0, RelocatedExceptionVectorStart
ldr r2, =0x0c000000
adr r3, RelocatedExceptionVectorEnd
0
cmp r0, r3
ldrcc r1, [r0], #4
strcc r1, [r2], #4
bcc %B0

其中HANDLER是一個(gè)宏,用于查找Exception Handler Routines的入口地址。這些地址存放在由HandleXXX指向的表項(xiàng)中,該表定位在RAM高端,基地址為_(kāi)ISR_STARTADDRESS:

^ _ISR_STARTADDRESS
HandleReset # 4
HandleUndef # 4
HandleSWI # 4
HandlePAbort # 4
HandleDAbort # 4
HandleReserved # 4
HandleIRQ # 4
HandleFIQ # 4

該表的內(nèi)容將在步驟1.5:“初始化Exception/Interrupt Handler Entry Table”中被填寫(xiě)為各Exception Handler Routine的入口地址。

1.3 初始化各種處理器模式

ARM7TDMI 支持7種Operation Mode:User,F(xiàn)IQ,IRQ,Supervisor,Abort,System和Undefined。Bootloader需要依次切換到每種模 式,初始化其程序狀態(tài)寄存器(SPSR)和堆棧指針(SP)。S3C44B0X處理器在上電或復(fù)位后處于Supervisor模式,本步驟中把對(duì) Supervisor模式的初始化放在最后,也就是說(shuō)Bootloader的后續(xù)部份仍將運(yùn)行在Supervisor模式下。

1.4 復(fù)制RO和RW,清零ZI

對(duì) 于ADS開(kāi)發(fā)工具而言,一個(gè)ARM程序由RO,RW和ZI三個(gè)段組成,其中RO為代碼段,RW是已初始化的全局變量,ZI是未初始化的全局變量(對(duì)于 GNU工具,對(duì)應(yīng)的概念是TEXT,DATA和BSS)。RO段既可以在Flash Memory中運(yùn)行,也可以在RAM中運(yùn)行。考慮到Bootloader中可能需要燒寫(xiě)Flash Memory,因此在引導(dǎo)階段應(yīng)當(dāng)將RO和RW段復(fù)制到RAM中,并將ZI段清零。當(dāng)RO段復(fù)制完畢之后,程序就可以跳轉(zhuǎn)到RAM中運(yùn)行。若不考慮燒寫(xiě) Flash Memory,則可以不復(fù)制RO段,程序始終在Flash Memory中運(yùn)行。ADS使用下列Linker Symbols來(lái)記錄各段的起始和結(jié)束地址:

|Image$$RO$$Base| :RO段起始地址
|Image$$RO$$Limit| :RO段結(jié)束地址加1
|Image$$RW$$Base| :RW段起始地址
|Image$$RW$$Limit| :ZI段結(jié)束地址加1
|Image$$ZI$$Base| :ZI段起始地址
|Image$$ZI$$Limit| :ZI段結(jié)束地址加1

可 以在程序中引用這些標(biāo)號(hào)。需要注意的是,這些標(biāo)號(hào)的值是根據(jù)ARM Linker中RO Base和RW Base的設(shè)置來(lái)計(jì)算的,屬于“Linker Address”或“Execution Address”,并不一定代表這些段存放在Flash Memory中的地址,在編寫(xiě)復(fù)制程序時(shí)需要根據(jù)具體情況作相應(yīng)的計(jì)算。

1.5 初始化Exception/Interrupt Handler Entry Table

在 步驟1.2里已經(jīng)提到,需要在這一步中填寫(xiě)各Exception Handler Routine的入口地址。由于IRQ Exception為全部的中斷所共用,因此必須在IRQ Exception Handler Routine中根據(jù)中斷狀態(tài)寄存器判斷中斷源,并調(diào)用相應(yīng)的Interrupt Handler Routine。各Interrupt Handler Routine的入口地址也存放在上述的Exception/Interrupt Handler Entry Table中(緊接在HandleFIQ之后),需要在這一步中填寫(xiě),這里就不一一列出了。

另外,S3C44B0X處理器的 Interrupt Controller支持兩種中斷處理模式:Vectored Mode和Non-Vectored Mode,其中前者可能是Samsung特有的模式,并不被其它ARM7內(nèi)核所支持。考慮到代碼的可移植性,以上討論僅針對(duì)這里所使用的Non- Vectored Mode。

1.6 初始化Device Drivers

在這一步中需要為Bootloader用到的一些關(guān)鍵Device Drivers建立必要的數(shù)據(jù)結(jié)構(gòu),主要包括用于精確定時(shí)的Watchdog Timer Driver和用于支持串行終端的UART Driver。

1.7 硬件初始化階段二

繼 續(xù)對(duì)硬件進(jìn)行初始化,主要包括:GPIO,Cache,Interrupt Controller,Watchdog Timer和UARTs。S3C44B0X處理器內(nèi)置data/instruction合一的8KB Cache,且允許按地址范圍設(shè)置兩個(gè)Non-Cacheable區(qū)間。合理的配置是打開(kāi)對(duì)RAM區(qū)間的Cache,關(guān)閉對(duì)其它地址區(qū)間(包含F(xiàn)lash Memory區(qū)間)的Cache。所有硬件初始化完畢之后,開(kāi)中斷。

在步驟1.6和1.7中,仍然遵循“必要”的原則對(duì)硬件和Device Drivers進(jìn)行初始化。在目前階段沒(méi)有涉及的設(shè)備(如Ethernet Controller),可以留待使用它們之前再進(jìn)行初始化。

1.8 建立人機(jī)界面
引 導(dǎo)過(guò)程的最后一步是在串行終端上建立人機(jī)界面,并等待用戶(hù)輸入命令。合理的做法是先等待固定的秒數(shù),若在此期間未接收到用戶(hù)輸入,則直接從Flash Memory中加載and/or調(diào)用uClinux Kernel。若接收到用戶(hù)輸入,則顯示菜單模式或命令行模式的交互界面,等待用戶(hù)進(jìn)一步的命令。這里就不對(duì)此詳細(xì)討論了。

2.加載Kernel

Bootloader是否需要執(zhí)行加載操作,取決于uClinux Kernel Image的類(lèi)型。根據(jù)不同的配置,可以生成下面幾種uClinux Kernel Image:

2.1 非壓縮,非XIP

XIP(eXecute In Place)是指不對(duì)代碼段重新定位,在存放代碼段的位置就地運(yùn)行程序。該類(lèi)型的uClinux Kernel Image以非壓縮格式存放在Flash Memory中,由Bootloader加載到RAM中并直接調(diào)用。

2.2 非壓縮,XIP

該類(lèi)型的uClinux Kernel Image以非壓縮格式存放在Flash Memory中,不需加載,由Bootloader直接調(diào)用。復(fù)制init段和data段,清零bss段的工作由Kernel自行完成。

2.3 RAM自解壓

壓 縮格式的uClinux Kernel Image都是由開(kāi)頭的一段自解壓代碼和后面的壓縮數(shù)據(jù)部分組成。對(duì)于Kernel而言,由于是以壓縮格式存放,因次只能以非XIP方式執(zhí)行。RAM自解 壓類(lèi)型的uClinux Kernel Image存放在Flash Memory中,由Bootloader加載到RAM中的一段臨時(shí)空間,然后調(diào)用其自解壓代碼??蓤?zhí)行的uClinux Kernel被解壓到最終的執(zhí)行空間,然后運(yùn)行。壓縮格式Image所占據(jù)的臨時(shí)RAM空間可在隨后由uClinux回收利用。

2.4 ROM自解壓

解 壓縮操作也可以在Flash Memory中完成。實(shí)際上,這意味著以XIP方式執(zhí)行自解壓代碼。ROM自解壓類(lèi)型的uClinux Kernel Image存放在Flash Memory中,不需加載,由Bootloader直接調(diào)用其自解壓代碼。自解壓代碼自行復(fù)制其data段,清零bss段,然后將可執(zhí)行的uClinux Kernel解壓到最終的執(zhí)行空間并運(yùn)行之。與RAM自解壓相比,用ROM自解壓方式引導(dǎo)uClinux并不真正節(jié)省RAM,而且在Flash Memory中解壓縮速度較慢,因此實(shí)用價(jià)值不大。

2.5 Memory Map

下面給出Bootloader和 uClinux在存儲(chǔ)和運(yùn)行時(shí)的Memory Map。系統(tǒng)存儲(chǔ)器由NOR Flash Memory (2MB)和SDRAM(32MB)組成,F(xiàn)lash Memory的地址范圍從0x0到0x00200000,SDRAM的地址范圍從0x0C000000到0x0E000000。

Flash Memory
0x00000000 ~ 0x00020000: 存放Bootloader
0x00020000 ~ 0x00200000: 存放所有類(lèi)型的uClinux Kernel Image
運(yùn)行2.2類(lèi)型的uClinux Kernel
運(yùn)行2.4類(lèi)型的自解壓代碼
SDRAM
0x0C008000 ~ xxxxxxxx: 運(yùn)行Bootloader
0x0C200000 ~ xxxxxxxx: 運(yùn)行2.1,2.3,2.4類(lèi)型uClinux Kernel
0x0C400000 ~ xxxxxxxx: 臨時(shí)存放2.3類(lèi)型壓縮Image,并運(yùn)行自解壓

3.設(shè)置內(nèi)核啟動(dòng)參數(shù)

Linux 2.4.x以后的內(nèi)核都期望以標(biāo)記列表(tagged list)的形式來(lái)傳遞啟動(dòng)參數(shù)。每個(gè)標(biāo)記存放在一個(gè)tag結(jié)構(gòu)中,每個(gè)tag結(jié)構(gòu)由標(biāo)識(shí)被傳遞參數(shù)的tag_header結(jié)構(gòu)以及隨后存放的參數(shù)值組 成。數(shù)據(jù)結(jié)構(gòu)tag、tag_header以及各種參數(shù)的數(shù)據(jù)結(jié)構(gòu)都定義在Linux內(nèi)核源碼的頭文件linux/include/asm- armnommu/setup.h中。

通常需要由Bootloader設(shè)置的啟動(dòng)參數(shù)有:ATAG_MEM、 ATAG_CMDLINE、ATAG_RAMDISK、ATAG_SERIAL、ATAG_INITRD等。啟動(dòng)參數(shù)的標(biāo)記列表以ATAG_CORE開(kāi) 始,以ATAG_NONE結(jié)束,代碼示例如下。其中0x0C000100是內(nèi)核啟動(dòng)參數(shù)在RAM中的基地址,指針params的類(lèi)型是struct tag。宏tag_next()以指向當(dāng)前標(biāo)記的指針為參數(shù),計(jì)算下一個(gè)標(biāo)記的起始地址。

params = (struct tag *)0x0C000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size(tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next(params);
……
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;

在Linux 內(nèi)核源碼的linux/arch/armnommu/mach-s3c44b0/arch.c中設(shè)置內(nèi)核啟動(dòng)參數(shù)在RAM中的基地址。如果Kernel不 需要從Bootloader接收啟動(dòng)參數(shù),下面代碼中的“BOOT_PARAMS(0x0C000100)”這一行可以不寫(xiě)。


MACHINE_START(S3C44B0, "44B0EVAL")
MAINTAINER("XXX YYY")
BOOT_MEM(DRAM_BASE,0x00000000,0x00000000)
BOOT_PARAMS(0x0C000100)
INITIRQ(genarch_init_irq)
MACHINE_END

uClinux Kernel處理啟動(dòng)參數(shù)時(shí)的代碼調(diào)用關(guān)系可查閱linux/init/main.c和 linux/arch/armnommu/kernel/setup.c:start_kernel()àsetup_arch() àparse_tags()。parse_tags()函數(shù)中調(diào)用parse_tag()函數(shù)依次處理每個(gè)標(biāo)記。parse_tag()函數(shù)先判斷 tag_header結(jié)構(gòu)中的標(biāo)記類(lèi)型,然后調(diào)用相應(yīng)的處理函數(shù)。例如,調(diào)用parse_tag_cmdline()處理ATAG_CMDLINE標(biāo)記, 調(diào)用parse_tag_initrd()處理ATAG_INITRD標(biāo)記,等等。對(duì)應(yīng)關(guān)系如下:

static const struct tagtable core_tagtable[] __init = {
{ ATAG_CORE, parse_tag_core},
{ ATAG_MEM, parse_tag_mem32},
{ ATAG_VIDEOTEXT, parse_tag_videotext},
{ ATAG_RAMDISK, parse_tag_ramdisk},
{ ATAG_INITRD, parse_tag_initrd},
{ ATAG_SERIAL, parse_tag_serialnr},
{ ATAG_REVISION, parse_tag_revision},
{ ATAG_CMDLINE, parse_tag_cmdline}
};

對(duì) 于Kernel Command Line,parse_tag_cmdline()函數(shù)將用內(nèi)核參數(shù)表中的命令字符串來(lái)覆蓋default_command_line[]變量。如果 Kernel不從Bootloader接收啟動(dòng)參數(shù),也可以有兩種方法來(lái)初始化Kernel Command Line。在linux/arch/armnommu/kernel/setup.c中有:

static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;

因 此一種方法是在make menuconfig時(shí)通過(guò)修改“General Setup”子菜單中的“Default kernel command string”選項(xiàng)來(lái)定義linux/include/linux/autoconf.h頭文件中的CONFIG_CMDLINE宏,另一種方法是在 linux/arch/armnommu/kernel/setup.c中直接把default_command_line[]寫(xiě)死。

4.調(diào)用Kernel

Bootloader調(diào)用uClinux Kernel的方法是直接跳轉(zhuǎn)到Kernel的第一條指令處。在跳轉(zhuǎn)時(shí)要滿足下列條件:

CPU寄存器r0=0;
CPU 寄存器r1=Machine Type ID(S3C44B0X的Machine Type ID定義在include/asm-arm/mach-types.h中:#define MACH_TYPE_S3C44B0 178。寄存器r1也可以在Kernel啟動(dòng)之初的head-armv.S中設(shè)置);
禁止中斷(IRQs和FIQs);
CPU運(yùn)行在SVC模式;
MMU必須關(guān)閉(S3C44B0X沒(méi)有MMU);
指令Cache可以打開(kāi)也可以關(guān)閉,數(shù)據(jù)Cache必須關(guān)閉(S3C44B0X的Cache是指令與數(shù)據(jù)合一的,因此只能選擇關(guān)閉)。

C代碼調(diào)用Kernel的示例如下,其中r0和r1的值通過(guò)參數(shù)傳遞:

void (*CallKernel)(int zero, int mach) = (void (*)(int, int))KERNEL_ADDR;
CallKernel(0, 178);

5.輔助功能

完 整的Bootloader還應(yīng)該支持從主機(jī)下載文件到目標(biāo)板的RAM;用RAM中的數(shù)據(jù)燒寫(xiě)Flash Memory;以及上述功能所需的人機(jī)交互接口。文件下載途徑視目標(biāo)板所提供的物理通訊接口而定,比較簡(jiǎn)單的方法一般是通過(guò)串口,用Xmodem或 Ymodem協(xié)議下載,但速度較慢。目標(biāo)板上只需要實(shí)現(xiàn)協(xié)議的接收部份,主機(jī)上可以用HyperTerminal等工具來(lái)發(fā)送文件。如果目標(biāo)板提供 Ethernet等快速接口,也可以移植一個(gè)簡(jiǎn)單的TCP/IP棧,用TFTP等標(biāo)準(zhǔn)文件傳輸協(xié)議下載。目前Flash Memory一般都是用NOR Flash,燒寫(xiě)是非常簡(jiǎn)單的;需要注意的是對(duì)于多數(shù)Flash芯片,在Erase/Program之前需要先Unprotect。人機(jī)交互接口不難在串 行終端上實(shí)現(xiàn),這里就不贅述了。

參考文獻(xiàn):
1. S3C44B0X User‘s Manual Samsung
2.嵌入式系統(tǒng)Boot Loader技術(shù)內(nèi)幕 詹榮開(kāi)

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多