新闻中心

EEPW首页 > 嵌入式系统 > 设计应用 > 基于ARM-Linux嵌入式系统引导程序的设计

基于ARM-Linux嵌入式系统引导程序的设计

作者:时间:2012-11-01来源:网络收藏

  (a)建立中断向量表,当程序出现异常后可跳转到相应子程序执行。如
bResetAddr;
bUndefAddr;handlerforUndefinedmode0x4
bSWI_Addr;handlerforSWIinterrupt0x8
bPreAbortAddr;handlerforPreAbort0xC
bDataAbortAddr;handlerforDataAbort0x10
b.;reserved0x14
bIRQ_Addr;handlerforIRQinterrupt0x18
bFIQ_Addr;handlerforFIQinterrupt0x1C
  (b)屏蔽所有的中断。为中断提供服务通常是操作系统设备驱动程序的责任,因此在的执行全过程中可以不必响应任何中断。可以通过写的寄存器INTMSK、INTSUBMSK来完成;
  (c)设置CPU的速度和时钟频率。可以通过写寄存器LOCKTIME、MPLLCON、UPLLCON来实现;
  (d)RAM初始化。包括正确地设置系统的内存控制器的功能寄存器BWSCON以及各内存控制寄存器等。
  (e)初始化LED。典型地,通过GPIO来驱动LED,其目的是表明系统的状态是正常还是出现错误。

3.1.2为加载Stage2准备RAM空间,拷贝Stage2到RAM中。
  为了获得更快的执行速度,通常把Stage2加载到RAM空间中来执行,因此必须为加载的Stage2准备好一段可用的RAM空间范围。具体的地址范围可以任意安排,比如我们习惯将Stage2可执行映像安排到RAM地址最顶部1MB开始的空间内执行。拷贝时要确定两点:Stage2的可执行映像存放在Flash中的起始地址和终止地址;以及RAM空间的起始地址。

3.1.3设置堆栈指针sp。
  堆栈指针的设置是为了执行C语言代码作好准备,通常我们可以把sp(Userstack)设置在上面所安排的那个1MBRAM空间的最顶端(堆栈向下生长)。此外,在设置堆栈指针sp之前,也可以关闭LED灯,以提示我们准备跳转到Stage2。

3.1.4跳转到Stage2的C入口点。
  在上述一切都就绪后,就可以跳转到的Stage2去执行了。比如通过修改PC寄存器为合适的地址来实现。

3.2Bootloader的Stage2通常依次执行以下主要步骤:

3.2.1进入Stage2的入口程序
  Stage2的代码通常用C语言来实现,但是与普通C语言应用程序不同的是,在编译和链接bootloader这样的程序时,我们无法使用glibc库中的任何支持函数。这就需要我们利用汇编语言写一段trampoline(弹簧床)小程序,并将这段trampoline小程序来作为Stage2可执行映象的执行入口点。然后我们可以在trampoline小程序中用CPU跳转指令跳入main()函数中去执行;而当main()函数返回时,CPU执行路径显然再次回到了trampoline程序。具体程序如下:
.text
.globl_trampoline
_trampoline:
blmain
b_trampoline

3.2.2初始化本阶段要使用到的硬件设备
  这通常包括:初始化至少一个串口,以便和终端用户进行I/O输出信息;初始化计时器等。在初始化这些设备之前,也可以重新把LED灯点亮,以表明我们已经进入main()函数执行。设备初始化完成后,可以输出一些打印信息,程序名字字符串、版本号等。

3.2.3检测系统的内存映射(Memorymap)
  所谓内存映射就是指在整个4GB物理地址空间中有哪些地址范围被分配用来寻址系统的RAM单元。CPU通常预留出一段足够大的地址空间给系统RAM,但是在搭建具体的嵌入式系统时不一定会实现CPU预留的全部RAM地址空间。而是往往只把CPU预留的全部RAM地址空间中的一部分映射到RAM单元上,而让剩下的那部分预留RAM地址空间处于未使用状态。如使用的RAM空间仅为0x30000000-0x33ffffff。

3.2.4加载内核映像和根文件系统映像并从Flash上拷贝
  规划内存占用的布局。这里包括两个方面:(1)内核映像所占用的内存范围;(2)根文件系统所占用的内存范围。对于内核映像,一般将其拷贝到从(MEM_START+0x8000)这个基地址开始的大约1MB大小的内存范围内(嵌入式Linux的内核一般都不超过1MB)。从MEM_START到MEM_START+0x8000这段32KB大小的内存之所以被空出,是因为Linux内核要在这段内存中放置一些全局数据结构,如:启动参数和内核页表等信息。而对于根文件系统映像,则一般将其拷贝到MEM_START+0x0010,0000开始的地方。若采用Ramdisk作为根文件系统映像,则其解压后的大小一般为1MB。
由于像ARM这样的嵌入式CPU通常都是在统一的内存地址空间中寻址Flash等固态存储设备,因此从Flash上读取数据与从RAM单元中读取数据并没有什么不同。用一个简单的循环就可以完成从Flash设备上拷贝映像的工作。如:
count=kernelsize
while(count>0){
*dest++=*src++;/*theyareallalignedwithwordboundary*/
count-=4;/*bytenumber*/
};

3.2.5设置内核的启动参数
  将内核映像和根文件系统映像拷贝到RAM空间后,设置Linux内核的启动参数,如ATAG_CORE、ATAG_MEM、ATAG_CMDLINE、ATAG_RAMDISK、ATAG_INITRD等,然后就可以准备启动Linux内核了。

3.2.6调用内核。
  Bootloader调用Linux内核的方法是直接跳转到内核的第一条指令处,也即直接跳转到MEM_START+0x8000地址处。此时,还需要设置CPU寄存器、CPU模式、Cache和MMU。


3.结束语
  Bootloader是依赖于硬件而实现的,每个目标板的硬件配置都不完全一样,因此Bootloader程序也都不会完全一样。本文以Samsung公司的的开发板为平台,阐述了Bootloader运行的主要步骤和关键技术,为实现引导Linux操作系统内核运行提供合适的环境。文章后面关于Linux内核启动参数的具体设置及如何调用内核是和具体操作系统密切关系的,未做详细论述。此外,设计与实现一个优秀的Bootloader程序是一个庞大复杂的过程,在程序中如能多利用LED和串口输出信息会是帮助我们调试的好方法。

参考文献:

[1].ARM920Tdatasheethttp://www.dzsc.com/datasheet/ARM920T_139814.html.
[2].ROMdatasheethttp://www.dzsc.com/datasheet/ROM_1188413.html.


上一页 1 2 下一页

评论


相关推荐

技术专区

关闭