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走势流程了