1. 程式人生 > >Bootloader介紹和Uboot原始碼結構

Bootloader介紹和Uboot原始碼結構

本文是對《嵌入式Linux應用開發完全手冊》的一個自我總結!

一. Bootloader介紹

1.Bootload引入的原因

Bootloader的作用是在系統啟動的時候初始化必要的硬體裝置,引導核心映象檔案,傳遞引數給核心,然後將控制權交給核心以結束自己的使命。總的來說就是為了引導作業系統。
Bootloader非常依賴具體的硬體,對每一個板子都有一個獨一無二的Bootloader。

2.Bootloader啟動方式

Bootloader有兩種啟動方式,分別對應著成熟的產品和開發中的產品,分別是:啟動載入模式下載模式

  • 啟動載入模式
    在系統啟動時,執行Bootloader,當Bootloader準備好載入核心的環境後就直接從FLASH中拷貝核心映象到記憶體,並且執行核心。

  • 下載模式
    該模式適合開發者。在開發過程中,所有東西都沒有定型,需要經常性的修改。所以一般不會將核心放到目標板上面,而是存在在宿主機上,通過串列埠、USB、網路將核心傳遞到目標板上。串列埠傳輸協議有xmodem、ymodem、zmodem;網路傳輸有tftp、nfs。一般採用TFTP傳輸,因為網路傳輸速度快很多。

像Uboot這種強大的Bootloader可以同時支援兩種模式。在預設情況下使用啟動載入模式,但是中間會有幾秒時間供開發者進入下載模式。

Bootloader的結構和啟動過程

嵌入式Linux軟體分為4類:

  • 引導載入程式
    分為固化在韌體中的boot(可選)和Bootloader兩大部分。PC機上的BIOS就是boot中的一種,對於大多數嵌入式裝置只有Bootloader。

  • Linux核心
    包含特製的Linux核心程式碼和核心啟動引數。核心啟動引數可以是Bootloader傳遞的,或者是編譯核心時選定的預設引數。

  • 檔案系統
    包含根檔案系統和建立在FLASH記憶體裝置上的檔案系統,其他檔案系統時掛載在根檔案系統之上的。

  • 使用者應用程式
    存放在檔案系統裡面。

boot parameters中存放的引數有IP地址等網路相關引數串列埠波特率命令列引數等等。這些引數會存放在與核心約定好的記憶體地址上。

Bootloader啟動的兩個過程

Bootloader的啟動分為多階段和單階段兩種方式。多階段啟動的Bootloader有更好的移植性,而且能實現更復雜的功能。第一階段用匯編語言實現,第二階段用C語言實現。

  • 第一階段
    1.硬體裝置初始化
    2.為載入Bootloader的第二階段程式碼準備RAM空間
    3.複製Bootloader的第二段程式碼到RAM空間中
    4.設定好棧
    5.跳轉到第二階段程式碼的C入口點

在第一階段的硬體初始化包括關閉watchdog、設定為SVC模式、關閉中斷、設定CPU的速度和時鐘頻率、RAM初始化等。這些並不都是必須的,比如設定CPU的速度和時鐘頻率可以放在第二階段。
其實將第二階段拷貝到RAM中也不是必須的,對於NOR Flash可以直接在上面執行程式碼,但是效率將會降低。對於NAND FLASH必須要進行第二段程式碼的拷貝,因為一般Bootloader的二進位制檔案大於100K,而S3C2440內部自帶的RAM才4K,不足以存放整個Bootloader。

  • 第二階段
    1.初始化本階段要使用的硬體裝置(串列埠、網絡卡、NAND FLASH對於下載模式是必須的)
    2.檢測系統記憶體對映(確定板上使用了多少記憶體、它們的地址空間)
    3.將核心映象和根檔案系統映象從FLASH上讀到RAM空間(對於不在FLASH上的核心和檔案系統不執行)
    4.為核心設定啟動引數

