记一次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 检测功能去掉。

在这里插入图片描述
重新编译运行,一切正常!
再次感谢以上两位博主的文章!

发布了63 篇原创文章 · 获赞 20 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/agave7/article/details/102572974