天天看點

linux系統移植---bootloader(2)

一.bootloader

1.了解系統的啟動過程

 PC: BIOS(固件)------>bootloader(硬碟MBR)------>OS核心(拷貝到RAM)- ---->啟動系統

 bootlloadre的啟動過程一般分為2段,BL1 BL2

 嵌入式: bootloader(flash)------->OS核心(拷貝到記憶體)—>啟動系統

 S5PV210的啟動過程:

 IROM(固件)------>bootloader(flash,網絡,usb,SD,序列槽)加載到記憶體 ---->啟動OS核心---->系統

 bootloader有兩種狀态,一種是自啟動模式(加載核心),另一種叫下載下傳更新模式(指令行)

 bootloader的種類:e-boot u-boot r-boot vivi…

2.u-boot是bootloader的一種

Uboot官方下載下傳位址:

 ftp://ftp.denx.de/pub/u-boot/

 git://git.denx.de/u-boot.git

 http://git.denx.de/u-boot.git

u-boot的通用性:

 1)支援多種架構的CPU:PowerPC、ARM、X86、MIPS、NIOS、XScale

 2)支援多種作業系統:Linux Vxworks QNX…

3.分析uboot的源代碼

注意:檢視uboot源代碼時在source Insight文檔選項–>檔案過濾器加上[*c,*h,*s,*S]。

uboot源碼目錄下檔案夾的介紹:

1)cpu

 包含和CPU架構相關的代碼,u-boot支援的CPU在該目錄下都有一個子目錄 與之對應。

2)board

 包含和開發闆相關的檔案,每一個開發闆都以一個目錄的形式出現在該目錄下。

3)drivers

 本目錄下存放所有外圍晶片的驅動,網卡、USB、序列槽、LCD、Nand Flash等。

4)lib_arm

 支援ARM架構下的通用檔案。

5)include/configs/smdkv210single.h

 定義了大量的宏定義,配置u-boot的參數(如:晶振的頻率、序列槽的波特率、開發闆的IP位址)。

4.源代碼研究:

Makefile

1)确定編譯器(在Makefile檔案中加入下面兩行代碼确定編譯器)

126 ARCH = arm

127 CROSS_COMPILE = arm-linux-(根據實際工具添加)

2)uboot配置

make smdkv210single_config

Makefile:

2584 smdkv210single_config : unconfig

2585 @$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110

2586 @echo “TEXT_BASE = 0xc3e00000” > $(obj)board/samsung/smdkc110/config.mk

476 unconfig:

477 @rm -f $(obj)include/config.h $(obj)include/config.mk

478 $(obj)board//config.tmp $(obj)board/

138 bl nand_asm_init

//nand初始化

//做了非常重要的底層初始化

//回到cpu/s5pc11x/start.S

324 beq nand_boot

334 nand_boot:

335 mov r0, #0x1000

336 bl copy_from_nand

//将uboot從nand flash拷貝到外部DRAM

337 b after_copy

拷貝完成後

開啟MMU

初始化堆棧

清BSS段

//使用絕對跳轉跳轉到start_armboot執行(BL2)

411 ldr pc, _start_armboot

413 _start_armboot:

414 .word start_armboot

uboot的BL1的執行流程

1.關中斷,設定為管理模式

2.在lowlevel_init中進行底層初始化(看門狗,時鐘,記憶體,序列槽,nand)

3.将uboot搬運到外部DRAM—>0x23e00000

4.開啟MMU 0x23e00000---->0xc3e00000

5.初始化棧

6.清空BSS段

7.使用跳轉指令ldr pc, _start_armboot将代碼跳轉到BL2運作(外部DRAM中)

uboot的BL2

//lib_arm/board.c

291 typedef int (init_fnc_t) (void);

//定義了一個函數類型,傳回值為int,參數為void

start_armboot:

325 init_fnc_t **init_fnc_ptr;

362 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

363 if ((*init_fnc_ptr)() != 0) {

364 hang ();

365 }

366 }

//周遊init_sequence函數指針數組,執行其中的每一個函數

//init_sequence數組中儲存的是一系列初始化函數,執行失敗,報錯

gd_t bd_t

//include/asm-arm/global_data.h

typedef struct global_data {

bd_t *bd;

} gd_t;

//定義u-boot的全局資訊結構體

#define DECLARE_GLOBAL_DATA_PTR register volatile gd_t *gd asm (“r8”)

//定義一個寄存器變量儲存gd變量的位址,而且必須儲存在r8寄存器中

//include/asm-arm/u-boot.h

typedef struct bd_info {

ulong bi_arch_number; /機器碼(開發闆ID)/

ulong bi_boot_params; /uboot傳遞給核心的參數位址/

struct

{

ulong start;

ulong size;

} bi_dram[CONFIG_NR_DRAM_BANKS];

} bd_t;

//開發闆資訊結構體

//board/samsung/smdkc110.c

int board_init(void)

{

DECLARE_GLOBAL_DATA_PTR;

#ifdef CONFIG_DRIVER_SMC911X

smc9115_pre_init();

#endif

#ifdef CONFIG_DRIVER_DM9000

dm9000_pre_init();

#endif

gd->bd->bi_arch_number = MACH_TYPE;
//開發闆的機器碼,啟動核心時傳遞給核心(2456)
gd->bd->bi_boot_params = (PHYS_SDRAM_1+0x100);
//uboot傳遞給核心的參數所在的位址(0x20000100)

return 0;
           

}

int dram_init(void)