與核心的互動

Bootloader和核心的互動是單向的,只能從Bootloader向核心傳遞。與核心相互可以分為兩種:以核心要求的形式設定硬體,以核心要求的地方存放資料。

1.設定硬體

(1)CPU暫存器設定

  • R0 = 0

  • R1 = 機器型別ID;可參見/linux/arch/arm/tools/mach-types(在啟動核心時首先就是檢測CPU型別和mach型別是否正確)

  • R2 = 啟動引數標記列表在RAM中起始基地址

(2)CPU工作模式

  • 必須禁止中斷(IRQs和FIQs)

  • CPU必須是SVC模式

(3)Cache和MMU的設定

  • MMU必須關閉

  • 指令Cache可以開啟也可以關閉

  • 資料Cache必須關閉

2.存放資料

必須約定好引數的存放地址(通過R2暫存器傳遞),同時必須規範資料的結構。在Linux 2.4之後,核心期望以標記列表的形式來傳遞引數。標記列表以ATAG_CORE開始,以ATAG_NONE作為結束。

struct tag {
    struct tag_header hdr;
    union {
        struct tag_core     core;
        struct tag_mem32    mem;
        struct tag_videotext    videotext;
        struct tag_ramdisk  ramdisk;
        struct tag_initrd   initrd;
        struct tag_serialnr serialnr;
        struct tag_revision revision;
        struct tag_videolfb videolfb;
        struct tag_cmdline  cmdline;

        /*
         * Acorn specific
         */
        struct tag_acorn    acorn;

        /*
         * DC21285 specific
         */
        struct tag_memclk   memclk;
    } u;
};

上述程式碼是標記的結構體

    params = (struct tag *) bd->bi_boot_params;

    params->hdr.tag = ATAG_CORE;
    params->hdr.size = tag_size (tag_core);

    params->u.core.flags = 0;
    params->u.core.pagesize = 0;
    params->u.core.rootdev = 0;

    params = tag_next (params);

上述程式碼是設定標記ATAG_CORE

#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))

tag_next(t)用來移動指標

常用Bootloader

對於x86常見的Bootloader是LILO、GRUB等,對於ARM架構的CPU,有U-Boot和Vivi。

Vivi是Mizi公司針對SAMSUNG的ARM架構CPU專門設計的,基本上可以直接使用。不過初始版本只支援串列埠下載,速度慢。網上有各種改進版本,支援網路功能、USB功能、燒寫YAFFS檔案系統映像等。
U-boot則支援大多數的CPU,支援的功能強大,不過它的使用複雜。但是可以用來更方便地除錯程式。

二、Uboot原始碼結構

Uboot特性

U-boot有如下特性:

  • 開放原始碼

  • 支援多種核心:Linux、NetBSD、Vxworks、QNX、RTEMS、ARTOS、LynxOS

  • 支援多個處理器系列:PowerPC、ARM、x86、MIPS、XScale

  • 高度靈活的功能設定,適合U-Boot除錯、作業系統不同引導要求、產品釋出

  • 豐富的裝置驅動原始碼

  • 較為豐富的開發除錯文件與強大的網路支援

  • 支援NFS掛載、RAMDISK形式的根檔案系統

  • 支援NFS掛載、從Flash中引導壓縮或非壓縮系統核心

  • 可靈活設定、傳遞多個關鍵引數給作業系統、對Linux支援較為強勁

  • 支援目標板環境變數多種儲存方式,如Flash、NVRAM、EEPROM

  • CRC32校驗,可檢查Flash中核心、RAMDISK映象檔案是否完好

  • 上電自檢功能:SDRAM、FLASH大小自動檢測

  • 特殊功能:XIP核心引導

U-boot原始碼結構

接下來的分析都是對於U-boot-2010-03

U-boot的原始碼目錄可以分為4類:

  • 平臺相關或開發板相關目錄

  • 通用函式

  • 驅動程式

  • U-Boot工具、示例程式、文件

