AT91RM9200启动源代码crt0.s中的错误分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

AT91RM9200启动源代码crt0.s 中的错误分析
本人的AT91RM9200采用从norflash 启动方式,产品采用的norflash 型号为JS28F128J3D75,后来更换为JS28F128J3F75。

当采用JS28F128J3D75时代码正常启动,当采用JS28F128J3F75时代码无法正常启动,程序卡在了clearbss 函数中,因此对启动文件BOOT 源代码进行了分析。

系统上电检测到BMS 为低电平时,系统将外部norflash 地址映射为0x0,并且CPU 从0x0地址处读取命令执行。

此地址norflash 存储的是BOOT 程序。

BOOT 程序所包含的源代码包括:entry.S 、crt0.S 、initboot.c 、main.c 等。

程序在entry.S 中初始化时钟,调用AT91F_LowLevelInit 初始化函数,初始化各种运行模式下的堆栈范围,然后跳转至_main 函数中,_main 函数在crt0.S 文件中,进行了数据拷贝和bss 数据初始化工作,然后跳转至main 函数,进行端口打印和uboot 解压缩。

流程如下图所示:
BMS 为0,norflash 地址为0x0
entry.S crt0.S main.c initboot.c :初始化sdram 、
flash 、串口等
程序中定义的有初始值的全局变sdata 段,将本段
的数据拷贝至变量区。

程序中定义的未初始化的全局变
量,在变量区初始化为0
Gcc 在编译时按照链接文件ld.script 描述语言将源代码中的程序和只读变量放置在text 段,将已初始化的全局变量(包括初始化为0)按照地址排列至data 段,将未初始化的全局变量按照地址排列值bss 段。

ld.script : MEMORY {
ram : ORIGIN = 0x20000000, LENGTH = 0xf000 rom : ORIGIN = 0x00000000, LENGTH = 0xf000
}
SECTIONS { .text : {
_stext = . ; *(.text) *(.rodata) . = ALIGN(4); _etext = . ; } > rom .data : {
_sdata = . ; *(.data) *(.glue_7*) . = ALIGN(4); _edata = . ; } > ram .bss : {
_sbss = . ; *(.bss)
. = ALIGN(4); _ebss = . ; } > ram
}
由ld.script 文件可以看出,text 段在rom 区,起始地址为0x0,data 段在ram 区,起始地址为0x20000000,bss 段紧接着data 段存储。

链接文件定义了c 程序运行环境参数,当c 程序运行时,全局变量便会去0x20000000开始的ram 区相应的地址去查找。

在c 程序中引用的全局变量按照地址的形式使用,地址范围在ram 地址规定的范围里面。

当设备上电后,程序从flash 执行,全局变量从ram 中读取,由于ram 是易失性的,上电时里面的内容是乱的,因此在全局变量使用之前需要首先对全局变量区域进行初始化,这些初始化值被烧写在了flash 中。

因此烧写在flash 中的boot 文件结构为:
_stext
_etext
因此在上电时程序执行copydata 函数就是从flash 中将全局变量初始值拷贝至data 段,并且将ram 中bss 段数据清0,执行完后,数据结构如下图所示:
_stext
_etext _sdata
_edata _sbss
_ebss
0x0
0x20000000
此时,运行带有全局变量c 程序的环境已经建立起来。

由上面分析可知,程序运行时copydata 函数是将flash 地址_etext 开始的一段内容拷贝到0x20000000开始的地址内,大小为(_edata-_sdata )。

Clearbss 函数是将_sbss 开始的一段内容清0。

Crt0.s 内容如下: @ r0 -> start of flash @ r1 -> where to load data @ r2 -> start of program
.text .align
.global main,_main
main: _main:
# copy .data section ldr r3, =_etext ldr r4, =_sdata ldr r5, =_edata subs r5, r5, r4 bl copydata
# clear .bss section ldr r4, =_sbss ldr r5, =_ebss subs r5, r5, r4 mov r0, #0 bl clearbss
# and jump to the kernel b boot
copydata:
subs r5, r5, #4 ldr r6, [r3], #4
str r6, [r4], #4
bne copydata
mov pc, lr
clearbss:
subs r5, r5, #4
str r0, [r3], #4
bne clearbss
mov pc, lr
由代码可以看出,clearbss函数是将flash中烧写的全局变量初始值区后开始的bss 段大小空间清0。

而在实际使用中,程序会去找ram空间中的bss段,而非flash段,因此上面的程序存在错误,应该将“str r0, [r3], #4”改为“str r0, [r4], #4”,通过实验验证了这一结论。

在main.c文件文件中声明一个未初始化的全局变量,并将这一全局变量地址和内容打印出来,发现此地址在ram空间bss段,且值不为0,也就证明了原先的clearbss函数没有起到应有的作用。

当把“str r0, [r3], #4”改为“str r0, [r4], #4”后,重新试验,此变量值为0,验证了修改的正确性。

另外,如果声明的全局变量初始化为0,则打印出来的结果显示,此变量在data段,并不在bss段,因此不论clearbss是否正确,打印出来值都是0。

通过分析IAR编译器编译完成的stm32f103的启动代码发现烧写在flash中的全局变量初始值是经过算法优化的,所以在flash中data区大小是要小于ram中data区大小的。

修改crt0.s后,焊接JS28F128J3F75的板卡正常启动,问题得以解决。

但是为什么未修改前JS28F128J3D75可以启动,JS28F128J3F75无法启动,却不得而知。

通过分析两颗芯片的对比文件并未发现有太多的不同,仅仅增加了密码保护命令和对错误命令处理机制上不同。

通过前面的试验发现焊接JS28F128J3D75时,clearbss也并未真正把相应的flash空间清0。

怀疑是clearbss非正常写入flash时两颗芯片的处理方式不同吧,由于问题已经解决,也就不再去花太多力气去分析了。

相关文档
最新文档