{

DECLARE_GLOBAL_DATA_PTR;

gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
//第一塊記憶體的起始位址(0x20000000)
gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;
//第一塊記憶體的大小(0x20000000) 512M
           

#if defined(PHYS_SDRAM_2)

gd->bd->bi_dram[1].start = PHYS_SDRAM_2;

gd->bd->bi_dram[1].size = PHYS_SDRAM_2_SIZE;

#endif

return 0;
           

}

最後執行main_loop

uboot的兩種模式:

自啟動模式:執行bootcmd環境變量中的指令

下載下傳更新模式:進入指令行

//commom/main.c

main_loop:

擷取環境變量bootdelay bootcmd

在bootdelay秒内,判斷序列槽是否有輸入

1>有,通過敲擊空格鍵,進入下載下傳更新模式(指令行)

GEC210#

可以在該提示符下執行鍵盤輸入的指令

2>沒有,進入自啟動模式,啟動核心

如何啟動核心?

通過擷取一個環境變量,bootcmd環境變量,該環境變量中存放了啟動核心相關指令,接着執行這些指令,啟動核心

bootcmd=tftp 20008000 zImage;bootm 20008000

//将核心鏡像zImage加載到20008000;到20008000去運作核心鏡像zImage

uboot的指令:

1>print(printenv):檢視目前環境的環境變量

print bootdelay

2>set(setenv):設定環境變量

set bootdelay 5

3>save(saveenv):儲存環境變量

4>tftp:通過tftp服務下載下傳在tftp伺服器目錄下的程式到記憶體中

tftp 30008000 led.bin

5>go:執行記憶體中的二進制代碼

go 30008000

6>bootm:啟動記憶體中的核心鏡像檔案zImage

bootcmd=tftp 20008000 zImage;bootm 20008000

7>nand系列指令

nand erase:擦nand flash

nand erase 0 100000

nand write:寫nand flash

nand write 20008000 0 100000

nand read:讀nand flash

nand read 20008000 0 100000

uboot源代碼中如何定義指令?

//include/command.h

struct cmd_tbl_s {

char *name; /指令名/

int maxargs; /最大參數個數/

int repeatable; /重複次數/ //指令對應的處理函數

int (*cmd)(struct cmd_tbl_s *, int, int, char *[]);

char *usage; /用法資訊/

#ifdef CFG_LONGHELP

char *help; /幫助資訊/

#endif

};

//uboot的指令結構體

typedef struct cmd_tbl_s cmd_tbl_t;

#define Struct_Section attribute ((unused,section (".u_boot_cmd")))

//__attribute__是GNU C對标準C的擴充,可以用來設定變量,函數,類型的屬性

//在這裡表示被該屬性修飾的變量,在連結時被該屬性修飾的變量必須放//到.u_boot_cmd段中

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

cmd_tbl_t _u_boot_cmd##name Struct_Section = {#name, maxargs, rep, cmd, usage, help}

//common/command.c

U_BOOT_CMD(

version, 1, 1, do_version,

“version - print monitor version\n”,

NULL

);

cmd_tbl_t __u_boot_cmd_version attribute ((unused,section (".u_boot_cmd"))) =

{version, 1, 1, do_version, “version - print monitor version\n”, NULL};

bootm指令:

//common/cmd_bootm.c

U_BOOT_CMD(

bootm, CFG_MAXARGS, 1, do_bootm,

“bootm - boot application image from memory\n”,

“[addr [arg …]]\n - boot application image stored in memory\n”

“\tpassing arguments ‘arg …’; when booting a Linux kernel,\n”

“\t’arg’ can be the address of an initrd image\n”

#if defined(CONFIG_OF_LIBFDT)

“\tWhen booting a Linux kernel which requires a flat device-tree\n”

“\ta third argument is required which is the address of the\n”

“\tdevice-tree blob. To boot that kernel without an initrd image,\n”

“\tuse a ‘-’ for the second argument. If you do not pass a third\n”

“\ta bd_info struct will be passed instead\n”

#endif

#if defined(CONFIG_FIT)

“\t\nFor the new multi component uImage format (FIT) addresses\n”

“\tmust be extened to include component or configuration unit name:\n”

“\taddr:<subimg_uname> - direct component image specification\n”

“\taddr#<conf_uname> - configuration specification\n”

“\tUse iminfo command to get the list of existing component\n”

“\timages and configurations.\n”

#endif

);

bootm 20008000

do_dootm函數---->do_bootm_linux函數(lib_arm/bootm.c)

---->theKernel (0, machid, bd->bi_boot_params);

開發闆ID 傳遞給核心的啟動參數的位址

2456 0x20000100

啟動核心,uboot到此結束

uboot的整個啟動過程:

1>start.S->前8K代碼在CPU的IRAM中執行(管理模式,關中斷)

2>lowlevel_init.S->關看門狗,初始化時鐘,記憶體,nand,序列槽

3>start.S->将整個uboot拷貝到外部DRAM中,為其運作在0xc3e00000做準備

開mmu,建棧,清bss段,使用ldr pc, _start_armboot跳轉到uboot的BL2

4>start_armboot->執行初始化函數清單(board_init,dram_init…)

5>main_loop->擷取bootdelay,bootcmd環境變量

6>執行bootcmd環境變量中的啟動指令tftp/nand read bootm

7>bootm指令->do_bootm->do_bootm_linux->theKernel(0,2456,0x20000100)

bootargs環境變量很重要

-ffixed-r8:編譯時不使用r8寄存器

cp uboot.bin /tftpboot

tftp 30008000 u-boot.bin

nand erase 0 100000

nand write 30008000 0 100000

繼續閱讀