U-Boot頂層目錄說明

目錄 特性 說明
board 開發板相關 對應不同的電路板(即使CPU相同),比如smdk2410、sbc2410x
cpu 平臺相關 對應不同的CPU,比如arm920T、i386等,他們的子目錄可以進一步細分,比如arm920t下有at91rm9200、s3c24x0
lib_i386類似 平臺相關 某一架構下通用的檔案
include 通用函式 標頭檔案和開發板配置檔案,開發板的配置檔案都放在include/configs目錄下,U-Boot沒有圖形化配置選單,需要手動修改配置檔案中的巨集定義
lib_generic 通用函式 通用的庫函式,比如printf等
comment 通用函式 通用的函式,對下一層驅動程式的進一步封裝
disk 驅動程式 硬碟介面程式
drivers 驅動程式 各類具體裝置的驅動程式,基本上可以通用,他們通過巨集從外面引入平臺/開發板相關的函式
dtt 驅動程式 數字溫度測量器或者感測器的驅動
fs 驅動程式 檔案系統
nand_spl 驅動程式 NAND驅動程式
net 驅動程式 各種網路協議
post 驅動程式 上電自檢程式
rtc 驅動程式 實時時鐘的驅動
doc 文件 開發、使用文件
examples 示例程式 一些測試程式,可以使用U-Boot下載後執行
tools 工具 製作S-Recond、U-Boot格式映像的工具,比如mkimage

U-boot的配置、編譯、連線過程

編譯U-boot只需要兩步:

    make <board_name>_config 
    make all

之後就會在原始碼根目錄下生成三個檔案:

  • U-Boot.bin : 二進位制可執行檔案,可以直接燒入ROM、NOR Flash

  • U-Boot : ELF格式的可執行檔案

  • U-Boot.srec : Motorola S-Record格式的可執行檔案

在編譯完成之後會在tools子目錄下生成一些工具,比如mkimage,可以用來生成U_boot格式的核心映象uImage

U-Boot的配置過程

頂層makefile檔案中程式碼

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

將目標中的config字尾去掉,結果為smdk2410

實際上上述程式碼等價於:

./mkconfig smdk2410 arm arm920t smdk2410 samsung s3c24x0

mkconfig是位於根目錄下的指令碼檔案,接下來的很大一部分內容由它完成

mkconfig解析

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

說明了mkconfig中各個引數的含義

(1)確定開發板名稱BOARD_NAME

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

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

因為在命令中沒有-a、-n等符號,所以while開始的語句沒有執行。
執行完上述程式後BOARD_NAME = smdk2410

(2)建立標頭檔案之間的連線

if [ "$SRCTREE" != "$OBJTREE" ] ; then
...
else
    cd ./include
    rm -f asm
    ln -s asm-$2 asm
fi

rm -f asm-$2/arch

if [ -z "$6" -o "$6" = "NULL" ] ; then
    ln -s ${LNPREFIX}arch-$3 asm-$2/arch
else
    ln -s ${LNPREFIX}arch-$6 asm-$2/arch
fi

if [ "$2" = "arm" ] ; then
    rm -f asm-$2/proc
    ln -s ${LNPREFIX}proc-armv asm-$2/proc
fi

一般我們會在原始碼根目錄進行編譯,所以SRCTREE=OBJTREE,執行else部分的程式碼。

刪除原有的/include/asm,建立新的連線

ln -s /include/asm-arm /include/asm

$6!=NULL,所以執行else語句,刪除原有的/include/asm-arm/arm,建立新的連線,LNPREFIX為空

ln -s /include/asm-arm/arch-s3c24x0 /include/asm-arm/arch 

建立另一個連線

ln -s /include/asm-arm/proc-armv  /include/asm-arm/proc

(3)為頂層makefile建立config.mk

下面程式碼摘自頂層makefile

