ARM7的Bootloader和分散加载文件笔记.docx
- 文档编号:7648631
- 上传时间:2023-01-25
- 格式:DOCX
- 页数:20
- 大小:191.42KB
ARM7的Bootloader和分散加载文件笔记.docx
《ARM7的Bootloader和分散加载文件笔记.docx》由会员分享,可在线阅读,更多相关《ARM7的Bootloader和分散加载文件笔记.docx(20页珍藏版)》请在冰豆网上搜索。
ARM7的Bootloader和分散加载文件笔记
BootLoader概述
简单地说,在操作系统内核运行之前,通过一小程序,可以初始化硬件设备、建立内存空间的映射图等,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核配置好相应的环境,也可以下载文件到系统板上的SDRAM,对Flash进行擦除与编程,这个小程序一般称为BootLoader。
可以说,一个功能完善的BootLoader已经相当于一个微型的操作系统了。
BootLoader作为系统复位或上电后首先运行的代码,一般应写入Flash存储器并从起始物理地址0x0开始。
BootLoader是非常依赖于硬件而实现的,而且根据实现的功能不同,其复杂程度也各不相同。
一个简单的BootLoader可以只完成USB口的初始化,而功能完善的BootLoader可以支持比较复杂的命令集,对系统的软硬件资源进行合理的配置与管理。
因此,建立一个通用的BootLoader几乎是不可能的。
系统初始化代码直接对ARM微处理器内核及硬件控制器编程,多采用汇编语言编程,初始化代码一般应包括如下典型任务:
1. 定义程序入口点;
2. 设置异常和中断向量表;
3. 初始化存储设备;
4. 初始化堆栈指针寄存器;
5. 初始化用户执行环境;
6. 呼叫主应用程序。
1.1定义程序入口
初始化代码必须定义整个程序的入口点。
通过伪指令Entry指定编译器保留该段代码,同时配合链接器的设置,确定整个程序的入口点。
1.2设置异常和中断向量表
1.3初始化存储设备
1. 存储器类型和时序的配置
2. 存储器的地址分配与地址重映射
一种典型的存储器地址重映射过程描述如下:
当系统上电或复位以后,PC指针指向0x0,程序从0x0地址开始执行,因此,为了能正确读取代码,要求此时Flash(或其它类型的ROM)的起始地址为0x0。
但Flash(或其它类型的ROM)的访问速度大大低于RAM,每次产生异常后,都要从Flash(或其它类型的ROM)的异常向量表调转到相应的处理程序,会影响异常的响应速度,因此,系统便提供一种灵活的地址重映射方法,在系统完成必要地初始化以后,将RAM安排到0x0地址处,而将原来位于0x0处的Flash(或其它类型的ROM)安排到其他的地方上去,加快异常的响应速度。
这个过程中最容易出错的地方是如何保证程序执行流程的连续性。
因为PC指针最初在Flash里取指令执行,在进行地址重映射以后,Flash(或其它类型的ROM)被安排到其他地址上去了,而当前地址被安排为RAM,如果事先没有对RAM的内容进行正确地设置,在往下取指令执行就会出错,即程序的连续性被存储器地址重映射这种变化所打断。
常用的处理方法是:
先将Flash(或其它类型的ROM)的内容全部复制到RAM中,然后再进行地址重映射。
此时尽管Flash(或其它类型的ROM)和RAM的物理地址发生了变化,但由于RAM中的内容与原来的Flash(或其它类型的ROM)是一样的,PC指针就可以继续取得正确地指令执行,从而保证了程序流程的连续性。
ARM的存储器映射与存储器重映射
arm处理器本身所产生的地址为虚拟地址,每一个arm芯片内都有存储器,而这个芯片内的存储器的地址为物理地址。
我们写程序的目的是为了利用芯片内的存储器,因此我们要知道存储器的地址,即物理地址,所以虚拟地址和物理地址之间必然存在一定的转换关系,这就是映射。
把虚拟地址按照某种规则转换成物理地址的方法就为存储器映射。
物理地址表示了被访问的存储器的位置。
存储器映射有两种映射规则--大端映射和小端映射。
存储器映射是指把芯片中或芯片外的FLASH,RAM,外设,BOOTBLOCK等进行统一编址。
即用地址来表示对象。
这个地址绝大多数是由厂家规定好的,用户只能用而不能改。
用户只能在挂外部RAM或FLASH的情况下可进行自定义。
ARM7TDMI的存储器映射可以有0X00000000~0XFFFFFFFF的空间,即4G的映射空间,但所有器件加起来肯定是填不满的。
一般来说,0X00000000依次开始存放FLASH——0X00000000,SRAM——0X40000000,BOOTBLOCK,外部存储器0X80000000,VPB(低速外设地址,如GPIO,UART)——0XE0000000,AHB(高速外设:
向量中断控制器,外部存储器控制器)——从0XFFFFFFFF回头。
他们都是从固定位置开始编址的,而占用空间又不大,如AHB只占2MB,所以从中间有很大部分是空白区域,用户若使用这些空白区域,或者定义野指针,就可能出现取指令中止或者取数据中止。
由于系统在上电复位时要从0X00000000开始运行,而第一要运行的就是厂家固化在片子里的BOOTBLOCK,这是判断运行哪个存储器上的程序,检查用户代码是否有效,判断芯片是否加密,芯片是否IAP(在应用编程),芯片是否ISP(在系统编程),所以这个BOOTBLOCK要首先执行。
而芯片中的BOOTBLOCK不能放在FLASH的头部,因为那要存放用户的异常向量表的,以便在运行、中断时跳到这来找入口,所以BOOTBLOCK只能放在FLSAH尾部才能好找到,呵呵。
而ARM7的各芯片的FLASH大小又不一致,厂家为了BOOTBLOCK在芯片中的位置固定,就在编址的2G靠前编址的位置虚拟划分一个区域作为BOOTBLOCK区域,这就是重映射,这样访问<2G即<0X80000000的位置时,就可以访问到在FLASH尾部的BOOTBLOCK区了。
BOOTBLOCK运行完就是要运行用户自己写的启动代码了,而启动代码中最重要的就是异常向量表,这个表是放在FLASH的头部首先执行的,而异常向量表中要处理多方面的事情,包括复位、未定义指令、软中断、预取指中止、数据中止、IRQ(中断),FIQ(快速中断),而这个异常向量表是总表,还包括许多分散的异常向量表,比如在外部存储器,BOOTBLOCK,SRAM中固化的,不可能都由用户直接定义,所以还是需要重映射把那些异常向量表的地址映到总表中。
为存储器分配地址的过程称为存储器映射,那么什么叫存储器重映射呢?
为了增加系统的灵活性,系统中有部分地址可以同时出现在不同的地址上,这就叫做存储器重映射。
重映射主要包括引导块“BootBlock”重映射和异常向量表的重映射。
1.引导块“BootBlock”及其重映射
BootBlock是芯片设计厂商在LPC2000系列ARM内部固化的一段代码,用户无法对其进行修改或者删除。
这段代码在复位时被首先运行,主要用来判断运行哪个存储器上面的程序,检查用户代码是否有效,判断芯片是否被加密,系统的在应用编程(IAP)以及在系统编程功能(ISP)等。
BootBlock存在于内部Flash,LPC2200系列大小为8kb,它占用了用户的Flash空间,但也有其他的LPC系列不占用FLash空间的,而部分没有内部Flash空间的ARM处理器仍然存在BootBlock。
重映射的原因:
BootBlock中有些程序可被用户调用,如擦写片内Flash的IAP代码。
为了增加用户代码的可移植性,所以最好把BootBlock的代码固定的某个地址上。
但由于各芯片的片内Flash大小不尽相同,如果把BootBlock的地址安排在内部Flash结束的位置上,那就无法固定BootBlock的地址。
为了解决上面的问题,于是芯片厂家将BootBlock的地址重映射到片内存储器空间的最高端,即接近2Gb的地方,这样无论片内存储器的大小如何,都不会影响BootBlock的地址。
因此当BootBlock中包含可被用户调用的IAP操作的代码时,不用修改IAP的操作地址就可以在不同的LPC系列的ARM上运行了。
2.异常向量表及其重映射
ARM内核在发生异常后,会使程序跳转到位于0x0000~0x001C的异常向量表处,再经过向量跳转到异常服务程序。
但ARM单条指令的寻址范围有限,无法用一条指令实现4G范围的跳转,所以应在其后面的0x0020~0x003F地址上放置跳转目标,这样就可以实现4G范围内的任意跳转,因此一个异常向量表实际上占用了16个字的存储单元。
以下为一张中断向量表:
LDR PC,ResetAddr
LDR PC,UndefinedAddr
LDR PC,SWI_Addr
LDR PC,PrefetchAddr
LDR PC,DataAbortAddr
DCD 0xb9205f80
LDR PC,[PC,#-0xff0]
LDR PC,FIQ_Addr
ResetAddrDCD ResetInit
UndefinedAddrDCD Undefined
SWI_AddrDCD SoftwareInterrupt
PrefetchAddrDCD PrefetchAbort
DataAbortAddDCD DataAbort
NouseDCD 0
IRQ_AddrDCD 0
FIQ_AddrDCD FIQ_Handler
重映射的原因:
由于ARM处理器的存储器结构比较复杂,可能同时存在片内存储器和片外存储器等,他们在存储器映射上的起始地址都不一样,因此ARM内核要访问的中断向量表可能不在0x0000~0x003F地址上,因此采用了存储器重映射来实现将存在与不同地方的中断向量表都映射到0x0000~0x003F地址上。
注意:
BootBlock也存在中断向量表,而且复位后这段代码首先映射到0x0000~0x003F地址上,也就是说复位后首先运行的是BootBlock程序。
各个存储区域的中断向量表也不尽相同。
1.4初始化堆栈
因为ARM有7种执行状态,每一种状态的堆栈指针寄存器(SP)都是独立的(注意System和User模式使用同一个SP)。
所以,对程序中需要用到的每一种模式都要给SP定义一个堆栈地址。
方法是改变状态寄存器内的状态位,使处理器切换到不同的状态,然后给SP赋值。
注意:
不要切换到User模式进行User模式的堆栈设置,因为进入User模式后就不能再操作CPSR回到别的模式了,可能会对接下去的程序执行造成影响。
1.5初始化用户执行环境
主要包括初始化临界I/O设备,初始化应用程序执行环境,改变处理器的运行模式和状态,使能中断4部分。
初始化临界I/O设备。
临界I/O设备是指哪些使能中断之前必须进行初始化的设备。
如果不对这些设备进行必要的初始化,它们可能会在使能中断后产生一些没有意义的中断请求,从而影响程序的运行。
初始化应用程序执行环境。
程序代码通过编译、链接后生成可执行映像文件,一个ARM映像文件由RO,RW和ZI三个段组成,其中RO为代码段,RW是已初始化的全局变量,ZI是未初始化的全局变量。
映像一开始总是存储在ROM/Flash里面的,其RO部分即可以在ROM/Flash里面执行,也可以转移到速度更快的RAM中执行;而RW和ZI这两部分是必须转移到可写的RAM里去。
所谓应用程序执行环境的初始化,就是完成必要的从ROM到RAM的数据传输和内容清零。
改变处理器的运行模式和状态。
ARM微处理器在复位或上电状态下的默认模式为系统管理模式,而在初始化代码中可能需要切换到其它模式进行必要的操作,如初始化各个模式下的堆栈指针寄存器。
因此,在系统的初始化过程中处理器模式一般会经历如图2所示的变化。
同时,ARM微处理器在复位后总是处于ARM状态,对于兼容Thumb指令的处理器如果应用程序的入口点对应Thumb指令,则必须将微处理器切换到Thumb状态。
使能中断。
如果系统需要使用中断,初始化代码应该使能中断。
中断使能可以通过清除CPRS中的中断禁止位来完成。
1.6呼叫主应用程序
当所有的系统初始化工作完成之后,就需要把程序流程转入主应用程序。
如果主应用程序是由C代码编写,可以通过以下两种方式进入C代码运行,最简单的情况如下:
IMPORTC_Entry;定义一个外部标号,最好不使用main
BC_Entry;跳转到该处执行
在ARM的ADS编译环境中,还另外提供了一种进入C代码的机制:
IMPORT__main
B__main
__main()是编译器提供的一个函数,负责完成库函数的初始化和对C代码运行环境的初始化,最后自动调转到main()函数执行,此时应用程序的主函数名必须是main()。
用户可以根据需要选择是否使用main()函数,如果想让系统自动完成初始化过程,可以使用main()函数;如果所有的初始化过程都由用户自己完成,则不使用main()。
ADS下的分散加载文件应用实例
ADS下的分散加载文件应用实例
load_region_name start_address|"+"offset [attributes][max_size]
{
execution_region_name start_address|"+"offset [attributes][max_size]
{
module_select_pattern ["("
("+"input_section_attr|input_section_pattern)
([","]"+"input_section_attr|","input_section_pattern))*
")"]
}
}
加载区(load_region):
指用来保存永久性数据(程序和只读变量)的区域;
执行区(execution_region):
程序执行时所表现出来的区域;程序执行时,从加载区域将数据复制到执行区;
load_region_name(加载区域名):
用于Linker区别不同的加载区域,最多31个字符;
start_address:
起始地址;
+offset:
前一个加载区域尾地址+offset,做为当前的起始地址,且offset为0或4的倍数;
attributes:
PI 与地址无关
RELOC 重新部署
OVERLAY 覆盖,允许多个可执行区域在同一个地址,ADS不支持
ABSOLUTE绝对地址(默认)
max_size:
该加载区域的大小;
execution_region_name:
执行区域名;
start_address:
链接是目标存放的地址,必须字对齐;
+offset:
同上;
attributes:
PI 与地址无关
OVERLAY 覆盖
ABSOLUTE绝对地址(默认)
FIXED 固定地址
UNINIT 不用初始化该区域的ZI段
module_select_pattern:
目标文件滤波器,支持通配符“*”和“?
”;*.o匹配所有目标,*(或“.ANY”)匹配所有目标文件和库。
input_section_attr:
每个input_section_attr必须跟随在“+”后;且大小写不敏感;
RO-CODE或CODE
RO-DATA或CONST
RO或TEXT,selectsbothRO-CODEandRO-DATA
RW-DATA
RW-CODE
RW或DATA,selectsbothRW-CODEandRW-DATA
ZI或BSS
ENTRY,thatisasectioncontaininganENTRYpoint.
FIRST,用于指定存放在一个执行区域的第一个或最后一个区域
LAST,同上
input_section_pattern:
段名;
汇编中指定段:
AREA vectors,CODE,READONLY
C中指定段:
#pragmaarmsection[sort_type[[=]"name"]][,sort_type="name"]*
sort_type:
code
rwdata
rodata
zidata
如果“sort_type”指定了但没有指定“name”,那么之前的修改的段名将被恢复成默认值。
#pragmaarmsection将恢复所有段名为默认值。
一般应用:
#pragmaarmsectionrodata="sram",code="sram"
.此间的“rodata”和“code”将定位在“sram”段中。
#pragmaarmsection
程序中对某区域的引用方法:
Load$$region_name$$Base Loadaddressoftheregion.
Image$$region_name$$Base Executionaddressoftheregion.
Image$$region_name$$Length Executionregionlengthinbytes(multipleof4).
Image$$region_name$$Limit Addressofthebytebeyondtheendoftheexecutionregion.
Image$$region_name$$ZI$$Base ExecutionaddressoftheZIoutputsectioninthisregion.
Image$$region_name$$ZI$$Length LengthoftheZIoutputsectioninbytes(multipleof4).
Image$$region_name$$ZI$$Limit AddressofthebytebeyondtheendoftheZIoutputsectionintheexecutionregion.
SectionName$$Base InputAddressofthestartoftheconsolidatedsectioncalledSectionName.
SectionName$$Limit InputAddressofthebytebeyondtheendoftheconsolidatedsectioncalledSectionName.
Base:
首地址;
Limit:
尾地址;
region_name:
RO、RW、ZI、load_region_name、execution_region_name;
例如:
RAM1区域的首地址:
Image$$RAM1$$Base
sram段首地址:
sram$$Base
注意:
“sram$$Base”不一定等于“Image$$RAM2$$Base”;
实例:
起始地址 大小
ROM:
0x00000000 256K 0x1fc保留为加密字
RAM 0x40000000 16K
SRAM 0x80000000 512K
程序在ROM中运行;
RAM主要用于程序堆栈及优先用于存放部分变量;
SRAM速度慢,主要用于存放大的数据表。
LOAD_ROM10x00000000 ;指定该加载区域首地址
{
EXEC_ROM1 +0 0x1f8 ;没有前一加载区域,所以该执行区域首地址为加载去首地址
;并指定该区域长度
{
Startup.o(vectors,+FIRST) ;目标文件的vectors段放在该执行区域的第一段
irq.o(+RO) ;目标文件的所有RO段放在该执行区域
swi.o(+RO)
}
}
LOAD_ROM20x00000200 ;第二个加载区域
{
EXEC_ROM2 +0 0x3e600
{
*(+RO) ;所有目标文件和库文件中的RO段存放在该区域
}
RAM1 0x40000000 0x4000
{
*(+RW,+ZI) ;所有目标文件和库文件的RW和ZI段存放在该区域
}
SRAM2 0x80000000 0x80000
{
*(sram) ;所有目标文件中的sram段存放在该区域
}
}
实例二:
Load_region1 0x00000000 0x1fc
{
EXEC_ROM1 +0
{
Startup.o(vectors,+FIRST)
irq.o(+RO)
}
}
Load_region2 0x000002000x3e600
{
EXEC_ROM2 +0
{
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ARM7 Bootloader 分散 加载 文件 笔记