接着上一节的继续分析和实验
bl gpio_out
bl led1_on
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_cp15
#ifndef CONFIG_SKIP_LOWLEVEL_INIT_ONLY
bl cpu_init_crit /* 上一节分析到这里,面的lowlevel_init,我们初始化了ddr */
#endif
#endif
/* 同时开发吧制锁和K都打印出来了,说明下一步要执行_main */
/* 开发板制锁*/
ldr r0, = 0xe010e81c
ldr r1, = 0x301
str r1, [r0]
ldr r1, =0xe2900020
ldr r2, =0x4b
str r2, [r1]
bl _main
上一节分析了跳转到打印出了K就死掉了,首先我们判断_main子程序是否在16K以内。
打开u-boot.map查看_main的地址,发现0xce0小于16k,所以在16k以内,所以继续分析。
调到_main中继续分析,_main 要做的事
arch/arm/lib/crt0.S
/*
* entry point of crt0 sequence
*/
ENTRY(_main)
/*
* Set up initial C runtime environment and call board_init_f(0).
*/
#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_STACK) /* 我们没定义这个 */
ldr sp, =(CONFIG_SPL_STACK)
#else
/* 在s5pv210.h中定义,见下面分析,0x33000000 */
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
#endif
#if defined(CONFIG_CPU_V7M) /* v7M forbids using SP as BIC destination 不用分析*/
mov r3, sp
bic r3, r3, #7
mov sp, r3
#else
bic sp, sp, #7 /* 8-byte alignment for ABI compliance, sp 8字节对齐 */
#endif
mov r0, sp /* 把上面的0x33000000,作为参数传给下面c函数 */
bl board_init_f_alloc_reserve
mov sp, r0 /* c函数的返回值又给sp */
/* set up gd here, outside any C code */
mov r9, r0 /* r0即当前sp给r9, r9是gd全局变量的指针,同时作为参数传递给下面函数 */
bl board_init_f_init_reserve
mov r0, #0
bl board_init_f /* 把参数0,传给下面函数,并调用它 */
上面用到的宏
/* DRAM Base 我们的ddr_base就是这里,所以不用改*/
#define CONFIG_SYS_SDRAM_BASE 0x30000000
/* 0x34000000 */
#define CONFIG_SYS_LOAD_ADDR (CONFIG_SYS_SDRAM_BASE + 0x4000000)
/* 0x33000000 */
#define CONFIG_SYS_INIT_SP_ADDR (CONFIG_SYS_LOAD_ADDR - 0x1000000)
_main的前半部分的大体功能知道了,现在要确定到底有没有执行。
即调用的三个C函数都有没有在16k以内。
搜索u-boot.map,里面发现第一个函数就超出了16K(0xa8c8)。
所以我们要在执行这个之前把整个uboot搬移到ddr,并完成绝对跳转。
根据手册applicate_note给出的说明,编写代码。
在board/samsung/smdkv210/下增加mmc_relocate.c 文件,并添加搬移代码
typedef int _bool;
typedef _bool (*copy_sd_to_mem)(unsigned int,unsigned int, unsigned short, unsigned int*,_bool);
void mmc_relocate(void)
{
copy_sd_to_mem uboot_copy = (copy_sd_to_mem)(*(unsigned int*)(0xd0037f98));
unsigned int ch = *(volatile unsigned int*)(0xd0037488);
if(ch == 0xeb000000)
{
}
else if(ch == 0xeb200000)
{
/* 只要大于33号扇区就都可以,我搬移了400k */
uboot_copy(2, 49, 800,(unsigned int*) 0x34800000, 0);
}
}
在Makefile中增加
obj-y := smdkv210.o mmc_relocate.o
添加到lowlevel_init里面的ddr初始化后面
bl mem_ctrl_asm_init
bl mmc_relocate
/* 打印出搬移完的uboot的前四个字节数据 */
ldr r0, =0x34800000
bl uart_print_hex
为了今后方便烧写和测试,编写如下脚本
#! /bin/bash
./make-16k u-boot.bin u-boot-16k.bin
sudo dd iflag=dsync oflag=dsync if=u-boot-16k.bin of=/dev/sdb seek=1
sudo dd iflag=dsync oflag=dsync if=u-boot.bin of=/dev/sdb seek=49
使用如下命令查看uboot.bin的数据
hexdump -C u-boot.bin |less
发现和u-boot.bin一致,证明uboot搬移成功。
下面就是从16k的IRAM跳转到DDR运行了。
/* 开发板制锁*/
ldr r0, = 0xe010e81c
ldr r1, = 0x301
str r1, [r0]
ldr r1, =0xe2900020
ldr r2, =0x4b
str r2, [r1]
bl led3_on
/* 使用绝对跳转指令,跳转到_main的链接地址去运行 */
ldr pc, =jump_ddr
jump_ddr:
bl _main
还是打印的和之前的一样,没有增加什么。
理论上是要打印一些信息的,因为接下来的一段代码都是和硬件无关的。
后来查看了好久发现,人家用的是串口2打印的,虽然我在smdkv210.h中该了串口号,但新的uboot是用设备树进行设备管理的,这个串口2的地址写死了,不能通过smdkv210.h配置了。因为我设备树还没怎么学,所以就先不改了,继续用原来配置的串口2调试。将来学习了设备树,再修改串口号。
下面是打印出来的信息。
可以看到我的板子没oneNand,但却打印出来信息,说明最后应该是在oneNand这里又跑飞了。