include $(obj)include/config.mk
export  ARCH CPU BOARD VENDOR SOC

接下來看mkconfig為config.mk中寫了什麼內容

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

# Assign board directory to BOARDIR variable
if [ -z "$5" -o "$5" = "NULL" ] ; then
    BOARDDIR=$4
else
    BOARDDIR=$5/$4
fi

建立/config.mk,輸出如下內容

ARCH = arm
CPU = arm920t
BOARD = smdk2410
VENDOR = samsung
SOC = s3c24x0
BORADDIR = samsung/smdk2410

(4)建立目標板相關標頭檔案

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

for i in ${TARGETS} ; do
    echo "#define CONFIG_MK_${i} 1" >>config.h ;
done

cat << EOF >> config.h
#define CONFIG_BOARDDIR board/$BOARDDIR
#include <config_defaults.h>
#include <configs/$1.h>
#include <asm/config.h>
EOF

APPEND=no,所以在include目錄下建立config.h

for i in ${TARGETS} ; do
    echo "#define CONFIG_MK_${i} 1" >>config.h ;
done

該語句不知道什麼意思,但是它沒有執行

所以最後會生成/include/config.h,其內容如下:

/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/samsung/smdk2410
#include <config_defaults.h>
#include <configs/smdk2410.h>
#include <asm/config.h>

可以看出我們需要在/include/config目錄下建立和我們的目標板相應的標頭檔案。需要在/board目錄下建立屬於開發板的目錄。

總結上述過程:
(1)BOARD_NAME=smdk2410
(2)建立標頭檔案之間的軟連線

ln -s /include/asm-arm /include/asm
ln -s /include/asm-arm/arch-s3c24x0 /include/asm-arm/arch 
ln -s /include/asm-arm/proc-armv  /include/asm-arm/proc

(3)為頂層makefile建立/include/config.mk

ARCH = arm
CPU = arm920t
BOARD = smdk2410
VENDOR = samsung
SOC = s3c24x0
BORADDIR = samsung/smdk2410

(4)建立/include/config.h

/* Automatically generated - do not edit */
#define CONFIG_BOARDDIR board/samsung/smdk2410
#include <config_defaults.h>
#include <configs/smdk2410.h>
#include <asm/config.h>

配置U-Boot

U-Boot並沒有圖形化配置介面,所以需要手動配置,配置的檔案是/include/configs/board_name.h
以/include/configs/smdk2410.h為例講解如何配置U-Boot,並且配置是如何影響編譯過程的。

配置檔案中有兩類巨集:

  • 定義巨集的存在
#define CONFIG_ARM920T  1   
#define CONFIG_S3C24X0  1   
#define CONFIG_S3C2410  1   
#define CONFIG_SMDK2410 1   

這類巨集能決定編譯檔案中的哪一部分

  • 對巨集進行賦值
#define CONFIG_SYS_CLK_FREQ 12000000
#define CONFIG_CS8900_BASE  0x19000300
#define CONFIG_BAUDRATE     115200

巨集定義可以影響makefile的編譯具體檔案中的某一段的編譯

COBJS-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o

上述程式碼取自/driver/rtc/Makefile

#ifdef CONFIG_S3C2410
    return (readl(&gpio->GPEDAT) & 0x8000) >> 15;
#endif
#ifdef CONFIG_S3C2400
    return (readl(&gpio->PGDAT) & 0x0020) >> 5;
#endif

上述程式碼取自/driver/i2c/s3c24x0_i2c.c

U-Boot的編譯、連線過程

接下來講解的是執行make all時編譯和連線的過程。從makefile中可以瞭解到U-Boot使用了哪些檔案、哪些檔案首先執行、可執行檔案佔用記憶體的情況。

確定makefile中與ARM相關的部分

include $(obj)include/config.mk
export  ARCH CPU BOARD VENDOR SOC
...
ifeq ($(HOSTARCH),$(ARCH))
CROSS_COMPILE ?=
endif

