Bootloader 设计分析
3.1 Bootloader 的操作模式 (Operation Mode)
大多数 Bootloader 都包含两种不同的操作模式[2]:
(1). 启动加载(Boot loading)模式:也称为“自主”模式。即Bootloader 从目标机上的某个固态存储设备上将操作系统加载到 RAM 中运行,整个过程并没有用户的介入。
(2).下载(Downloading)模式:在这种模式下,目标机上的Bootloader将通过串口或网络连接等通信手段从主机(Host)下载内核映像和根文件系统映像等,然后保存到目标机上的FLASH 考研国家线2019类固态存储设备中。Bootloader的这种模式通常在系统初次安装和更新时被使用,工作于这种模式下的Bootloader通常都会向它的终端用户提供一个简单的命令行接口。
在我们的Bootloader设计中我们同时支持这两种工作模式,采用的方法是:一开始启动时处于正常的启动加载模式,但并不立即启动进入uClinux内核,而是提示延时5秒,等待终端用户如果按下某一特定按键,则切换到下载模式,否则继续启动uCLinux 内核。
3.2 Bootloader 的启动及初始化
jun jin基于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代码了。
在整个Bootloader的初始化过程中我们都不必响应中断,因此首先禁止系统的中断,然后程序设置CPU的速度和时钟频率,设置CPU内部指令/数据cache,DRAM初始化,DRA
M初始化完成后即可拷贝ROM中的代码到DRAM中,然后内存重映射,程序开始进入DRAM中执行,然后再初始化一些用户有特殊要求的端口、设备,比如LED或串口等,可以通过点亮LED,或者向串口打印一些调试信息,以此表明系统的状态是OK还是Error。然后准备进入once的用法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)前后中断现场的保护和恢复;
(3southampton) 中断服务:计算中断源索引号,清中断,然后进入中断服务。
本例中IRQ异常处理相关代码如下:
RetEntry
b SYS_RST_HANDLER ;复位异常
.
.....
b IRQ_SVC_HANDLER ;外部中断请求
MACRO ;通过一个宏定义,统一处理各异常处理程序与异常向量地址的映射关系
$HandlerLabel HANDLER $ExceptHandlerasio
$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_SERVICE最后进入中断服务程序,完成中断处理任务后返回。
4.2 命令控制台
当Bootloader工作在下载模式时,通常会通过串口向终端用户提供一个简单的命令控制台,为了使用的方便,我们这里对其功能进行了扩充,添加了命令键入时对键盘“上、下、左、右、Home、End”几个方向键的支持。
通过串口收发或显示字符时,我们使用的通常是字符的ASCII码。对于非控制字符,也即键入命令时我们可能使用到的命令字符,在控制台中我们使用了ASCII码值从0x20~0x7e之间的字符。对于控制字符,在常用字符ASCII码对照表中我们可以找到Enter键、Backsp
ace(退格)键以及ESC键的ASCII码,但是却没有上下左右方向键以及Home、End键对应的ASCII码,通过对键盘输入字符的串口收发测试发现,如果在测试时按下了方向键则串口在每次按键后会连续发送出3字节数据,前两字节所有方向键的数据相同,分别是0x1b,0x5b,第3字节对应不同的按键,上下右左方向键分别对应的值为:0x41、0x42、0x43、0x44,Home和End键对应的值为0x48和0x4b。故要检测键盘是否键入了方向键,需要向串口连续读取三字节的数据,同理,要控制光标向左、向右移动或Home、End也需要连续一次向串口发送3字节数据。命令控制台从串口接收到字符后,程序处理的流程图如图2所示。