上传一个bare metal 二进制,使用go跳转执行,出现prefetch abort。日志如下:
IPQ5018# tftpboot led.bin
IPQ5018# go 44000000
## Starting application at 0x44000000 ...
prefetch abort
pc : [<44000004>] lr : [<4a92851b>]
reloc pc : [<44000004>] lr : [<4a92851b>]
sp : 4a882938 ip : 0000001c fp : 00000002
r10: 00000000 r9 : 4a882ea0 r8 : 4a97dae8
r7 : 4a9284f1 r6 : 00000002 r5 : 44000000 r4 : 4a889374
r3 : 44000000 r2 : 4a889374 r1 : 4a889374 r0 : 00000001
Flags: nzCv IRQs off FIQs off Mode SVC_32
Resetting CPU ...
经过搜索,是预取指令失败,在执行预取的那条指令的时候,将产生prefetch instruction异常。但是44000000这个地址肯定是可以访问的。经过搜索,之后,确定是这块区域没有可执行权限。disable mmu cache即可,修改方法如下:
19 /* Allow ports to override the default behavior */
20 __attribute__((weak))
21 unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
22 char * const argv[])
23 {
24 disable_caches();
25 return entry (argc, argv);
26 }
真正的原因其实是MMU的page table去掉了可执行权限:高通修改了相关代码:
arch/arm/lib/cache-cp15.c
66 #define UBOOT_CACHE_SETUP 0x100e
67 #define GEN_CACHE_SETUP 0x101e
69 __weak void dram_bank_mmu_setup(int bank)
70 {
71 bd_t *bd = gd->bd;
72 unsigned long long i;
73
74 debug("%s: bank: %d\n", __func__, bank);
75 for (i = bd->bi_dram[bank].start >> 20;
76 i < ((unsigned long long)bd->bi_dram[bank].start + (unsigned long long)bd->bi_dram[bank].size) >> 20;
77 i++) {
78 /* Set XN bit for all dram regions except uboot code region */
79 if (i >= (CONFIG_SYS_TEXT_BASE >> 20) && i < ((CONFIG_SYS_TEXT_BASE + 0x100000) >> 20))
80 set_section_dcache(i, UBOOT_CACHE_SETUP);
81 else
82 set_section_dcache(i, GEN_CACHE_SETUP);
83 }
84 }
参考:
https://e2e.ti.com/support/processors-group/processors/f/processors-forum/542410/am335x-u-boot-fails