我們編譯的HOSTARCH為x86,而ARCH為arm,所以上述程式碼的CROSS_COMPILE ?= 不執行,所以我們要在make的時候加上CROSS_COMPILE = arm-linux-

在/lib-arm/config.mk檔案中定義了

CROSS_COMPILE ?= arm-linux-

但為了保險起見,還是在編譯時加上CROSS_COMPILE = arm-linux-

include $(TOPDIR)/config.mk

在makefile中還包含了根目錄下在config.mk

/config.mk分析

config.mk根據ARCH CPU BOARD VENDOR SOC定義了編譯器和編譯選項。

下列的程式碼摘自/config.mk

ifdef   VENDOR
BOARDDIR = $(VENDOR)/$(BOARD)
else
BOARDDIR = $(BOARD)
endif

其實這一段程式碼是多餘的,因為在/include/config.mk已經對BORADDIR賦了相同的值。

ifdef   ARCH
sinclude $(TOPDIR)/lib_$(ARCH)/config.mk 
endif
ifdef   CPU
sinclude $(TOPDIR)/cpu/$(CPU)/config.mk      
endif
ifdef   SOC
sinclude $(TOPDIR)/cpu/$(CPU)/$(SOC)/config.mk  
endif
ifdef   BOARD
sinclude $(TOPDIR)/board/$(BOARDDIR)/config.mk 

包含了各目錄下的config.mk檔案

其中/board/samsung/smdk2410/config.mk中包含了一個和連線有關的重要引數

TEXT_BASE = 0x33F80000

該檔案中只有這一行程式碼

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

上述語句相當於下列語句:

LDFLAGS = -T u-boot.lds -Ttext 0x33F80000

其中的obj為空

makefile中具體編譯內容

makefile中的目標檔案只有兩種OBJS、LIBS,其中OBJS是.o檔案,LIBS是.a檔案。

OBJS  = cpu/$(CPU)/start.o
ifeq ($(CPU),i386)
OBJS += cpu/$(CPU)/start16.o
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),ppc4xx)
OBJS += cpu/$(CPU)/resetvec.o
endif
ifeq ($(CPU),mpc85xx)
OBJS += cpu/$(CPU)/resetvec.o
endif

上述是所有和OBJS有關原始檔,可以看出只有一個原檔案/cpu/arm920t/start.o,除了這個檔案,原始碼樹中的所有其它檔案都被編譯成了靜態庫。

OBJS := $(addprefix $(obj),$(OBJS))

為OBJS加上字首

LIBS  = lib_generic/libgeneric.a
LIBS += lib_generic/lzma/liblzma.a
LIBS += lib_generic/lzo/liblzo.a
...

和LIBS有關的原檔案太多了

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

$(LIBS):	depend $(SUBDIRS)
        $(MAKE) -C $(dir $(subst $(obj),,[email protected]))

上述程式碼顯示進入相應的目錄後呼叫子目錄中的makefile,生成相應的目標檔案。

$(obj)u-boot:	depend $(SUBDIRS) $(OBJS) $(LIBBOARD) $(LIBS) $(LDSCRIPT) $(obj)u-boot.lds
        $(GEN_UBOOT)
ifeq ($(CONFIG_KALLSYMS),y)
        smap=`$(call SYSTEM_MAP,u-boot) | \
            awk '$$2 ~ /[tTwW]/ {printf $$1 $$3 "\\\\000"}'` ; \
		$(CC) $(CFLAGS) -DSYSTEM_MAP="\"$${smap}\"" \
            -c common/system_map.c -o $(obj)common/system_map.o
        $(GEN_UBOOT) $(obj)common/system_map.o
endif

$(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]

可見u-boot.bin是由u-boot經過轉換而成的,主要考慮u-boot的編譯過程。

連線方式由LDFLAGS決定

