1. 程式人生 > >U-Boot啟動流程(Linux核心)的分析

U-Boot啟動流程(Linux核心)的分析

這一篇主要就是U-Boot的config.mk進行了分析。如果要使用開發板board/<board_name>,就先執行“make<board_name>_config”命令進行配置,然後執行”make all“,就可以生成 如下3個文件。
U-boot.bin:二進位制可執行檔案,它就是可以直接燒入ROM,NORFlash的檔案
u-Boot:ELF格式的可執行檔案,
U-Boot.srec:Motorla S-Record格式的可執行檔案
    對於S3C2410的開發板,執行”make smdk2410_config“."make all"後生成的U-Boot.bin可以燒入NOR Flash中執行,啟動後可以看到串列埠輸出一些資訊後進行控制介面。
1。 U-boot的配置過程 在頂層Makefile中可以看到如下程式碼:

...........
MKCONFIG    := $(SRCTREE)/mkconfig
........
smdk2410_config    :    unconfig
    @$(MKCONFIG) $(@:_config=) arm arm920t smdk2410 samsung s3c24x0

 這是在根目錄下的MAKEFILE檔案中的兩個語句,其中的MKCONFIG就是根目錄下的mkconfi檔案。$(@:_config=)的結果就是將”smdk2410_config“中的_config去掉,結果為“smdk2410”.所以“make smdk2410_config”實際上就是執行如下命令: 

./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

mkconfig的作用,在mkconfig檔案開頭第6行給出了它的用法

# Parameters: Target Architecture CPU Board [VENDOR] [SOC]

  對於S3C2410 S3C2440,它們被稱為Soc(systme on chip),上面除CPU外,還集成了包括UART,USB控制器,NANDFlash控制器等裝置,稱為片上外設。                   下面看一下makeconfig的作用。
(1)確定開發板名稱BOARD_NAME,相關程式碼如下:

APPEND=no    # Default: Create new config file
BOARD_NAME=""    # Name to print in make output
while [ $# -gt 0 ] ; do
    case "$1" in
    --) shift ; break ;;
    -a) shift ; APPEND=yes ;;
    -n) shift ; BOARD_NAME="${1%%_config}" ; shift ;;
    *) break ;;
    esac
done

對於./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0命令,其中沒有 "--","-a","-n"等符號,所以上面幾行不會執行。

[ "${BOARD_NAME}" ] || BOARD_NAME="$1"

執行完上面的這句後,BOADR_NAME的值等於第1個引數,即"s3ck2410"
(2)建立到平臺開發板相關折頭檔案的連結

if [ "$SRCTREE" != "$OBJTREE" ] ; then //判斷原始碼目錄和目標檔案目錄是否是一樣
    mkdir -p ${OBJTREE}/include
    mkdir -p ${OBJTREE}/include2
    cd ${OBJTREE}/include2
    rm -asm
    ln -s ${SRCTREE}/include/asm-$asm
    LNPREFIX="../../include2/asm/"
    cd ../include
    rm -rf asm-$2
    rm -asm
    mkdir asm-$2
    ln -asm-$asm
else
    cd ./include
    rm -asm
    ln -asm-$asm
fi

   直接在原始碼目錄下編譯時,條件不滿足,將執行else分支的程式碼,在else分支中,進入include目錄,刪除asm檔案,然後再次建立 asm檔案,並令它連結向asm-$2目錄,即asm-arm。

rm -asm-$2/arch //刪除asm-$2/arch目錄,即asm-arm/arch

if [ -"$6" -"$6" = "NULL" ] ; then //$6="s3c24x0"不為空,也不為NULL,執行else分支

    ln -s ${LNPREFIX}arch-$asm-$2/arch //LNPREFIX 為空,這個命令實際上等同於"ln - s arch-s3c24x0 asm-arm/arch"

else
    ln -s ${LNPREFIX}arch-$asm-$2/arch
fi

if [ "$2" = "arm" ] ; then //重新建立/asm-arm/proc檔案,並讓它連結向proc-armv目錄 

    rm -asm-$2/proc
    ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

(3)建立頂層MAKEFILE包含的檔案include/config.mk

#
# Create include file for Make
#
echo "ARCH = $2" > config.mk
echo "CPU = $3" >> config.mk
echo "BOARD = $4" >> config.mk

[ "$5" ] && [ "$5" != "NULL" ] && echo "VENDOR = $5" >> config.mk

[ "$6" ] && [ "$6" != "NULL" ] && echo "SOC = $6" >> config.mk

   對於./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0命令,上面幾行建立的config.mk檔案的內容如下

ARCH = arm
CPU = arm920t
BOARD = smdk2410
SOC =s3c24x0

(4)建立開發板相關的標頭檔案include/config.h

