好久好久前就買了s5pv210的開發板,一直都是東搞搞西搞搞,一點收穫也沒有,這次下決心來移植最新的uboot到u-boot-2012.10上,並通過這個博客記錄下來以防時間長給忘了,我的開發板是QT210的。s5pv210的啓動分爲BL0,BL1,BL2,BL0是出廠的時候就固化在IROM裏的,所以我們的uboot就要實現BL1和BL2,BL1在uboot裏叫做u-boot-spl.bin,BL2就是我們很熟悉的u-boot.bin了。在移植之前,我們先看下Alex Ling的linaro-2011.10 for mini210的UBOOT是怎麼實現的。這裏主要還是分析SPL部分,u-boot.bin是如何生成的現在資料很多,也很複雜,我這個菜鳥也是一知半解的,所以就不分析了。
1.頂層的Makefile,從中可以知道,我們要想生成u-boot-spl.bin就必須配置COFNIG_SPL,那麼u-boot-spl.bin依賴什麼呢,我們繼續
ALL-$(CONFIG_SPL) += $(obj)spl/u-boot-spl.bin
all: $(ALL-y)
搜索發現,是進入到uboot頂層目錄的spl目錄下執行Makefile的
$(obj)spl/u-boot-spl.bin: depend
$(MAKE) -C spl all
2.打開spl/Makefile分析,一開始就給我們導出CONFIG_SPL_BUILD
CONFIG_SPL_BUILD := y
export CONFIG_SPL_BUILD
然後分析目標,因爲我們的平臺是三星的,所以,會有兩個目標,一個是不帶頭信息的u-boot-spl.bin,一個是$(obj)$(BOARD)-spl.bin。
ALL-y += $(obj)u-boot-spl.bin
ifdef CONFIG_SAMSUNG
ALL-y += $(obj)$(BOARD)-spl.bin
endif
all: $(ALL-y)
搜索$(obj)$(BOARD)-spl.bin,發現,他是通過一個工具生成帶頭信息的u-boot-spl.bin
ifdef CONFIG_SAMSUNG
$(obj)$(BOARD)-spl.bin: $(obj)u-boot-spl.bin
$(TOPDIR)/board/$(BOARDDIR)/tools/mk$(BOARD)spl.exe \
$(obj)u-boot-spl.bin $(obj)$(BOARD)-spl.bin
endif
好了,Makefile就分析到這裏,知道了BL1是如何生成的了。下面裏分析代碼了。
首先分析arch/arm/cpu/armv7/start.S
reset:
bl save_boot_params
/*
* set the cpu to SVC32 mode
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
/* the mask ROM code should have PLL and others stable */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
/* Set stackpointer in internal RAM to call board_init_f */
call_board_init_f:
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR)
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
ldr r0,=0x00000000
bl board_init_f
其中,cpu_init_crit中主要做初始化了memory和串口,接下來就是調用C函數board_init_f了,在調用C函數之前得設置棧,board_init_f有兩個,一個是在arch/arm/lib/board.c,一個在board/samsung/mini210/mmc_boot.c那麼道理是那個呢,看各個目錄下的Makefile
1.arch/arm/lib/下的
ifndef CONFIG_SPL_BUILD
...
COBJS-y += board.o
...
endif
2.board/samsung/mini210/
ifdef CONFIG_SPL_BUILD
COBJS += mmc_boot.o
endif
得出,是board/samsung/mini210/mmc_boot.c了,打開void board_init_f(unsigned long bootflag)
{
__attribute__((noreturn)) void (*uboot)(void);
copy_uboot_to_ram();
/* Jump to U-Boot image */
uboot = (void *)CONFIG_SYS_TEXT_BASE;
(*uboot)();
/* Never returns Here */
}
得出,首先拷貝BL2完整的UBOOT到RAM裏去,然後從ram裏開始執行,然後就沒有了。那麼是如何拷貝的呢,這就得需要一個文檔了S5PV210_iROM_ApplicationNote_Preliminary_20091126.pdf中
好了,看看copy_uboot_to_ram代碼
typedef u32(*copy_sd_mmc_to_mem)
(u32 channel, u32 start_block, u16 block_size, u32 *trg, u32 init);
ch = *(volatile u32 *)(0xD0037488);
copy_sd_mmc_to_mem copy_bl2 =
(copy_sd_mmc_to_mem) (*(u32 *) (0xD0037F98));
u32 ret;
if (ch == 0xEB000000) {
ret = copy_bl2(0, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CONFIG_SYS_TEXT_BASE, 0);
} else if (ch == 0xEB200000) {
ret = copy_bl2(2, MOVI_BL2_POS, MOVI_BL2_BLKCNT,
CONFIG_SYS_TEXT_BASE, 0);
}
其中,MOVI_BL2_POS是1,MOVI_BL2_BLKCNT是49,CONFIG_SYS_TEXT_BASE是uboot在內存裏的其實地址。
複製完成之後就會在內存裏從u-boot.bin的start.S出開始重新執行了。