LDFLAGS = -T u-boot.lds -Ttext 0x33F80000

下面分析u-boot.lds檔案

$(obj)u-boot.lds: $(LDSCRIPT)
        $(CPP) $(CPPFLAGS) $(LDPPFLAGS) -ansi -D__ASSEMBLY__ -P - <$^ >[email protected]

在原始碼的根目錄中會生成我們需要的u-boot.lds,但是它是從/cpu/arm920t/u-boot.lds拷貝的,中間的過程不知道。

OUTPUT_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 = .;
}
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

這兩句在執行file命令時,會顯示

ENTRY(_start)

定義了入口點為_start,它存在在start.S中。

.globl _start
_start: b   start_code

後面的一大段可以看出cpu/arm920t/start.o 在最前面的,所以它最先執行,從該檔案的_start標號處開始執行。

U-Boot啟動過程原始碼分析

1.第一階段程式碼分析

第一階段的啟動程式碼包含兩個檔案:/cpu/arm920t/start.S/board/samsung/smdk2410/lowlevel_init .S
其中一個是和平臺相關的、另一個是和開發板相關的。

(1)硬體裝置初始化

以此完成如下設定:將CPU設定為SVC管理模式、關閉WATCHDOG、設定FCLK、HCLK、PCLK的比例(即設定CLKDIVN暫存器)、關閉MMU、CACHE。

(2)為載入Bootloader的第二階段程式碼準備RAM空間

所謂準備RAM空間,對於s3c2410通過在呼叫start.S中呼叫lowlevel_init函式來設定儲存控制器。

(3)複製Bootloader的第二階段程式碼到RAM空間

(4)設定好棧

(5)清零BBS段、跳轉到第二階段程式碼的C入口點start_amrboot函式

U-Boot記憶體使用情況

2.第二階段程式碼分析

第二階段呼叫的函式位於檔案/lib-arm/board.c
大致可以分為3個階段:

  • init_sequence中的函式

  • start_armboot函式後續呼叫的初始化函式

  • 呼叫main_loop(),位於/commen/main.c

U_Boot命令格式

U_BOOT_CMD(name,maxargs,rep,cmd,usage,help)

name : 命令的名字,它不是一個字串(不要用雙引號括起來)
maxargs : 最大的引數個數
repeatable : 命令是否可重複,可重複是指執行一個命令後,下次敲回車即可再次執行
command : 對應的函式指標
usage : 簡短的使用說明,這是個字串
help : 較詳細的使用說明,這是個字串

U_BOOT_CMD巨集在include/command.h中定義

比如bootm命令,它如下定義:

U_BOOT_CMD
{
    bootm, CFG_MAXARGS,1,do_bootm,"string1","string2"
};

巨集U_BOOT_CMD擴充套件後如下所示:

cmd_tbl_t _u_boot_cmd_bootm  __attribute__ ((unused,section(".u_boot_cmd"))) = 

{"bootm",CFG_MAXARGS,1,do_bootm,"string1","string2"};

對於每個使用U_BOOT_CMD巨集來定義的命令,其實都是在“.u_boot_cmd”段中定義一個cmd_tbl_t結構。

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

程式中就是根據命令的名字在段__u_boot_cmd_start和__u_boot_cmd_end 之間找到相應的cmd_tbl_t結構,然後呼叫它的函式(請參考*command/command.c中的find_cmd函式)

為核心設定啟動引數

U_Boot是通過標記列表向核心傳遞引數的。一般而言,設定記憶體標誌和命令列標記就可以了,在配置檔案中include/configs/smdk2410.h 中新增如下兩個配置項即可:

#define CONFIG_SETUP_MEMORY_TAGS 1
#define CONFIG_CMDLINE_TAG   1

相關推薦

Bootloader介紹Uboot原始碼結構