#
# Create board specific header file
#
if [ "$APPEND" = "yes" ]    # Append to existing config file
then
    echo >> config.h
else
    > config.h        # Create new config file
fi
echo "/* Automatically generated - do not edit */" >>config.h
echo "#include <configs/$1.h>" >>config.h
echo "#include <asm/config.h>" >>config.h

exit 0

APPEND維持原值"NO",所以config.h被重新建立,也就是執行echo "#include <configs/$1.h>" >>config.h
#include <configs/smdk2410.h>
總之,當你執行make smdk2410_config ,實際的作用就是執行./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0,它將產生如下的

幾種作用
(1) 開發板的名稱 BOARD_NAME等於 $1
(2)建立到平臺,開發板相關的標頭檔案的連結,如下所示
ln -s asm-$2 asm
ln -s arch-$6 asm-S2/arch
ln - s proc-armv asmn-$2/proc 如果$2不是arm的話,此行沒有
(3)建立頂層Makefile包含的incldue /config.mk,如下所示
ARCH = $2
CPU = $3
BOARD = $4
VENDOR = $ $5  為空,或者NULL的話,些行沒有
SOC = $6
(4) 建立開發板相關的標頭檔案include/config.h,如下 所示
#include <config.h/$1.h>
   從上面執行完命令後的結果,可以看出來,如果要在board目錄下新建一個開發板<board_name>的目錄,則在 include/configs 目錄下也要建立一個檔案<board_name>.h,裡面存放的就是開發板<board_name>的配置資訊。
3.U-Boot的編譯,連線過程

# load ARCH, BOARD, and CPU configuration
include $(obj)include/config.mk
export    ARCH CPU BOARD VENDOR SOC

# set default to nothing for native builds
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif

# load other configuration
include $(TOPDIR)/config.mk

這是根目錄下的Makefile中與ARM相關的程式碼。
第一行中包含的config.mk檔案,就是在第一開始配置過程中製作出來的include/conifg.mk檔案,我們在一開始配置U-boot時執行過mkconfig。mini2440 時生成的檔案,其中定義了ARCH,CPU,BOARD,SOC等。4個變數的值為arm,arm920t,smdk2410,s3c24x0.我們在執行mkconfig。mini2440時,其實執行的是如下的命令:

./mkconfig smdk2410 arm arm920t smdk2410 NULL s3c24x0

最後一句話include $(TOPDIR)/config.mk 包含頂層目錄的config.mk檔案。它根據上面4個變數的值確定了編譯器。編譯選項等。在頂層的config.mk中可以看到:

fdef    VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif
ifdef    BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk    # include board specific rules
endif

LDSCRIPT := $(TOPDIR)/board/$(BOARDDIR)/u-boot.lds

LDFLAGS += -Bstatic -T $(obj)u-boot.lds $(PLATFORM_LDFLAGS)
ifneq ($(TEXT_BASE),)
LDFLAGS += -Ttext $(TEXT_BASE)
endif

 在u-boot-2009.08\board\samsung\smdk2410\config.mk中定義了“TEXT_BASE = 0x33F80000”.所以最終結果是:BOARDDIR為smdk2410;LDFLAGS中有“-T \cpu\arm920t\u-boot.lds -Ttext 0x33f80000”.其中的-Ttext $(TEXT_BASE),這句指明瞭程式碼段的起始地址。為什麼是0x33F8 0000呢?這是將NAND中Uboot拷貝到RAM中的起始地址,所以在程式碼拷貝到RAM之前不能使用絕對地址來定址資料,只能用相對地址,在以下將用虛擬地址來指Uboot在RAM中的地址,也就是0x33F80000
繼續分析MAKEFIle檔案:

OBJS = cpu/$(CPU)/start.o
LIBS = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
LIBS += lib_generic/lzo/liblzo.a
LIBS += $(shell if [ -f board/$(VENDOR)/common/Makefile ]; then echo \
    "board/$(VENDOR)/common/lib$(VENDOR).a"; fi)
LIBS += cpu/$(CPU)/lib$(CPU).a

  從上面的第一行我們可以看到OBJS的第一個值為"cpu/$(CPU)/start.o",即"cpu/arm920t/start.o"。下面的幾行指定了LIBS變數,也就是平臺,開發板相關的各個目錄,通用目錄下相應的庫。OBJS LIBS所代表的.o,.a檔案構成了U-Boot,它們通過下面相應的原始檔編譯得到。

$(OBJS):    depend
        $(MAKE) -C cpu/$(CPU) $(if $(REMOTE_BUILD),$@,$(notdir [email protected]))

