記一次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 檢測功能去掉。

在這裏插入圖片描述
重新編譯運行,一切正常!
再次感謝以上兩位博主的文章!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章