U-BOOT调试心得(一)
时间:2007-01-22 来源:marsky
第一次接触u-boot,先介绍一下环境,实验环境是mpc866系列的cpu--mpc852,当然之所以选择这款芯片主要是出于成本考虑。14$的价格只比arm9贵了6$,十分适合简单的网络应用。
u-boot采用1.16版本,是当时最新的,支持的开发板也毕竟多。看了一些开发板的config.h文件之后,我决定使用Adder的模版。
按照之前调试vxworks bsp时的寄存器参数修改了Adder.h文件后,把生成的u-boot文件用bdi2000下载到flash中。运行后出现mechine check interrupt,发生的位置是0x20002550。经过追踪发现是调试器实现的问题,具体如下:
首先是第一个开始执行的文件start.s。下面是我反汇编出来的代码:
20000118 <boot_cold>:
20000118: 38 60 10 02 li r3,4098
2000011c: 7c 60 01 24 mtmsr r3
20000120: 7c 7b 03 a6 mtsrr1 r3
20000124: 7c 74 22 a6 mficr r3
20000128: 7c 00 02 78 xor r0,r0,r0
2000012c: 7c 1c 23 a6 mtlctrl1 r0
20000130: 7c 1d 23 a6 mtlctrl2 r0
20000134: 7c 16 23 a6 mtcounta r0
20000138: 7c 17 23 a6 mtcountb r0
2000013c: 7c 70 8a a6 mfic_cst r3
20000140: 7c 78 8a a6 mfdc_cst r3
20000144: 3c 60 0a 00 lis r3,2560
20000148: 7c 70 8b a6 mtspr 560,r3
2000014c: 7c 78 8b a6 mtspr 568,r3
20000150: 3c 60 0c 00 lis r3,3072
20000154: 7c 70 8b a6 mtspr 560,r3
20000158: 7c 78 8b a6 mtspr 568,r3
2000015c: 3c 60 04 00 lis r3,1024
20000160: 7c 78 8b a6 mtspr 568,r3
20000164: 4c 00 01 2c isync
20000168: 3c 60 20 00 lis r3,8192
2000016c: 60 63 00 00 ori r3,r3,0
20000170: 38 63 01 7c addi r3,r3,380
20000174: 7c 68 03 a6 mtlr r3
20000178: 4e 80 00 20 blr
下面是start.s的源代码:
boot_cold:
boot_warm:
/* Initialize machine status; enable machine check interrupt */
/*----------------------------------------------------------------------*/
li r3, MSR_KERNEL /* Set ME, RI flags */
mtmsr r3
mtspr SRR1, r3 /* Make SRR1 match MSR */
mfspr r3, ICR /* clear Interrupt Cause Register */
/* Initialize debug port registers */
/*----------------------------------------------------------------------*/
xor r0, r0, r0 /* Clear R0 */
mtspr LCTRL1, r0 /* Initialize debug port regs */
mtspr LCTRL2, r0
mtspr COUNTA, r0
mtspr COUNTB, r0
/* Reset the caches */
/*----------------------------------------------------------------------*/
mfspr r3, IC_CST /* Clear error bits */
mfspr r3, DC_CST
lis r3, IDC_UNALL@h /* Unlock all */
mtspr IC_CST, r3
mtspr DC_CST, r3
lis r3, IDC_INVALL@h /* Invalidate all */
mtspr IC_CST, r3
mtspr DC_CST, r3
lis r3, IDC_DISABLE@h /* Disable data cache */
mtspr DC_CST, r3
#if !(defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || defined (CONFIG_FLAGADM))
/* On IP860 and PCU E,
* we cannot enable IC yet
*/
lis r3, IDC_ENABLE@h /* Enable instruction cache */
#endif
mtspr IC_CST, r3
/* invalidate all tlb's */
/*----------------------------------------------------------------------*/
tlbia
isync
/*
* Calculate absolute address in FLASH and jump there
*----------------------------------------------------------------------*/
lis r3, CFG_MONITOR_BASE@h
ori r3, r3, CFG_MONITOR_BASE@l
addi r3, r3, in_flash - _start + EXC_OFF_SYS_RESET
mtlr r3
blr
比较后我们发现,编译器编译了
#if !(defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || defined (CONFIG_FLAGADM))
/* On IP860 and PCU E, we cannot enable IC yet */
lis r3, IDC_ENABLE@h /* Enable instruction cache */
#endif
这段代码,也就是说,打开了指令catche,而出现machine check的位置,是在cup_init.c中的cpu_init_f函数中,见下段:
memctl->memc_br0 = CFG_BR0_PRELIM;
20002528: 3d 20 20 00 lis r9,8192
2000252c: 55 6b 05 2a rlwinm r11,r11,0,20,21
memctl->memc_or0 = CFG_OR0_PRELIM;
20002530: 3c 00 ff 00 lis r0,-256
20002534: 60 00 0f f6 ori r0,r0,4086
20002538: 61 6b 00 01 ori r11,r11,1
2000253c: 61 29 08 01 ori r9,r9,2049
20002540: 91 6a 00 00 stw r11,0(r10)
20002544: 91 2a 00 00 stw r9,0(r10)
20002548: 90 0a 00 04 stw r0,4(r10)
/*
* Reset CPM
*/
immr->im_cpm.cp_cpcr = CPM_CR_RST | CPM_CR_FLG;
2000254c: 38 00 80 01 li r0,-32767
20002550: b0 1f 09 c0 sth r0,2496(r31)
do { /* Spin until command processed */
__asm__ ("eieio");
20002554: 7c 00 06 ac eieio
} while (immr->im_cpm.cp_cpcr & CPM_CR_FLG);
20002558: a0 1f 09 c0 lhz r0,2496(r31)
2000255c: 70 09 00 01 andi. r9,r0,1
20002560: 40 82 ff f4 bne+ 20002554 <cpu_init_f+0xec>
20002564: 80 01 00 1c lwz r0,28(r1)
20002568: 83 e1 00 10 lwz r31,16(r1)
2000256c: 7c 08 03 a6 mtlr r0
20002570: 38 21 00 18 addi r1,r1,24
20002574: 4e 80 00 20 blr
出现在0x20002550,此时cpu访问的数据是非法数据且随机变化,每次开机都不同。
追踪时发现,在上面绿色的语句中:
20002540: 91 6a 00 00 stw r11,0(r10)
20002544: 91 2a 00 00 stw r9,0(r10)
20002548: 90 0a 00 04 stw r0,4(r10)
stw r11,0(r10) 此时r10=0xff000100,是br0的地址,但是r11是0x00000801,然后在下一句中stw r9,0(r10),r9存放的值是真正的br0的值,即0x20000801,但是此时LSU已经访问0x20002544寻找下一条指令,但由于此时的flash基地址已经变为0;因此会发生machine check也就不奇怪了。
之前之所以,频繁发生在0x20002550的错误,或者发生在20002554: eieio的错误,其实是由
#if !(defined(CONFIG_IP860) || defined(CONFIG_PCU_E) || defined (CONFIG_FLAGADM))
/* On IP860 and PCU E, * we cannot enable IC yet */
lis r3, IDC_ENABLE@h /* Enable instruction cache */
#endif
打开了指令catche,因此实际发生的问题的位置被延后了,因为在br0设置错误的时候,指令catche中已经load到了后面的几条正确的指令,但此时仍在执行指令的load操作,读到的指令当然是machine check,然后在指令catche中的指令执行完后,引发mechine check,但此时已经距离问题发生的位置有一定距离。
之所以会出现这样的问题是因为在memctl->memc_br0 = CFG_BR0_PRELIM; 之前,有这样一些处理:
reg = memctl->memc_br0;
reg &= BR_PS_MSK; /* Clear everything except Port Size bits */
reg |= BR_V; /* then add just the "Bank Valid" bit */
memctl->memc_br0 = reg;
这样,br0首先被清成0x00000801,当然这对于没有调试器的情况下,cpu会执行cs0上的存储器代码,而不会管他的地址。但是对于调试器则不会,我不是很清楚BDM调试器的原理,只能以JTAG调试器原理理解,虽然两者的原理完全不同,但是bdm试器的指令和数据应该和jtag一样,是在运行时,通过调试口插入到内核中,cpu以调试口输入的时钟工作。也就是说当配置bdi2000后,bdi2000会控制cpu从0x20000000的地址处执行指令,这也许是通过分析程序中的偏移量得到的。
这就是为什么使用bdi2000时,会出现mechine check ,而cpu自己运行时不会。解决的方法也很简单,把上面的语句删了就行了,我不太知道这句会在这里是什么作用,但是如果不放心的话,可以在调试完成后再加上,不会有什么影响。