本文是對《嵌入式Linux應用開發完全手冊》的一個自我總結! 一. Bootloader介紹 1.Bootload引入的原因 Bootloader的作用是在系統啟動的時候初始化必要的硬體裝置,引導核心映象檔案,傳遞引數給核心,然後將控制權交給核

C++容器類的介紹例子原始碼

剛接觸容器時,可以簡單的把他看做一個可以各種型別(struct也是可以的)的陣列,思路和操作也和陣列差不多,就是命令使用的有些區別 C++容器類的簡單介紹 一、原型與建構函式 Vector的原型可定義為 vector > 其建構函式為 vector() //空的 v

shell腳本介紹、腳本結構執行、date命令用法、腳本中的變量

用法 nth shell 日歷 顯示 集合 不可 mon 結果 20.1 Shell腳本介紹 shell是什麽 shell是一種腳本語言 可以使用邏輯判斷、循環等語法 可以自定義函數 shell是系統命令的集合 shell腳本可以實現自動化運維,能大大增加我們的運維效率

20.1-4 shell腳本介紹 shell腳本結構執行 date命令用法 shell腳本中的變量

十六周五次課(4月17日)20.1 shell腳本介紹20.2 shell腳本結構和執行20.3 date命令用法%w 星期幾 %W今年的第幾周cal是顯示日歷的時間戳可以相互查詢 20.4 shell腳本中的變量20.1-4 shell腳本介紹 shell腳本結構和執行 date命令用法 shell腳本中

shell(1)介紹、腳本結構執行、date命令、腳本中的變量、腳本中邏輯判斷、文件目錄屬性判斷

shell語法 一、shell腳本介紹我自定的shell腳本基本是放在/usr/local/sbin/目錄下。 二、Shell腳本結構和執行腳本命令:bash +腳本文件路徑sh +腳本文件路徑查看腳本執行過程-x :bash -x 1.sh查看腳本是否語法

Web2.0簡單介紹軟件開發結構淺談

Web2.0簡單介紹和軟件開發結構淺談 1、Web2.0指的是利用Web的平臺,由用戶主導而生成內容的互聯網產品模式,為了區別由網站雇員主導生成內容的傳統網站而定義為Web2.0基於Web2.0這些特點所產生的具有代表性的服務如下:博客、內容源、WiKi、參與評論與評分的Digg機制、美味書簽、社會化網絡、

shell腳本介紹 shell腳本結構執行 date命令用法 shell腳本中的變量

實現 images 個數 直接 shel png fff 冒號 用法 一、shell腳本介紹shell腳本要想寫好,必須通過不斷地去練習寫才能寫好,沒有捷徑要在我們拿到一個需求的時候有一個腳本的大致思路,想到需求怎麽去實現shell腳本可以大大提高我們的工作效率二、shel

【小家java】SortedMapNavigableMap的使用介紹---TreeMap的原始碼簡單分析

相關閱讀 【小家java】java5新特性(簡述十大新特性) 重要一躍 【小家java】java6新特性(簡述十大新特性) 雞肋升級 【小家java】java7新特性(簡述八大新特性) 不溫不火 【小家java】java8新特性(簡述十大新特性) 飽受讚譽 【小家java】java9

wpa_supplicant 客戶端介紹原始碼安裝

linux 系統平臺: 一. wpa_supplicant介紹 WPA是WiFi Protected Access的縮寫,中文含義為“WiFi網路安全存取”。WPA是一種基於標準的可互操作的WLAN安全性增強解決方案,可大大增強現有以及未來無線區域網絡的資料保護和訪問控制水平。 Wp

資料結構(三)StackVector原始碼分析

一、基本概念: 1、棧是什麼? 是一個只能在某一端進行插入、刪除操作的線性表。 * 從棧頂插入一個元素稱之為入棧(push) * 從棧頂刪除一個元素稱之為出棧(pop) 2、圖解: 3、棧的實現: 鏈式儲存(連結串列) 順序儲存(陣列) 4

