1.爲什麼需要uboot,不能直接用linux啓動。
答:linux內核對uboot初始化過的硬件照樣要重新初始化一遍,那麼爲什麼需要uboot呢,因爲linux內核很大,爲了減少硬件成本,必須放在相對便宜的儲存器中。要知道,CPU只能夠訪問具有直接運行代碼的存儲設備,即內存。
而對於要啓動設備而已,這個內存不僅要cup能夠直接訪問,而且斷電不丟失數據。既然要有這麼個內存,那麼爲了花費更小的硬件成本,就必須讓內存儘量小,這也就是不能用來直接開啓linux內核的原因。用儘可能短小精悍的代碼初始化必要的硬件後,就把內核搬運到內存中(斷電數據丟失,即RAM)中,然後啓動內核,這是目前所有設備都採用的一種非常的設計方案。
分析uboot,首先就要分析makefile,makefile和鏈接腳本(uboot.lds)決定了代碼的各種存放位置以及編譯和鏈接的先後順序。
.我們首先編譯uboot,make xxxx_config,查看makefile做了什麼事情:
%_config:: unconfig
@$(MKCONFIG) -A $(@:_config=) -->mkconfig -A xxxx
然後進入mkconfig
關鍵點:
line=`egrep -i "^[[:space:]]*${2}[[:space:]]" boards.cfg`
即查找有xxxx字符的這一行,然後把內容賦值給line變量
boards.cfg文件部分內容:
--------------------------------------------------------------------------------------------------------------------------
# Target ARCH CPU Board name Vendor SoC Options
###########################################################################################################
qong arm arm1136 - davedenx mx31
mx31ads arm arm1136 - freescale mx31
imx31_litekit arm arm1136 - logicpd mx31
omap2420h4 arm arm1136 - ti omap24xx
tnetv107x_evm arm arm1176 tnetv107xevm ti tnetv107x
smdk6450 arm arm11 smdk6450 samsung s5p6450
armadillo arm arm720t
ep7312 arm arm720t
impa7 arm arm720t
modnet50 arm arm720t
lpc2292sodimm arm arm720t - - lpc2292
SMN42 arm arm720t - siemens lpc2292
---------------------------------------------------------------------------------------------------------------------------
假設xxxx是qong那麼
line=qong arm arm1136 - davedenx mx31
關鍵代碼:set ${line}
這句代碼之後:從makefile傳遞給mkconfig的參數就是:$1=qong $2=arm $3=arm1136 $4=devedenx $5=mx31
繼續看mkconfig發現:
開始的
arch=""
cpu=""
board=""
vendor=""
soc=""
變成:
arch=$2
cpu=$3
board=$4
vendor=$5
soc=$6
關鍵點:
cd ${OBJTREE}/include2
ln -s ${LNPREFIX}arch-${cpu} asm/arch
ln -s ${LNPREFIX}proc-armv asm/proc
echo "ARCH = ${arch}" > config.mk
echo "CPU = ${cpu}" >> config.mk
echo "BOARD = ${board}" >> config.mk
cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include <config_defaults.h>
#include <configs/${CONFIG_NAME}.h>
#include <asm/config.h>
EOF
可以看出,創建了兩個文件:
include/config.mk //這個文件是給makefile使用的
include/config.h 編譯程序時的包含具體soc型號的頭文件
(此命令退出了)
這個命令的作用就是配置了我們需要針對的具體型號的配置信息。後續make的時候,就是根據這些信息配置編譯的。
2.make all
代碼片段:
ALL += $(obj)u-boot.srec $(obj)u-boot.bin $(obj)System.map $(U_BOOT_NAND) $(U_BOOT_ONENAND)
all: $(ALL)
$(obj)u-boot.hex: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O ihex $< $@
$(obj)u-boot.srec: $(obj)u-boot
$(OBJCOPY) -O srec $< $@
$(obj)u-boot.bin: $(obj)u-boot
$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
$(BOARD_SIZE_CHECK)
ifeq ($(CONFIG_S5PC210),y)
./mkbl2 u-boot.bin bl2.bin 14336
endif
$(obj)u-boot: depend \
$(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
一句話就是:
進入各個編譯目錄,講.c文件編譯成.o文件,然後根據u-boot.lds的鏈接規則,進行鏈接成文件u-boot,最重要的是最前面的代碼段是哪裏,這直接關係到設備已啓動的代碼是什麼
我查看的一個arch/arm/cpu/arm7目錄下的uboot-lds如下:
----------------------------------------------------------------------------------------------------------------------------------------------------------------
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
arch/arm/cpu/armv7/start.o (.text)
board/samsung/xyd4412/libxyd4412.o (.text)
arch/arm/cpu/armv7/exynos/libexynos.o (.text)
*(.text)
}
. = ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
. = ALIGN(4);
.data : {
*(.data)
}
. = ALIGN(4);
. = .;
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
. = ALIGN(4);
.rel.dyn : {
__rel_dyn_start = .;
*(.rel*)
__rel_dyn_end = .;
}
.dynsym : {
__dynsym_start = .;
*(.dynsym)
}
.bss __rel_dyn_start (OVERLAY) : {
__bss_start = .;
*(.bss)
. = ALIGN(4);
_end = .;
}
/DISCARD/ : { *(.dynstr*) }
/DISCARD/ : { *(.dynamic*) }
/DISCARD/ : { *(.plt*) }
/DISCARD/ : { *(.interp*) }
/DISCARD/ : { *(.gnu*) }
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------
可以看出,放在最前面的是arch/arm/cpu/armv7/start.o 那麼意味着start.o是入門點。
好了,makefile分析至此,後面就根據入口函數分析uboot走勢流程了