当前位置 博文首页 > 想要去旅行:记一次uboot 中出现的 data abort 错误
最近调试 uboot 遇到一个很顽固的错误,遇到我是一脸懵啊,花了一天的时间去解决。
fs_open() 100,p=45fb0a2d len=1436 H
fs_open() 108
data abort
pc : [<45f9b688>] lr : [<45fa4d29>]
reloc pc : [<4a024688>] lr : [<4a02dd29>]
sp : 41f63b38 ip : 00000006 fp : 00006401
r10: 45ffc678 r9 : 41f67ee0 r8 : 45ffc018
r7 : 80000000 r6 : 45fb0a2d r5 : 0000059c r4 : 00000000
r3 : 000002ce r2 : 45fb0a2b r1 : 01c20c00 r0 : 45fb0fc7
Flags: Nzcv IRQs off FIQs off Mode SVC_32
Resetting CPU ...
resetting ...
首先感谢 BeanHuo 的博客,提供了解决思路 ----博文链接:关于uboot下data abort的问题
结合我实际的log ,可以看出在 0x4a024688 位置除了错,接下来用 objdump -S u-boot 来找到对应的汇编指令
4a024684: 4620 mov r0, r4
4a024686: bd70 pop {r4, r5, r6, pc}
acc += *sdata;
4a024688: f832 1f02 ldrh.w r1, [r2, #2]!
4a02468c: 440c add r4, r1
4a02468e: b2a4 uxth r4, r4
if(acc < *sdata) {
4a024690: 42a1 cmp r1, r4
++acc;
4a024692: bf84 itt hi
4a024694: 3401 addhi r4, #1
4a024696: b2a4 uxthhi r4, r4
4a024698: e7df b.n 4a02465a
...
发现出错的汇编指令 对应的代码函数如下,在执行 acc += *sdata 的时候出了错误。
u16_t
uip_chksum(u16_t *sdata, u16_t len)
{
u16_t acc = 0;
for(acc = 0; len > 1; len -= 2) {
acc += *sdata;
if(acc < *sdata) {
/* Overflow, so we add the carry to acc (i.e., increase by
one). */
++acc;
}
++sdata;
}
/* add up any odd byte */
if(len == 1) {
acc += htons(((u16_t)(*(u8_t *)sdata)) << 8);
if(acc < htons(((u16_t)(*(u8_t *)sdata)) << 8)) {
++acc;
}
}
return acc;
}
为什么在执行 acc += *sdata 的时候出了错误。sdata 指针位置这哪里?
方法1,可以加打印看。
方法2,根据汇编推算。
这里直接看汇编:
acc += *sdata;
4a024688: f832 1f02 ldrh.w r1, [r2, #2]!
4a02468c: 440c add r4, r1
4a02468e: b2a4 uxth r4, r4
这里需要知道 r2 的值, r2 的值根据出错时的打印可以看到
pc : [<45f9b688>] lr : [<45fa4d29>]
reloc pc : [<4a024688>] lr : [<4a02dd29>]
sp : 41f63b38 ip : 00000006 fp : 00006401
r10: 45ffc678 r9 : 41f67ee0 r8 : 45ffc018
r7 : 80000000 r6 : 45fb0a2d r5 : 0000059c r4 : 00000000
r3 : 000002ce r2 : 45fb0a2b r1 : 01c20c00 r0 : 45fb0fc7
r2 = 45fb0a2b
[r2, #2] 得到 45fb0a2d
需要找到 45fb0a2d 对应的 位置, 先根据 pc , reloc pc 得到 offset
offset = reloc pc - pc = 4a024688 - 45f9b688 = 4089000
45fb0a2d - offset = 45fb0a2d - 4089000 = 4a039a2d
在 u-boot.map 文集中找到 4a039a2d 对应的位置
6110: .rodata.data_flashing_html
6111- 0x000000004a039a2d 0x59d httpd/built-in.o
6112: .rodata.data_index_html
这是一个 const char 数组。
为什么会导致 data abort ??????
百思不得解,
百思不得解,
百思不得解,
终于在重新翻看文章时,注意到这么一段话
其实在出错时,uboot已经告诉我们如何去找出问题所在,如上面的问题,我们可以通过查看doc/README.arm-unaligned-accesses来找到出错的位置。
arm-unaligned-accesses ? 非对齐地址访问 ?
查找相关资料后,找到一篇有帮助的文章:内存不对齐访问(unaligned access)及汇编下宕机
文中指出,开启内存地址对齐错误的检查功能时,进行对齐地址访问会导致宕机,data abort
uboot的cpu内核初始化阶段,启动了内存地址对齐错误的检查功能;然后用ldr加载和str存储内存地址不对齐的空间会发生什么事情?
参考ARM架构手册中如下表,可知将因指令的地址对齐错误导致数据中止异常。如果你用如下指令将SCTLR.A置为0,将不会产生异常,实现了不对齐访问,较早的ARM架构不支持这种功能,ARMv7上可以支持。
再看这次的 45fb0a2d ,地址为奇数,刚好就是非对齐地址,难怪总是出错!!!
如何解决?
正好的我的是 ARMv7 , 是可以支持不对齐访问的,只要在Start.s 中将 Align 检测功能去掉。
重新编译运行,一切正常!
再次感谢以上两位博主的文章!