那么内存初始化完成后,要做的就是将bl2的代码拷贝到内存中去了,原版的uboot在
arhc/arm/lib中
crt0.S的
relocate_code来对代码进行拷贝,但我们不使用这个(原因是我们的uboot放在nand和sd卡中,需要使用另一种方法来对代码进行拷贝),一如既往使用开发板的程序,移植过来。
重定位的地方就定在了lowlevel_init之后main之前。
代码过长,就不贴了,后期会整一个帖子专门放改过代码的地方。
注意,这里用到了
movi_bl2_copy这个函数,而这个函数也是需要移植的,当然,这个函数也需要放在前8k。
需要拷贝开发板的代码:
1、samsung-ubootinclude目录下的
movi.h拷贝到
u-boot-2014.10include目录下。
2、samsung-ubootcpus5pc11x目录
下的movi.c拷贝到
u-boot-2014.10oardsamsungX210目录中。
同样的,为了防止代码过于臃肿,删除
movi.c中不必要的代码。只保留我们需要用到的
movi_bl2_copy即可(当然不裁剪也可以,理论上应该是够用的)然后按照之前的方式,将
movi.o链接进前8k,编译的过程中会报错,原因基本上是因为缺少宏之类的,将缺少的宏补齐即可。然后我在复制代码完成后,打印了一个
'K'字符,来表示成功。然后跳转到
crt0里面的
main去执行
board_f函数。
之后编译,发现并不能使用(接下来就是开始排查问题的时候)
理论上,应该能够打印出
'K'这个字符,但实际上什么都没打印。于是我进行排查后,发现只要进入了
movi_bl2_copy后,就再也出不来了,直观的看就是串口只打印出
'B'不打印
'C'。
进入
movi_bl2_copy后,发现里面这个函数其实是
调用irom里面固化了的程序来copy代码到内存。问题应该就是出在这里面。
假设1:时钟初始化未完全,导致拷贝失败。
起因是我发现lowlevel中时钟的初始化并没有执行,但是立马就否定了,因为bl0中有对cpu做了初步的初始化,且咱们用sd卡烧录程序的时候,也应该是调用irom里面的固化程序来让将bl1拷贝到内部sram中的,所以否定。
假设2:DDR初始化未完成,所以拷贝到内存中失败了。
copy_bl2这个函数需要传入五个参数,分别是sd卡通道号,拷贝的起始block、拷贝的block数目、拷贝到内存的地址、固定为0。一看就知道是将bl2拷贝到内存中,那么如果内存初始化出错,应该也是拷贝不了的,况且这个函数是写死在irom里面,我们也无从得知里面是怎么样的,所以只能开始验证。
我将整个
movi_bl2_copy函数屏蔽掉,然后写下了以下的测试代码,主要作用就是往内存中写入数据,然后读出,看一不一致,如果一致的话打印
'Y',不一致的话打印
'N',结果是打印出'
Y',而且还能打印出
'C'这个字符。说明内存是能够正常使用的,去执行
movi_bl2_copy的时候出问题了。
假设3:C语言环境的栈设置有误。
栈里面保存了执行该函数前的任务信息,如果栈出问题了,就会导致信息丢失,就不能退回执行前的工作状态了。
于是我写了一个测试函数,在
movi_bl2_copy调用它,果然执行的时候,无法跳出。这样就说明栈设置有问题了。
最终问题定位: Review代码之后,发现在
start.S中设置了栈指针,
_TEXT_BASE地址为我们最开始设置的0x30000000,由于我们ARM的栈是满减栈,栈是向下生长,即:下一个地址为0x2fff_fffx,我们内存起始地址为0x30000000,所以就会导致栈数据丢失。
最后,将之前设置的
CONFIG_SYS_TEXT_BASE的值改大一点就可以解决上述问题了。这里我将
CONFIG_SYS_TEXT_BASE设置成一开始默认的0x3480_00000.