$(LIBS):    depend $(SUBDIRS)
        $(MAKE) -C $(dir $(subst $(obj),,$@))

 對於OBJS中的每個成員,都將進入cpu/$(CPU)目錄編譯它們,現在的OBJS為cpu/arm920t/start.o。它由cpu/arm920t/start.S編譯得到。對於LIBS中的每個成員,都將進入相應的子目錄執行"make命令"。當所有的OBJS,LIBS所表示的.o .a檔案都生成後,就剩最後的連線了,這對應MAKEFILE中的下面幾行:

$(obj)u-boot.srec:    $(obj)u-boot
        $(OBJCOPY) -O srec $< [email protected]

$(obj)u-boot.bin:    $(obj)u-boot
        $(OBJCOPY) ${OBJCFLAGS} -O binary $< [email protected]

$(obj)u-boot.ldr:    $(obj)u-boot
        $(obj)tools/envcrc --binary > $(obj)env-ldr.o
        $(LDR) -T $(CONFIG_BFIN_CPU) -c [email protected] $< $(LDR_FLAGS)

$(obj)u-boot.ldr.hex:    $(obj)u-boot.ldr
        $(OBJCOPY) ${OBJCFLAGS} -O ihex $< [email protected] -I binary

$(obj)u-boot.ldr.srec:    $(obj)u-boot.ldr
        $(OBJCOPY) ${OBJCFLAGS} -O srec $< [email protected] -I binary

$(obj)u-boot.img:    $(obj)u-boot.bin
        ./tools/mkimage -A $(ARCH) -T firmware -none \
        -a $(TEXT_BASE) -e 0 \
        -n $(shell sed --'s/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
            sed -'s/"[     ]*$$/ for $(BOARD) board"/') \
        -d $< [email protected]
................

GEN_UBOOT = \
        UNDEF_SYM=`$(OBJDUMP) -x $(LIBBOARD) $(LIBS) | \
        sed --'s/.*\($(SYM_PREFIX)__u_boot_cmd_.*\)/-u\1/p'|sort|uniq`;\
        cd $(LNDIR) && $(LD) $(LDFLAGS) $$UNDEF_SYM $(__OBJS) \
            --start-group $(__LIBS) --end-group $(PLATFORM_LIBS) \
            -Map u-boot.map -o u-boot
$(obj)u-boot:    depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
        $(GEN_UBOOT)

   先使用$(obj)u-boot:規則連線得到ELF格式的U-Boot,最後轉換為二進位制格式u-boot.bin.S-Record格式u-Boot.srec.其中LDFLAGS確定了連線方式,也就是-T \cpu\arm920t\u-boot.lds -Ttext 0x33f80000指定了程式的佈局地址,\cpu\arm920t\U-Boot.lds檔案如下:

UTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
    . = 0x00000000;

    . = ALIGN(4);
    .text :
    {
        cpu/arm920t/start.o    (.text)
        *(.text)
    }

    . = ALIGN(4);
    .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }

    . = ALIGN(4);
    .data : { *(.data) }

    . = ALIGN(4);
    .got : { *(.got) }

    . = .;
    __u_boot_cmd_start = .;
    .u_boot_cmd : { *(.u_boot_cmd) }
    __u_boot_cmd_end = .;

    . = ALIGN(4);
    __bss_start = .;
    .bss (NOLOAD) : { *(.bss) . = ALIGN(4); }
    _end = .;
}

    從cpu/arm920t/start.o (.text) 被放在程式的最前面,所以U-Boot的入口點在cpu/arm920t/start.s中,
總結一下U-Boot的編譯流程:
(1)首先編譯cpu/$(CPU)/start.s,對於不同的CPU,還可能編譯cpu/$(CPU)下面的其他檔案。
(2)然後,對於平臺開發板相關的每個目錄,每個通用目錄都使用它們各自的MAKEFILE生成相應和庫。
(3)將1,2步驟生成的.o.a檔案按照$(BOARDDIR)/config.mk 檔案中指定的程式碼段起始地址。$(obj)u-boot.lds 連線指令碼進行連線。
(4)第3步得到的是ELF格式的U-Boot,後面MAKEFILE還會將它轉換為二進位制格式 S-Record格式。

相關推薦

U-Boot啟動流程Linux核心分析

       前面一段時間一直在移植U-Boot,Linux核心和構建根檔案系統,其中有些地方還不是很明白,現在回過頭來,理解一下U-boot的啟動流程,以及u-Boot是如何載入引導核心啟動的。這裡的分析也都是以U-Boot-2009.08版本為基礎的,可能會和以前的版本

U-Boot啟動流程Linux核心分析

這一篇主要就是U-Boot的config.mk進行了分析。如果要使用開發板board/<board_name>,就先執行“make<board_name>_config”命令進行配置,然後執行”make all“,就可以生成 如下3個文件。 U-b

Android 8.0 系統啟動流程Linux核心啟動--kernel_init程序

    在上一篇文章中詳細的分析了kthreadd程序的啟動,init程序也是有idle程序去觸發啟動的,init程序分為前後兩部分,前一部分是在核心啟動的,主要是完成建立和核心初始化工作,內容都是跟Linux核心相關的;後一部分是在使用者空間啟動的,主要完成A

