|
我的平台是skyeye1.2.8+u-boot1.2.0+smdk2410,在运行的时候会出现大量的“bus read error”错误,或者u-boot跑飞出现乱码信息。我想这个问题应该很多人都遇到了,我用gdb终于发现了问题所在。通过调试发现skyeye设计确实不错,很有研究的价值。现将我的“发现之旅”帖出来共享,希望对大家加深对skyeye的了解有所帮助,但愿能有更多的爱好者加入对skyeye的研究。
1.2.8相对1.2.6最大的改变就是将存储管理这一块做成相对独立的模块,我想这样做的目的应该是能够把更多的精力放在新平台新架构的研发。出现问题我初步想法可能就是在这个改变上。通过与1.2.6上跑u-boot-1.2.0的输出信息进行比较,发现在输出版本号的时候会出错,在u-boot的display_banner函数中有这样一行:
printf ("\n\n%s\n\n", version_string);
如果正常会输出"U-Boot 1.2.0 2007.03 (Jun 26 2009 - 12:07:31)",现在是输出'%s'再出现大量乱码,初步可以认为是printf的问题。再来看看printf,它调用的是vsprintf,注意下面红色代码:
for (str=buf ; *fmt ; ++fmt) {
if (*fmt != '%') {
*str++ = *fmt;
continue;
}
。。。。。。
}
fmt是格式化字符串,也就是上面的"\n\n%s\n\n",目的是把%s筛选出来用可变参数代替。我在用gdb进行跟踪的时候发现fmt指到%的时候(*fmt != '%')条件并不满足,这是个奇怪的现象,于是进行汇编代码的单步,发现了问题:
33f8f028: e59d3008 ldr r3, [sp, #8]
33f8f02c: e2833001 add r3, r3, #1
33f8f030: e58d3008 str r3, [sp, #8]
33f8f034: e59d3008 ldr r3, [sp, #8]
33f8f038: e5d33000 ldrb r3, [r3]
在这里[sp, #8]就是fmt,r3是目标寄存器,存放从fmt取出的byte,在执行完ldrb后r3的高24位应该是0,低8位就是需要的数据,但是实际情况却是高24位不为0,这样(*fmt != '%')一直是true,这样生成的打印字符串会造成什么情况就不得而知了。
通过对skyeye代码的阅读,知道skyeye是动态翻译执行指令,因此ldrb为什么会有这种情况要到ARMul_Emulate32这个函数中去找问题。
在ARMul_Emulate32函数中对于ldrb的处理函数是LoadByte,调用顺序我列举几个关键点:LoadByte、bus_read、bank_read、mem_read、mem_read_byte,经过从调用顺序倒推发现问题出在mem_read中的代码:
*(uint8_t *)value = (uint8_t)mem_read_byte (offset);
执行完后*value的高24位确实不为0,我想原因在于value是uint32_t指针,如果未初始化成0,强制转换成uint8_t指针并赋uint8_t的值只会使它指向的内存数据的低8位改变,在用WRITEDEST将值传递给目标寄存器r3后就会造成上面所说的问题。做如下改动:
*value = (uint8_t)mem_read_byte (offset);
其实在1.2.6中就是这样做的,这也是1.2.6不出问题的原因。
另外请教陈老师:
对存储管理唯一全局对象global_memmap,为什么在实际使用中还是沿用1.2.6中的arm_mem全局对象?是基于什么考虑呢?
花了两天终于发现问题,还是要感谢这个问题,以前对gdb一窍不通,现在算是进门了。
[ 本帖最后由 alien75 于 2009-6-26 17:26 编辑 ] |
|