1.导言
作为一种16/32位的高性能、低成本、低功耗的嵌入式RISC(Reduced Instruction Set Computer)微处理器,ARM(Advanced RISC Machines )微处理器现在现已成为运用最为广泛的嵌入式微处理器[1]。在嵌入式体系开发中Bootloader常常是嵌入式体系开发中或许遇到的第一个技能难点。运用程序运转环境能否正确构建,内核能否发动成功,都取决于Bootloader能否正确的作业。一个功用完善的嵌入式体系Bootloader还要求可以供给体系更新的才能,以及为了完结这一操作所需求的一个简略的指令操控台。本文在根据ARM7-uClinux嵌入式体系的硬件渠道和软件渠道基础上,描绘了体系引导程序Bootloader的规划原理,论述了规划时应考虑的要素和需处理的技能难点并给出了一套可行的引导程序流程。
2.体系组成
典型的ARM嵌入式体系硬件渠道一般包含一个以ARM为内核的处理器、存储器和必要的外部接口与设备。在本体系中选用内嵌ARM7TDMI的Samsung公司S3C4510B处理器,存储器运用2MB的Flash和16MB的SDRAM,外部接口除了可用于下载和通讯的串口,还装备了一个以太网接口以支撑S3C4510B的网络功用。
软件渠道由体系引导程序、嵌入式操作体系内核和文件体系组成,体系引导程序一般即指咱们这儿的Bootloader,其代码量虽少可是效果非常大,相当于一般PC机中的BIOS。经过Bootloader,咱们可以初始化硬件设备、树立内存空间的映射图,从而将体系的软硬件环境带到一个适宜的状况,以便为终究调用操作体系内核预备好正确的环境。
3.Bootloader 规划剖析
3.1 Bootloader 的操作形式 (Operation Mode)
大大都 Bootloader 都包含两种不同的操作形式[2]:
(1). 发动加载(Boot loading)形式:也称为“自主”形式。即Bootloader 从方针机上的某个固态存储设备大将操作体系加载到 RAM 中运转,整个进程并没有用户的介入。
(2).下载(Downloading)形式:在这种形式下,方针机上的Bootloader将经过串口或网络连接等通讯手法从主机(Host)下载内核映像和根文件体系映像等,然后保存到方针机上的FLASH 类固态存储设备中。Bootloader的这种形式一般在体系初度装置和更新时被运用,作业于这种形式下的Bootloader一般都会向它的终端用户供给一个简略的指令行接口。
在咱们的Bootloader规划中咱们一起支撑这两种作业形式,选用的办法是:一开端发动时处于正常的发动加载形式,但并不当即发动进入uClinux内核,而是提示延时5秒,等候终端用户假如按下某一特定按键,则切换到下载形式,不然持续发动uCLinux 内核。
3.2 Bootloader 的发动及初始化
根据ARM的芯片大都为杂乱的片上体系(SoC),这类杂乱体系里的大都硬件模块都是可装备的[3]。因而大大都 Bootloader 都分为 stage1 和 stage2 两大部分。依赖于 CPU 体系结构的代码,一般都放在 stage1 中,并且在这一部分,咱们直接对处理器内核和硬件操控器进行编程,因而常常都用汇编言语来完结。而stage2则一般用C言语来完结,这样可以完结更杂乱的功用,并且代码会具有更好的可读性和可移植性。
3.2.1 Bootloader的stage1
这部分代码有必要首要完结一些根本的硬件初始化,为stage2的履行以及随后的kernel 的履行预备好一些根本的硬件环境[2]。Bootloader的stage1一般通用的内容包含:
* 界说程序进口点
* 设置反常向量表
* 初始化存储体系(包含地址重映射)
* 初始化有特殊要求的端口,设备
* 初始化用户程序的履行环境
* 初始化仓库指针寄存器,必要时改动处理器的形式
* 设置FIQ/IRQ中止处理程序进口
* 进入C程序
在整个Bootloader的初始化进程中咱们都不必呼应中止,因而首要制止体系的中止,然后程序设置CPU的速度和时钟频率,设置CPU内部指令/数据cache,DRAM初始化,DRAM初始化完结后即可仿制ROM中的代码到DRAM中,然后内存重映射,程序开端进入DRAM中履行,然后再初始化一些用户有特殊要求的端口、设备,比方LED或串口等,可以经过点亮LED,或许向串口打印一些调试信息,以此标明体系的状况是OK仍是Error。然后预备进入C言语代码:仿制Bootloader的RW/RO 段到相应的运转方位,初始化ZI段,初始化体系仓库,设置FIQ/IRQ中止处理程序进口,设置完结就可以进入到C代码了。
3.2.2 Bootloader的stage2
为了让程序跳入C言语的“main”函数,咱们选用直接将pc指针指向“main”函数的办法,完结代码如下:
[ THUMBCODE ; [ = IF , 假如是汇编Thumb代码,则选用bx指令跳转
bx lr
| ; | = ELSE
mov pc, lr ; 汇编ARM代码,则直接跳转到main函数
] ; ] = ENDIF
进入main函数后即可以开端本阶段stage2的初始化使命,这包含:
(1)初始化至少一个串口,以便和终端用户进行交互;
(2)初始化计时器,延时并提示发动形式的挑选,假如进入发动加载形式,则体系操控权交由uClinux操作体系,Bootloader功遂身退 ,不然程序持续向下履行。
(3)初始化网络,包含网络根本信息装备等;
(5)假如体系配有LCD等外设,可以在此初始化;
(6)初始化Flash:检测是否支撑该Flash芯片(可经过比较Flash ID的方法完结);
(7)初始化中止,包含屏蔽中止,铲除中止悬挂标志,初始化中止向量表,注册需求的中止处理函数等。
(8)初始化指令操控台,等候用户键入指令。
在初始化这些设备之前,也可以改动 LED 灯的状况,以标明咱们现已进入main函数履行。设备初始化完结后,可以经过串口输出一些打印信息,如程序姓名字符串、版本号等。本体系中选用的体系发动引导计划流程图如图1所示。
4.难点剖析
4.1反常及中止处理
在ARM支撑的7种形式中,共有5种反常形式,而其间又尤以外部中止形式(IRQ)运用较为广泛,其反常处理进程也较为杂乱。本文下面将以IRQ反常处理为例,叙述一个通用的中止运用及处理进程。一个ARM通用的中止处理进程大致可以分为以下3步:
(1) 反常呼应:获取反常处理程序进口地址,并进入反常处理程序;
(2) 现场维护及康复:即进入中止服务程序(ISR)前后中止现场的维护和康复;
(3) 中止服务:核算中止源索引号,清中止,然后进入中止服务。
本例中IRQ反常处理相关代码如下:
ResetEntry
b SYS_RST_HANDLER ;复位反常
……
b IRQ_SVC_HANDLER ;外部中止请求
MACRO ;经过一个宏界说,一致处理各反常处理程序与反常向量地址的映射联系
$HandlerLabel HANDLER $ExceptHandler
$HandlerLabel
sub sp,sp,#4 ;预留一个字的空间用来保存PC的跳转地址
stmfd sp!,{r0} ;保存下面中止处理中运用到的r0寄存器
ldr r0,=$ExceptHandler ;将保存有反常处理函数进口的地址读入r0
ldr r0,[r0] ;将反常处理函数进口读入r0
str r0,[sp,#4] ;将反常处理函数进口存入仓库中方才预留的空间
ldmfd sp!,{r0,pc} ;康复现场,一起跳入反常处理函数
MEND
IRQ_SVC_HANDLER HANDLER IrqSvcVector ;调用宏界说
……
SYS_RST_HANDLER ;复位反常时程序跳转地址
…… ;体系初始化代码
ldr r0, =IrqSvcVector
ldr r1, =IRQ_SERVICE
str r1, [r0] ;将IRQ反常处理程序进口存入变量IrqSvcVector
……
IRQ_SERVICE
STMFD sp!, {r0-r12, lr}
BL ISR_IrqHandler ;跳入C言语中界说的中止服务程序(ISR)
LDMFD sp!, {r0-r12, lr}
SUBS pc, lr, #4 ;反常回来一起仿制相应SPSR到CPSR,完结处理器形式主动切换
void ISR_IrqHandler(void) //C言语中界说的中止服务程序
{
unsigned int IntOffSet;
IntOffSet = (unsigned int)inl(INTOFFSET);//取出中止源索引号
Clear_PendingBit(IntOffSet>>2); //清中止
(*InterruptHandlers[IntOffSet>>2])(); // 进入对应的中止服务子函数
}
从上面的代码咱们可以总结得出,接收到IRQ中止请求后程序的履行流程是:
(1)履行完当时指令,程序主动跳到0x18地址;
(2)从0x18 程序跳转到IRQ_SVC_HANDLER;
(3)从IRQ_SVC_HANDLER 再到SDRAM高端反常矢量表;
(4)从SDRAM高端反常矢量表跳转到IRQ_SERVICE反常处理程序;
(5)由IRQ_SERV%&&&&&%E最终进入中止服务程序,完结中止处理使命后回来。
4.2 指令操控台
当Bootloader作业在下载形式时,一般会经过串口向终端用户供给一个简略的指令操控台,为了运用的便利,咱们这儿对其功用进行了扩大,添加了指令键入时对键盘“上、下、左、右、Home、End”几个方向键的支撑。
经过串口收发或显现字符时,咱们运用的一般是字符的ASCII码。关于非操控字符,也即键入指令时咱们或许运用到的指令字符,在操控台中咱们运用了ASCII码值从0x20~0x7e之间的字符。关于操控字符,在常用字符ASCII码对照表中咱们可以找到Enter键、Backspace(退格)键以及ESC键的ASCII码,可是却没有上下左右方向键以及Home、End键对应的ASCII码,经过对键盘输入字符的串口收发测验发现,假如在测验时按下了方向键则串口在每次按键后会接连发送出3字节数据,前两字节一切方向键的数据相同,别离是0x1b,0x5b,第3字节对应不同的按键,上下右左方向键别离对应的值为:0x41、0x42、0x43、0x44,Home和End键对应的值为0x48和0x4b。故要检测键盘是否键入了方向键,需求向串口接连读取三字节的数据,同理,要操控光标向左、向右移动或Home、End也需求接连一次向串口发送3字节数据。指令操控台从串口接收到字符后,程序处理的流程图如图2所示。
5.结束语
Bootloader与详细的硬件环境和操作体系是紧密联系在一起,针对某个CPU芯片编写Bootloader代码,首要要了解该CPU的内核结构、指令体系,其次是详细芯片的结构和各种片上资源,以及所选用的操作体系。本文给出的Bootloader代码现已在根据Samsung公司的S3C4510B芯片开发的体系板上运转并测验经过。该Bootloader可以正常引导及更新uClinux内核,体系运转安稳,彻底完结了规划意图,达到了嵌入式体系的规划要求。
参考文献:
[1]. 李驹光等.ARM运用体系开发详解——根据S3C4510B的体系规划. 清华大学出版社.2003 .
[2]. 詹荣开. 嵌入式体系Bootloader技能内情.
http://linux.chinaunix.net/doc/embedded/2005-01-13/762.shtml
[3]. 蔡治等.根据ARM核的嵌入式运用体系中的发动代码的编程.电子科技,NO6,2005