指令碼實現U盤自動掛載linux平臺

原文地址: 這裡是通過對udev 的設定,讓 udev 收到核心發來的 U 盤訊息後自動掛載,首先你要確保你的系統有udev的支援,如果有直接進行對udev設定,如果沒有請先移植udev,移植方法在本文最後面。  自動掛載:   1、在/etc/udev/rules.d

IMX6Q u-boot啟動流程分析

文章目錄 u-boot第一階段 中斷向量 reset復位向量程式碼 uboot第二階段 程式碼與中斷向量重定位 程式碼重定位過程 board_init_r函式 啟動Linux核心

Linux核心printk 格式說明

printk的格式說明符 :  int %d 或者 %x( 注: %d 是十進位制, %x 是十六進位制 )  u32 或者 unsigned int %u 或者 %x  long %ld 或者 %l

【ARM-Linux開發】U-Boot啟動過程--詳細版的完全分析

----------------------------------------------------------------------------------------------------------------------------------------

Linux 核心建立雙向迴圈連結串列

#define LIST_HEAD_INIT(name) { &(name), &(name) }    #define LIST_HEAD(name) \ struct list_h

[kernel 啟動流程] 第二章第一階段之——設定SVC、關閉中斷

本文是基於arm平臺。例子都是以tiny210(s5pv210 armv7)為基礎的。 [kernel 啟動流程]系列: 建議參考文件: ================================================ 零、說

Linux 核心雙向迴圈連結串列list_head

什麼是雙向迴圈連結串列就不說了,學習linux的應該都有C家族的基礎。 struct list_head {   struct list_head *next, *prev; }; list_head

塊IO層Linux核心原始碼分析

背景 本篇部落格重點分析塊IO層,試圖瞭解在linux原始碼中是如何實現塊IO的。 基本知識 塊裝置與字元裝置 塊裝置與字元裝置都是物理外設。簡單來說,塊裝置與字元裝置的最大區別在於塊裝置都隨機對資料片段進行讀寫的,而字元裝置都以順序對資料片段進

記憶體管理Linux核心原始碼分析

背景 本篇部落格試圖通過linux核心原始碼分析linux的記憶體管理機制,並且對比核心提供的幾個分配記憶體的介面函式。然後聊下slab層的用法以及介面函式。 核心分配記憶體與使用者態分配記憶體 核心分配記憶體與使用者態分配記憶體顯然是不同的,核心不可

(一)U-Boot啟動過程--詳細版的完全分析

--------------------------------------------------------------------------------------------------------------------------------------

Uboot啟動流程——u-boot.lds

.lds為連結指令碼 我們平時寫的程式碼也會有連結(ld)過程;x86下面輸入ld -verbose可以檢視連結指令碼 uboot生成映象也是需要lds的,下面為lds部分內容: OUTPUT

linux 核心啟動流程涉及到根檔案系統的問題

Linux核心啟動及檔案系統載入過程 當u-boot開始執行bootcmd命令。就進入Linux核心啟動階段,與u-boot類似,普通Linux核心的啟動過程也能夠分為兩個階段,但針對壓縮了的核心如uImage就要包含核心自解壓過程了。本文以linux-2.6.37版原始

Spring Boot啟動流程詳解

轉載:http://www.cnblogs.com/xinzhao/p/5551828.html 環境 本文基於Spring Boot版本1.3.3, 使用了spring-boot-starter-web。 配置完成後,編寫了程式碼如下: @

ARM Linux啟動流程分析——start_kernel前啟動階段彙編部分

本文整理了ARM Linxu啟動流程的第二階段——start_kernel前啟動階段(彙編部分),核心版本為3.12.35。我以手上的樹莓派b(ARM11)為平臺示例來分析Linux核心在自解壓後到跳轉執行start_kernel之前所做的主要初始化工作:包括引數有效性驗證

u-boot啟動Linux核心分析

一、uImage的結構 通過前面分析u-boot的啟動流程,我們可以知道,u-boot啟動核心的命令是bootcmd=nand read.jffs 0x30007FC0  kernel:bootm 0

U-Boot啟動過程原始碼分析2-第二階段

先總述:第一階段cpu/arm920t/start.S和board/smdk2410/lowlevel_init.S進行初始化,再跳到第二階段的入口點lib_arm/board.c中的start_armboot函式。 第二階段start_armboot函式需

[kernel 啟動流程] 第五章第一階段之——臨時核心頁表的建立

本文是基於arm平臺。例子都是以tiny210(s5pv210 armv7)為基礎的。 [kernel 啟動流程]系列: 建議參考文件: ================================================ 零、說明