uboot源碼分析 (1) --makefile分析

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章