Vue學習(2)————————目錄檔案結構介紹基本取值

此檔案是配置檔案,在命令列裡選擇的內容 在裡面也可以顯示 cnpm install 也是根據此檔案來構建依賴 各種依賴包 開發的各種資源  執行專案描述資源 打包配置檔案,讓Ide寫的vue檔案伺服器可以識別 路由配置檔案 Vue裡面的

《2.uboot系統移植-第6部分-2.6.uboot原始碼分析2-啟動第二階段》

《2.uboot和系統移植-第6部分-2.6.uboot原始碼分析2-啟動第二階段》 第一部分、章節目錄 2.6.1.start_armboot函式簡介 2.6.2.start_armboot解析1 2.6.3.記憶體使用排布 2.6.4.start_armboot解析2 2.6.5.s

《2.uboot系統移植-第5部分-2.5.uboot原始碼分析1-啟動第一階段》

《2.uboot和系統移植-第5部分-2.5.uboot原始碼分析1-啟動第一階段》 第一部分、章節目錄 2.5.1.start.S引入 2.5.2.start.S解析1 2.5.3.start.S解析2 2.5.4.start.S解析3 2.5.5.start.S解析4 2.5.6.s

Git原始碼管理介紹使用

Git原始碼管理介紹和使用 大型專案協作開發,使用版本控制器 1.Git引入和簡單介紹 Git是分散式版本控制系統 為了方便多人協同開發,方便版本控制(隨時回退檢視開發進度) 1。分散式管理:開發電腦還是伺服器都可以版本提交管理 2.Git會在原始碼根目錄建立一個.git隱藏

Tensorflow原始碼解析1 -- 核心架構原始碼結構

1 主流深度學習框架對比 當今的軟體開發基本都是分層化和模組化的,應用層開發會基於框架層。比如開發Linux Driver會基於Linux kernel,開發Android app會基於Android Framework。深度學習也不例外,框架層為上層模型開發提

資料結構之赫夫曼樹的演算法介紹實現

一、基礎知識: (1)最優二叉樹(赫夫曼樹)的介紹: a、路徑長度:從樹中一個結點到另一個結點之間的分支構成這兩個結點之間的路徑,路徑上分支數目稱做路徑長度。 b、樹的路徑長度:從樹根到每一個結點之間的路徑長度之和。上一篇介紹的完全二叉樹就是這種路徑長度最短的二叉樹。 c、

【Spring原始碼閱讀】IOC核心容器基礎繼承體系結構

BeanFactory BeanFacotry作為Spring的根容器物件,提供了對Bean的基礎操作功能,包括例項化、配置、管理Bean等。 ApplicationContext ApplicationContext對BeanFactory進行了進一步地封裝,內建了Bean

輕量級富文字編輯器wangEditor原始碼結構介紹

1. 引言   wangEditor——一款輕量級html富文字編輯器(開源軟體)   從我釋出wangEditor到現在,大概有七八個月了,隨著近期增加的插入視訊,表情,地圖這三個功能,目前為止基本的功能已經大體完善了。這期間也修改了幾個bug,都是各位網友反映的。至

[Android原始碼分析]L2CAP的bind分析以及psmcid的介紹實現

繼續上文的socke的建立之後,我們自然而然就會想到下面的工作了,沒錯就是bind。 5.6 l2cap的bind分析     按照國際慣例,在建了socket之後,必然會有bind,哈哈~~ i

十六週二次課 2018.02.05 shell指令碼介紹、shell指令碼結構執行、date命令用法、shell指令碼中的變數

20.1 shell指令碼介紹微信公眾號部落格,20.2 shell指令碼結構和執行建立目錄,然後我們進去在裡面寫指令碼第一行是他表示接下來的命令是通過這一個直譯器操作解析的的,通常都是/bin/bash(如果你是在本機上執行那麼不用寫也行,因為它知道接下來的命令能夠在這臺機