ARM的启动代码(3):异常向量
ARM的启动代码(1):介绍
ARM的启动代码(2):AT91SAM9260启动详解
这次我们聊聊ARM的代码的具体编写。那么什么样的代码会涉及到这些问题呢?
1.Bootloader或者位于启动序列上进行加载其他应用程序的程序;
2.单独的二进制镜像,直接可以在ARM处理器上直接执行。
这两种代码都需要对ARM的启动过程有深入理解。说深入理解,其实只有一条,闹闹记住,ARM7,ARM9的异常向量表从地址0开始。这是铁打不能改变的事实。这样一来,所有的程序都要用0地址存储自己的向量表,这岂不是成了稀缺资源。所以不同家的ARM芯片都提供了一些办法解决这种问题。
对于arm7,很多芯片使用片内的flash。如at91sam7x256。为了方便,经常需要bootloader+应用程序的方式。At91sam7x256提供了一个叫bootMemory的地址,1Mbytes,从0x0~0x000FFFFF。可以映射成为内部的Flash和内部的SRAM。这个映射是:
BootMemory:0x0~0x000FFFFF,1Mbytes
InternalFlash:0x00100000~0x001FFFFF,1Mbytes
InternalSRAM:0x00200000~0x002FFFFF,1Mbytes
当BootMemory映射成InternalFlash,flash的地址仍然从0x00100000开始,但是从0x0访问,等同于访问0x00100000;当映射成为InternalSRAM,SRAM地址不变,访问0x0地址,等同于访问0x00200000。其实硬件做起来很简单,就是将地址线用逻辑电路稍微处理一下。
由于代码都要存放在FLASH里,否则,没电以后,啥都没有了,也无法再次启动。所以,异常向量要从0x0开始,那么自然也要把向量放在这个位置,7x256上电以后默认bootmemory映射从flash开始。也就是说,把向量放在0x00100000即可解决这样的问题。
当0x00100000被占用以后,bootloader的向量问题解决了,那用户代码的中断向量怎么办呢?不可能把bootloader的向量擦了,把用户自己的向量写入,那岂不是bootloader也完了?这里有个小技巧,如果用户程序从0x00101000开始,向量依然从这个位置开始。只不过,在打开中断,向量真正起作用前,将0x00101000这个地方向量到SRAM的首地址上,然后切换BootMemory映射SRAM。那么向量依然从0x0开始。这样的话,无论多少级boot代码,都可以完美的解决该问题。
ARM9除了以上的方法,还有个终极的利器,那就是MMU,你高兴放哪就放哪,在向量起作用之前,用MMU将其地址变换为0即可。一点技术含量都没有。
道理总是简单的,实现起来总是有点点弯弯绕。我们看看实际的实现吧。这是7x256的向量代码:
__vector:
LDR PC,[PC,#24];Absolutejumpcanreach4GByte
LDRPC,[PC,#24];Branchtoundef_handler
LDRPC,[PC,#24];Branchtoswi_handler
LDRPC,[PC,#24];Branchtoprefetch_handler
LDRPC,[PC,#24];Branchtodata_handler
DC320;Reserved
LDR PC,[PC,#24] ;Branchtoirq_handler
LDR PC,[PC,#24] ;Branchtofiq_handler
DC32_program_start
DC32ARM_ExceptUndefInstrHndlr
DC32ARM_ExceptSwiHndlr
DC32ARM_ExceptPrefetchAbortHndlr
DC32ARM_ExceptDataAbortHndlr
DC320
DC32ARM_ExceptIrqHndlr
DC32ARM_ExceptFiqHndlr
这里相对比较简单,对这个指令做一下解释。LDR PC,[PC,#24]是将当前PC+24的地址的值载入到PC寄存器中。由于ARM流水线的问题,当前执行的指令,地址已经是后面两条了。所以,是+24并不是+32。也就是把_program_start加载入PC指针里。这段代码已经消除了指令当前位置对跳转位置的影响,可以随意的拷贝到任意的地方去执行。这段代码放在0x200000地方,可以正常执行;放在0x100000地方也可以正常执行。
RTEMS的ARM9(CSB337)启动向量:
vector_block:
ldrpc,Reset_Handler
ldrpc,Undefined_Handler
ldrpc,SWI_Handler
ldrpc,Prefetch_Handler
ldrpc,Abort_Handler
nop
ldrpc,IRQ_Handler
ldrpc,FIQ_Handler
Reset_Handler:bbsp_reset
Undefined_Handler:bUndefined_Handler
SWI_Handler:bSWI_Handler
Prefetch_Handler:bPrefetch_Handler
Abort_Handler:bAbort_Handler
nop
IRQ_Handler:bIRQ_Handler
FIQ_Handler:bFIQ_Handler
Rtems是个复杂的操作系统,在汇编代码里安装的只是一个简单的复位向量。其它向量都只是简单的死循环。操作系统运行起来以后,还要再次安装向量的。向量指向操作系统的复杂的处理函数。但不管这些,向量存储的地址是没有改变的。Link脚本上可以看到向量被放在内部的SRAM的首地址上。(CSB337)
SECTIONS
{
.base:
{
_sram_base=.;
/*reserveroo
ARM启动代码异常向 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)