【嵌入式開發】 Bootloader 詳解 ( 代碼環境 | ARM 啓動流程 | uboot 工做流程 | 架構設計)



做者 : 韓曙亮前端

博客地址 http://blog.csdn.net/shulianghan/article/details/42462795linux

轉載請著名出處編程


相關資源下載 windows

-- u-boot 源碼 http://download.csdn.net/detail/han1202012/8342761數組

-- S3C2440 文檔http://download.csdn.net/detail/han1202012/8342701sass

-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文檔http://download.csdn.net/detail/han1202012/8342709安全

-- S3C6410_Internal_ROM_Bootin 文檔 : http://download.csdn.net/detail/han1202012/8342725網絡

-- S3C6410X 文檔 : http://download.csdn.net/detail/han1202012/8342731架構

-- S5PV210_UM_REV1.1 文檔http://download.csdn.net/detail/han1202012/8342745app




一. Bootloader 簡介



1. Bootloader 簡介


Bootloader 做用 : 啓動系統時將 Kernel 帶入到內存中, 以後 Bootloader 就沒有用處了;

-- Bootloader 在 Linux 系統中的層次 : Bootloader --> Boot parameters --> Kernel --> root filesystems;

-- 最經常使用的 bootloader : uboot 是 bootloader 中最優秀的;


uboot 簡介

-- 支持 CPU : MIPS, x86, ARM 等;

-- 引導的系統 : Linux, Android, VxWorks, QNX;


uboot 模式 :

-- 自主模式 : 若是開機, 咱們什麼操做都不作就是自主模式;

-- 開發模式 : 開機後馬上按下 空格鍵, 會進入 uboot 的命令行模式, 即開發模式;



2. 使用 Source Insight 閱讀 uboot 源碼


Source Insight 使用流程

-- 建立工程 : "菜單欄" --> "Project" --> New Project 彈出下面的對話框, 在對話框中輸入代碼的保存路徑 和 工程名;


-- 每一個工程有本身的文件 : 點擊 OK 後, 在下面的對話框選擇第一個選項, 其它默認;


-- 彈出選擇源碼界面 : 這裏如今這裏暫停下, 也能夠關掉, 從 "菜單" --> "Project" --> "Add and Remove Project Files";


-- 解壓 uboot 源碼 : 使用 Samba 文件共享, 將 uboot 源碼在 linux 目錄下解壓, 因爲編碼和文件系統特性, 在 windows 目錄下解壓會出錯, 經過 直接在 Samba 用戶目錄下解壓;

[root@localhost arm]# cd /home/samba/
[root@localhost samba]# ls
ARM-tools  uboot.tar.gz
[root@localhost samba]# 
[root@localhost samba]# 
[root@localhost samba]# tar -xvzf uboot.tar.gz 
uboot/
uboot/README

... ...
-- 映射網絡驅動器 : 複製 Samba 中存放 uboot 源碼的共享文件路徑爲 "\\192.168.0.111\samba\uboot",  打開 "個人電腦", 選擇 "計算機" 菜單;


-- 添加映射地址 : 在映射網絡驅動器對話框中, 填入 Samba 目錄;


-- 生成了一個 Z 盤


-- 導入代碼 : 選擇 "菜單" --> "Project" --> "Add and Remove Project Files", 在彈出的對話框中選中 uboot 目錄, 並進入其跟目錄, 選擇 右側 "Add all" 按鈕, 在彈出的對話框中選擇兩個選項都選擇, 以便其子目錄中的文件也能被加載進入;


-- 查看加載完成的工程 : 發現沒有 .S 彙編文件;


-- 加載彙編文件 : 選擇  "菜單" --> "Options" --> "Document Options", 在 C Source File 中選擇 *.s;*.S, 結果爲 "*.c;*.h;*.s;*.S";


-- 繼續添加工程文件 : 選擇 "菜單" --> "Project" --> "Add and Remove Project file";


-- 此時彙編文件出現了






二. ARM 處理器啓動流程 (啓動方式 | 內存映射 | 啓動流程)



1. S3C2440 芯片啓動流程



(1) S3C2440 啓動方式


2440 啓動方式

-- Nor Flash : Nor Flash 大小隻有 2M;

-- Nand Flash : Nand Flash 大小 256M;



(2) S3C2440 內存映射


內存映射 : S3C2440 文檔, Page 221, 第六章 Nand Flash Memory Mapping, 也能夠搜索 Mapping 關鍵詞;

-- 左圖 : Nor Flash 啓動地址映射;

-- 右圖 : Nand Flash 啓動地址映射;




(3) S3C2440 啓動流程


Nor Flash 指令加載 :  CPU 上電 讀取指令 : 從 0x0 地址讀取指令;


Nand Flash 指令加載 : 

-- 啓動 0 地址 : Nand Flash 不能被直接訪問到, 沒有參與 ARM 的編址, BootSRAM 是片內的 RAM;

-- BootRAM 簡介 : BootSRAM 又名 Setpping stone (墊腳石), Bootloader 最前端 4K 自動複製到 BootRAM, 剩下的 複製到 內存中, 4K 的代碼運行完以後會跳轉到內存繼續執行剩下的代碼;

-- 內存地址 : 在下面的 Nand Flash Memory Mapping 圖中, s3c2440 芯片內存起始地址是 0x3000_0000;

-- 文檔參考 : Page 213, 章節6 Nand Flash Contorller;

OVERVIEW
In recent times, NOR flash memory gets high in price while an SDRAM and a NAND flash memory is comparatively
economical , motivating some users to execute the boot code on a NAND flash and execute the main code on an
SDRAM.
S3C2440A boot code can be executed on an external NAND flash memory. In order to support NAND flash boot
loader, the S3C2440A is equipped with an internal SRAM buffer called ‘Steppingstone’. When booting, the first 4
KBytes of the NAND flash memory will be loaded into Steppingstone and the boot code loaded into Steppingstone
will be executed.
Generally, the boot code will copy NAND flash content to SDRAM. Using hardware ECC, the NAND flash data
validity will be checked. Upon the completion of the copy, the main program will be executed on the SDRAM.




2. S3C6410 芯片啓動流程



(1) S3C6410 啓動方式


s3c6410 啓動方式介紹

-- SROM 啓動 : 即 Nor Flash 啓動, 6410 也支持 Nor Flash 啓動;

-- OneNand 啓動 : 特殊的 Nand Flash, 同時具備 Nor Flash 和 Nand Flash 的特性;

-- MODEM 啓動 :  詳情參考文檔;

-- IROM 啓動 : IROM 是處理器內部的組件, 該啓動方式包括 SD 卡啓動 和 Nand Flash 啓動;

-- 啓動方式文檔 : S3C6410X 文檔, 搜索關鍵詞 booting, Page 123, 3.3.3 章節;


(2) S3C6410 地址映射


啓動設備地址佈局 :

-- IROM (Internal ROM) : 0x0800_000 地址, 64M; 

-- Stepping Stone (Boot Loader) : 0x0C00_0000 地址, 64M;  

-- 地址佈局文檔 :  S3C6410X 文檔, Page 116, 2.2 章節, Device Specific Address Space 圖表 設備特殊地址空間; 


0 地址映射介紹

-- 鏡像區域 : Booting Device Region by XOM Setting (XOM設置的引導設備區域), 根據不一樣的啓動設置, 將對應的啓動設備映射到該區域;

-- IROM 啓動 : 會將 IROM 映射到該鏡像區域;

-- Nor Flash 啓動 : 將 Nor Flash 映射到該鏡像區域;

-- 文檔參考 : 從上面的文檔截圖 : 





(3) S3C6410 啓動流程


啓動流程S3C6410_Internal_ROM_Booting 文檔, Page 6, 2.1 章節;

-- 1. IROM 初始化 : IROM 中固化了軟件, 稱爲 bootloader0, 是 0階段的 bootloader, 該 BL0 執行 初始化時鐘, D-TCM, 設備特殊控制器, 引導設備; 

-- 2. 加載 BL1 : 加載 BL1 到 Stepping Stone (墊腳石), 將放在 nand flash 中的 bootloader1 (即 Bootloader 最前面的 8K) 拷貝到 Stepping Stone 中; 

-- 3. 執行 BL1 : BL1 初始化系統時鐘, UART, SDRAM, Stepping Stone 執行完 8K Bootloader 後, 將剩餘的 bootloader (BL2) 拷貝到 SDRAM 中運行;

-- 4. 執行 BL2 : 跳轉到 SDRAM 中執行 BL2, 加載內核;

-- 對比 2440 : 上電後 6410 先運行 IROM 中的代碼, 不是先運行 Bootloader;

-- 文檔參考




3. S5PV210 芯片啓動流程



(1) S5PV210啓動方式


S5PV210 啓動方式簡介

-- IROM 啓動方式 : 包括 Nand Flash 啓動, SD 卡啓動;

-- First boot URAT --> USB 啓動方式 : USB , 串口等啓動方式;

-- 文檔位置 : S5PV210_UM_REV1.1 文檔, Page 523, 6.2.4 章節;







(2) S5PV210地址映射


S5PV210 地址映射

-- IROM : 首地址 0xD000_0000, 大小 64KB;

-- IRAM : 這是 Stepping Stone (墊腳石), 首地址 0xD002_0000, 大小 96KB;

-- 零地址 : Boot area, 是一個映射區域, 與啓動模式(boot model)相關. 該地址不固定於某一個設備, 若是使用 IRAM 啓動, 就會將 IRAM 地址映射到 零地址處;

-- 內存 : 內存 首地址 0x2000_0000, DRAM0 位置;

-- 文檔位置 : Page 30, 2.1.1 章節, Device Specific Address Space 表;





(3) S5PV210啓動過程



名詞解釋

-- IROM : 引導區域, 該區域的鏡像取決與啓動模式, 根據啓動模式裝載不用的設備映像到該 IROM 區域;

-- I-SRAM | SRAM : 這裏的 SRAM 是 Stepping Stone (墊腳石), 用於存放拷貝的 bootloader 第一 和 第二階段的代碼;

-- BL1 : bootloader 第一階段; 

-- BL2 : bootloader 第二階段;

-- SDRAM Controller : 內存控制器;

-- SDRAM | DRAM : 內存;


S5PV210 啓動過程

-- 1. IROM 初始化 : 初始化系統時鐘, 初始化設備特別控制器, 引導設備;

-- 2. 裝載 BL1 : 將 BL1 (16KB) 拷貝到 IRAM (Strpping Stone 96KB 明顯比arm11 要大) 中, IROM 會在安全引導模式下驗證 BL1 完整性;

-- 3. 執行 BL1 : 將 BL2 (80KB) 拷貝到 I-SRAM (Internal 內部 SRAM ) 中, BL1 會在安全引導模式下驗證 BL2 完整性;

-- 4. 執行 BL2 : 初始化內存控制器, 若是 Stepping Stone 還不夠, 那麼就將剩餘的拷貝到 SDRAM(內存) 中, 而後裝載操做系統到內存中;

-- 5. 執行操做系統 : 跳轉到內存中, 執行 剩餘的 BL 或者 執行操做系統代碼;

-- 參考文檔 : S5PV210_iROM_ApplicationNote_Preliminary_20091126 文檔, Page 7, 2.1 章節, Operating Sequence 圖;





做者 : 韓曙亮

博客地址 http://blog.csdn.net/shulianghan/article/details/42462795

轉載請著名出處


相關資源下載 

-- u-boot 源碼 http://download.csdn.net/detail/han1202012/8342761

-- S3C2440 文檔 : http://download.csdn.net/detail/han1202012/8342701

-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文檔 : http://download.csdn.net/detail/han1202012/8342709

-- S3C6410_Internal_ROM_Bootin 文檔 : http://download.csdn.net/detail/han1202012/8342725

-- S3C6410X 文檔 : http://download.csdn.net/detail/han1202012/8342731

-- S5PV210_UM_REV1.1 文檔 : http://download.csdn.net/detail/han1202012/8342745




三. U-Boot 工做流程詳解



1. S3C2440 芯片的 U-Boot 工做流程



(1) S3C2440 BL 程序入口


S3C2440 uboot 入口分析

-- Makefile 分析 : 查看uboot 源碼根目錄下的 Makefile 文件, 能夠找到下面的內容 : 

smdk2440_config	:	unconfig
	@$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440
-- 2440 開發板相關配置 : 第二行的第三項 "smdk2440" 是開發板相關的配置目錄;

-- 2440 開發板相關文件 : 與該芯片對應的各類硬件相關文件在 \board\samsung\smdk2440 目錄, 下面是目錄內容;

[root@localhost uboot]# cd board/samsung/smdk2440/
[root@localhost smdk2440]# ls
config.mk  libsmdk2440.a    Makefile    smdk2440_val.h
flash.c    lowlevel_init.o  smdk2440.c  u-boot.lds
flash.o    lowlevel_init.S  smdk2440.o

-- u-boot.lds 連接器腳本內容 : 分析 "cpu/s3c24xx/start.o (.text)" 內容, 能夠知道 cpu/s3c24xx/start.o 是程序入口;

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x00000000;
	. = ALIGN(4);
	.text      :
	{
	  cpu/s3c24xx/start.o	(.text)
	  cpu/s3c24xx/s3c2440/cpu_init.o	(.text)
	  *(.text)
	}
	. = ALIGN(4);
	.rodata : { *(.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);
	.mmudata : { *(.mmudata) }

	. = ALIGN(4);
	__bss_start = .;
	.bss : { *(.bss) }
	_end = .;
}
-- 找到 start.o 對應文件 : start.S 是對應的文件, 在上面的 u-boot.lds 連接器腳本中有 "ENTRY(_start)" 說明 _start 是程序入口, 下面是 start.S 中_start 程序入口代碼;

/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */


.globl _start
_start:
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

_undefined_instruction:
	.word undefined_instruction
_software_interrupt:
	.word software_interrupt
_prefetch_abort:
	.word prefetch_abort
_data_abort:
	.word data_abort
_not_used:
	.word not_used
_irq:
	.word irq
_fiq:
	.word fiq

	.balignl 16,0xdeadbeef



(2) S3C2440 BL1 工做流程


分析 Linux 內核 驅動 Bootloader 原則

-- 先看功能 : 看註釋, 看代碼功能作了什麼, 暫時不關心如何實現的, 實現細節最後看;


BL1 階段代碼分析

-- 設置中斷向量表 : Line 63;

/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */


.globl _start
_start:
	b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
-- 設置處理器工做模式 : Line 147, 設置處理器 SVC 模式;

reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0,cpsr
	bic	r0,r0,#0x1f
	orr	r0,r0,#0xd3
	msr	cpsr,r0
-- 刷新 I/D Cache : Line 176;

	/*
	 * we do sys-critical inits only at reboot,
	 * not when booting from ram!
	 */
cpu_init_crit:
	/*
	 * flush v4 I/D caches
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
-- 關閉 MMU 和 cache : Line 187;

	/*
	 * disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002300	/* clear bits 13, 9:8 (--V- --RS) */
	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
-- lowlevel_init 方法 : Line 243定義, lowlevel_init 在 lowlevel_init.S 中定義, 這裏的方法定義在 /board/samsung/smdk2440/lowlevel_init.S 中, 如何查看 : 點擊方法, 而後點擊 書 圖標, 能夠看到該方法在不少類中定義, 在右側搜索欄找到 與本開發板相關的定義位置;

	/*
	 * Go setup Memory and board specific bits prior to relocation.
	 */
	bl	lowlevel_init	/* go setup pll,mux,memory */

-- 關閉看門狗 : lowlevel_init.S Line 79;

	/* Disable Watchdog */
	ldr	r0, =ELFIN_WATCHDOG_BASE
	mov	r1, #0
	str	r1, [r0]

-- 關閉全部中斷 lowlevel_init.S Line 85;

	/* mask all IRQs by setting all bits in the INTMR - default */
	ldr	r0, =ELFIN_INTERRUPT_BASE
	mov	r1, #0xffffffff
	str	r1, [r0, #INTMSK_OFFSET]
	ldr	r1, =0x000007ff
	str	r1, [r0, #INTSUBMSK_OFFSET]

-- 初始化系統時鐘 : 在 lowlevel_init.S 中定義的 lowlevel_init 方法, Line 45;

	/* init system clock */
	bl system_clock_init
-- 初始化串口

	/* for UART */
	bl uart_asm_init
-- Nand Flash 簡單初始化

	/* simple init for NAND */
	bl nand_asm_init
-- 內存初始化 : 判斷 uboot 是否運行在內存中的, 若是沒有運行在內存中, 說明是從 Nand Flash 啓動, 這時須要對內存進行初始化;

	/* when we already run in ram, we don't need to relocate U-Boot.
	 * and actually, memory controller must be configured before U-Boot
	 * is running in ram.
	 */
	ldr	r0, =0xf0000fff
	bic	r1, pc, r0	/* r0 <- current base addr of code */
	ldr	r2, _TEXT_BASE	/* r1 <- original base addr in ram */
	bic	r2, r2, r0	/* r0 <- current base addr of code */
	cmp     r1, r2		/* compare r0, r1                  */
	beq     1f		/* r0 == r1 then skip sdram init   */

	adrl    r0, mem_cfg_val
	bl	mem_con_init
-- 返回到上一級代碼處

1:	mov	lr, r12
	mov	pc, lr
-- 查詢時 Nand Flash 啓動仍是 Nor Flash 啓動 : 這裏咱們只說 Nand Flash 啓動的狀況;

	/* check boot device is nand or nor */
	ldr	r0, =0x00000000
	ldr	r3, [r0]
	ldr	r1, =0xfffffffe
	str	r1, [r0]

	ldr	r2, [r0]
	str	r3, [r0]
	cmp	r1, r2
-- 複製 Nand Flash 到內存中

nand_copy:
	mov	r0, #0x1000
	bl	copy_from_nand
-- 設置堆棧 : 爲 C 語言編程準備, Line 365;

	/* Set up the stack						    */
stack_setup:
-- 清除 bss 段 : Line 379;

clear_bss:
	ldr	r0, _bss_start		/* find start of bss segment        */
	ldr	r1, _bss_end		/* stop here                        */
	mov 	r2, #0x00000000		/* clear                            */

-- 跳轉到 arm_boot : PC 指針跳轉到 _start_armboot 函數運行; 

	ldr	pc, _start_armboot

_start_armboot:
	.word start_armboot
-- _start_armboot 函數位置 : 該函數式 /lib_arm/Border.c 中的一個函數

void start_armboot (void)
{
	init_fnc_t **init_fnc_ptr;
	char *s;


(3) S3C2440 BL2 工做流程


分析 BL2 執行流程

-- BL2 程序入口 : /lib_arm/board.c 中的 Line 268, start_armboot 函數, 在這個函數中執行了一個循環 : 

	for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
		if ((*init_fnc_ptr)() != 0) {
			hang ();
		}
	}

-- init_sequence 指針函數 數組定義

init_fnc_t *init_sequence[] = {
	cpu_init,		/* basic cpu dependent setup */
	board_init,		/* basic board dependent setup */
	interrupt_init,		/* set up exceptions */
	env_init,		/* initialize environment */

	init_baudrate,		/* initialze baudrate settings */
	serial_init,		/* serial communications setup */
	console_init_f,		/* stage 1 init of console */
	display_banner,		/* say that we are here */
#if defined(CONFIG_DISPLAY_CPUINFO)
	print_cpuinfo,		/* display cpu info (and speed) */
#endif
#if defined(CONFIG_DISPLAY_BOARDINFO)
	checkboard,		/* display board info */
#endif
	dram_init,		/* configure available RAM banks */
	display_dram_config,

	NULL,
};
-- 串口 初始化serial_init, 在Line 253 的  init_sequence 指針函數 數組中定義, 這裏咱們只討論硬件初始化問題, 軟件初始化問題暫不討論;

-- lcd 初始化 : Line 344 行定義;

size = lcd_setmem (addr);
-- 初始化網卡 : Line 484 , 中 " eth_initialize(gd->bd);" ;

-- 初始化 led : Line 487, "led_init();     /*led all off --forlinx add */";

-- 執行用戶輸入命令 : 初始化 led 以後進入主循環, main_loop 解析用戶控制檯輸入命令解析, 並執行用戶輸入的命令;

    led_init();     /*led all off --forlinx add */

	/* main_loop() can return to retry autoboot, if so just run it again. */
	for (;;) {
		main_loop ();
	}

	/* NOTREACHED - no way out of command loop except booting */




2. S3C2440 芯片 u-boot 分析


(1) S3C2440 uboot 配置編譯


uboot 配置和編譯

-- 找到 Makefile 中的 2440 目標項 : 目標是 smdk2440_config;

smdk2440_config	:	unconfig
	@$(MKCONFIG) $(@:_config=) arm s3c24xx smdk2440 samsung s3c2440

-- 配置編譯環境 : 執行 make smdk2440_config 命令; 

[root@localhost uboot]# make smdk2440_config
Configuring for smdk2440 board which boot from   ...
-- 進行編譯 : 執行 make 命令;


-- 反編譯 u-boot elf 文件 : 使用 arm-linux-objdump -S -D u-boot > uboot_dump 命令, 反編譯, 分析反編譯結果 : 

[root@localhost uboot]# arm-linux-objdump -S -D u-boot > uboot_dump 
[root@localhost uboot]# gedit uboot_dump 


30009100 <start_armboot>: 

NULL, 
}; 

void start_armboot (void) 
{ 
30009100:	e92d4070 push	{r4, r5, r6, lr} 

gd_base = CFG_UBOOT_BASE + CFG_UBOOT_SIZE - CFG_MALLOC_LEN - CFG_STACK_SIZE - sizeof(gd_t); 
#ifdef CONFIG_USE_IRQ 
gd_base -= (CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ); 
#endif 
gd = (gd_t*)gd_base; 
30009104:	e59f8190 ldr	r8, [pc, #400]	; 3000929c <start_armboot+0x19c> 

NULL, 
};


(2) S3C2440 uboot 連接地址分析


連接地址分析

-- 查看鏈接器腳本 : 查看 /board/samsung/smdk2440/u-boot.lds 連接器腳本, 代碼段的起始地址是 0x00000000;

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
	. = 0x00000000;
	. = ALIGN(4);
	.text      :
	{
	  cpu/s3c24xx/start.o	(.text)
	  cpu/s3c24xx/s3c2440/cpu_init.o	(.text)
	  *(.text)
	}

... ...
-- 查看 config.mk 腳本 : Line 189 行, "LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)" 內容, -Ttext $(TEXT_BASE) 會把連接器腳本中的地址覆蓋掉;

-- TEXT_BASE 變量定義 : 在 /board/samsung/smdk2440/config.mk 中 "TEXT_BASE = 0x30008000" 定義了該變量;

-- 查看反編譯中的地址 : 代碼的起始地址果真是 30008000;

octopus@octopus:~/arm/uboot/uboot$ more uboot_dump 

u-boot:     file format elf32-littlearm

Disassembly of section .text:

30008000 <_start>:
 */


.globl _start
_start:
	b	reset
30008000:	ea000013 	b	30008054 <reset>
	ldr	pc, _undefined_instruction
30008004:	e59ff014 	ldr	pc, [pc, #20]	; 30008020 <_undefined_instruction>
	ldr	pc, _software_interrupt
30008008:	e59ff014 	ldr	pc, [pc, #20]	; 30008024 <_software_interrupt>
	ldr	pc, _prefetch_abort
3000800c:	e59ff014 	ldr	pc, [pc, #20]	; 30008028 <_prefetch_abort>
	ldr	pc, _data_abort
30008010:	e59ff014 	ldr	pc, [pc, #20]	; 3000802c <_data_abort>
	ldr	pc, _not_used
30008014:	e59ff014 	ldr	pc, [pc, #20]	; 30008030 <_not_used>
	ldr	pc, _irq
30008018:	e59ff014 	ldr	pc, [pc, #20]	; 30008034 <_irq>



(3) S3C2440 uboot 中的相對地址跳轉 和 絕對地址跳轉


相對地址和絕對地址跳轉

-- 相對跳轉 : 不會對 PC 形成實質性的影響, B 指令, 首先計算一個相對值, 在 PC 原有基礎上;

-- 相對跳轉示例 : 如 以前的初始化的方法 "bl lowlevel_init", 該行代碼的地址是 0x30008000, lowlevel_init 在 0x30008010 地址處, 執行到了該行代碼, 30008010 是連接地址, 可是此時 PC 指針指向的值 還在 墊腳石中, 小於4K, 如此時 PC = 100, 若是進行連接地址跳轉 PC = 100 + (0x30008010 - 300080000) 地址, 以後 PC = 110, PC 仍是在墊腳石中, 相對地址跳轉不會對 PC 形成實質性的影響;

-- 絕對跳轉 : 直接修改 PC 指針的值, PC 直接跳到內存中, ldr pc #0x30008010, PC 就會編程 0x30008010;




(4) S3C2440 內存分佈角度分析啓動流程


內存分佈角度分析啓動流程

-- arm 內存前 4K : 內存中前 4K 是 Stepping Stone;

-- 拷貝 BL1 : 啓動時, 會將 Nand Flash 拷貝到 Stepping Stone 中, 主要是將 start.S 拷貝進去;

-- 執行 BL1 : 以後執行 start.S 的 _start 開始執行;

-- 拷貝 BL2 : 執行到 BL1 最後會將 BL2 代碼拷貝到內存中去;

-- 執行 BL2 : BL1 執行完後, PC 指針會跳轉到內存中接着運行 BL2 的代碼;




(5) S3C2440 地址跳轉角度分析啓動流程



地址跳轉角度分析啓動流程

-- arm 地址空間 : 前面 4K 是 Stepping Stone (墊腳石);

-- nand flash 地址空間 : 前 4K 會被複制到墊腳石中;

-- PC 指針 : 此時 PC 指針指向 0, 會取 arm 中的 墊腳石中的指令, 執行這些指令; 

-- 拷貝剩餘 BL : 執行到必定程度, 會將 nand flash 中的剩餘 BL 複製到 0x30008000 地址;

-- PC 跳轉到內存 : PC 跳轉到 0x30008000 執行, 以前 PC 指針值一直小於 4K, 可是跳轉後順便值變成 0x30008000 以後的地址了;




2. S3C6410 芯片的 U-Boot 工做流程



(1) S3C6410 BL 程序入口


S3C6410程序入口分析

-- 分析 Makefile 文件 : Line 1953 處定義了 forlinx_nand_ram256_config 目標, 對應開發板是 smdk6410;

forlinx_nand_ram256_config :  unconfig
	@$(MKCONFIG) smdk6410 arm s3c64xx smdk6410 samsung s3c6410 NAND ram256
--  smdk6410 開發板相關配置文件


-- 分析連接器腳本 u-boot.lds : 能夠看到程序入口是 cpu/s3c64xx/start.S 彙編文件;

... ...

SECTIONS
{
	. = 0x00000000;

	. = ALIGN(4);
	.text      :
	{
	  cpu/s3c64xx/start.o	(.text)
	  cpu/s3c64xx/s3c6410/cpu_init.o	(.text)
	  cpu/s3c64xx/onenand_cp.o	(.text)
	  cpu/s3c64xx/nand_cp.o	(.text)
	  cpu/s3c64xx/movi.o (.text)
	  *(.text)
	  lib_arm/div0.o
	}

... ...
-- 分析 start.S 代碼_start 是程序入口;

... ...

.globl _start
_start: b	reset
	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq

... ...



(2) S3C6410 BL1 流程分析


S3C6410 BL1 流程分析

-- 初始化向量表 : start.S Line 52;

	ldr	pc, _undefined_instruction
	ldr	pc, _software_interrupt
	ldr	pc, _prefetch_abort
	ldr	pc, _data_abort
	ldr	pc, _not_used
	ldr	pc, _irq
	ldr	pc, _fiq
-- 設置 CPU 爲 SVC 模式 : start.S Line 136;

/*
 * the actual reset code
 */

reset:
	/*
	 * set the cpu to SVC32 mode
	 */
	mrs	r0,cpsr
	bic	r0,r0,#0x1f
	orr	r0,r0,#0xd3
	msr	cpsr,r0
-- 刷新 I/D Cache : start.S Line 163;

	/*
	 * flush v4 I/D caches
	 */
	mov	r0, #0
	mcr	p15, 0, r0, c7, c7, 0	/* flush v3/v4 cache */
	mcr	p15, 0, r0, c8, c7, 0	/* flush v4 TLB */
-- 關閉 MMU 和 Cache : start.S Line 170;

	/*
	 * disable MMU stuff and caches
	 */
	mrc	p15, 0, r0, c1, c0, 0
	bic	r0, r0, #0x00002300	@ clear bits 13, 9:8 (--V- --RS)
	bic	r0, r0, #0x00000087	@ clear bits 7, 2:0 (B--- -CAM)
	orr	r0, r0, #0x00000002	@ set bit 2 (A) Align
	orr	r0, r0, #0x00001000	@ set bit 12 (I) I-Cache
	mcr	p15, 0, r0, c1, c0, 0
-- 外設基地址初始化 (6410 獨有) : start.S Line 178;

	/* Peri port setup */
	ldr	r0, =0x70000000
	orr	r0, r0, #0x13
    	mcr	p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
-- 調用 lowlevel_init 方法 : start.S Line 240;

	/*
	 * Go setup Memory and board specific bits prior to relocation.
	 */
	bl	lowlevel_init	/* go setup pll,mux,memory */

	/* when we already run in ram, we don't need to relocate U-Boot.
	 * and actually, memory controller must be configured before U-Boot
	 * is running in ram.
	 */
-- lowlevel_init 方法定義位置 : /board/samsung/smdk6410/lowlevel_init.S 中定義該方法, 入口是 lowlevel_init.S Line 41;

... ...

	.globl lowlevel_init
lowlevel_init:
	mov	r12, lr

	ldr	r0, =ELFIN_GPIO_BASE

... ...

-- LED 點亮 : lowlevel_init.S Line 62;

	/* LED on only #8 */
	ldr	r0, =ELFIN_GPIO_BASE  
	ldr	r1, =0x00111111
	str	r1, [r0, #GPMCON_OFFSET]

	ldr	r1, =0x00000555
	str	r1, [r0, #GPMPUD_OFFSET]

	ldr	r1, =0x002a
	str	r1, [r0, #GPMDAT_OFFSET]



	ldr	r1, =0  /*0x55555555 phantom*/
	str	r1, [r0, #MEM1DRVCON_OFFSET]
-- 關閉看門狗lowlevel_init.S Line 78;

	/* Disable Watchdog */
	ldr	r0, =0x7e000000		@0x7e004000
	orr	r0, r0, #0x4000
	mov	r1, #0
	str	r1, [r0]
-- 關閉全部中斷 : lowlevel_init.S Line 91;

	@ Disable all interrupts (VIC0 and VIC1)
	mvn	r3, #0x0
	str	r3, [r0, #oINTMSK]
	str	r3, [r1, #oINTMSK]
-- 初始化時鐘lowlevel_init.S  Line 109;

	/* init system clock */


	bl system_clock_init

-- 初始化串口lowlevel_init.S Line 113;

	/* for UART */
	bl uart_asm_init
-- 初始化內存 : lowlevel_init.S Line 127;

    /* simple init for NAND */
	bl nand_asm_init
-- 返回到 start.Slowlevel_init.S Line 156;

	mov	pc, lr
-- 複製 nand flash 內容到內存 : start.S Line 276;

#ifdef CONFIG_BOOT_NAND
	mov	r0, #0x1000
	bl	copy_from_nand
-- 堆棧初始化 : start.S Line 398;

	/* Set up the stack						    */
stack_setup:
#ifdef CONFIG_MEMORY_UPPER_CODE
	ldr	sp, =(CFG_UBOOT_BASE + CFG_UBOOT_SIZE - 0xc)
#else
	ldr	r0, _TEXT_BASE		/* upper 128 KiB: relocated uboot   */
	sub	r0, r0, #CFG_MALLOC_LEN	/* malloc area                      */
	sub	r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
	sub	r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
	sub	sp, r0, #12		/* leave 3 words for abort-stack    */

#endif
-- 清除 BSS 段 : start.S Line 412;

clear_bss:
	ldr	r0, _bss_start		/* find start of bss segment        */
	ldr	r1, _bss_end		/* stop here                        */
	mov 	r2, #0x00000000		/* clear                            */
-- 執行 BL2 : start.S Line 245;

	ldr	pc, _start_armboot

_start_armboot:
	.word start_armboot
-- 6410 與 2440 的 BL2 階段是相同, 由於 start_armboot 不論是什麼開發板, BL2 指向的 該函數都是在一個文件中;




3. S5PV210 芯片的 U-Boot 工做流程



(1) S5PV210 BL1 執行流程


S5VP 210 BL1 流程
-- 1. 設置中斷向量表;
-- 2. 設置 CPU svc 工做模式;
-- 3. 關閉 L1 (一級的) I/D Cache 失效;
-- 4. 關閉 MMU 和 Cache;
-- 5. 檢查 reset 狀態;
-- 6. IO 引腳初始化;
-- 7. 關閉看門狗;
-- 8. SRAM 和 SROM 初始化;
-- 9. 時鐘初始化;
-- 10. 內存初始化;
-- 11. UART 簡單初始化;
-- 12. 取消存儲保護區;
-- 13. nand flash 簡單初始化;
-- 14. 關閉 ABB;
-- 15. 設置堆棧;
-- 16. 將 BL2 到 RAM 中;
-- 17. 跳轉到 RAM 中 運行 BL2;



(2) S5PV210 BL2 複製分析


BL2 複製相關問題
-- BL2 複製到內存中什麼位置 : 到代碼中尋找, 這個地址在頭文件中定義, 0x23100000 位置;
-- BL1 如何找到 BL2 : nand flash 寫入後 BL1 與 BL2 間距 是 8KB, BL1 是 16KB + 8KB, BL2 在 24KB 地址開始的位置;
-- BL2 大小要求 : 複製 512KB 到內存中去;



(3) S5PV210 BL 啓動分析


S5PV210 啓動流程 : BL1 和 BL2 在 210 上被劃分紅了兩部分;

-- iROM 映射 : iROM 經過映射 被映射到 arm 0 地址處, 裏面是一個固件程序, 是三星燒寫好的;

-- iRAM 墊腳石 : 96KB, Stepping Stone 墊腳石, 在 irom 上面;

-- 拷貝 BL1 : iROM 固化程序將 BL1 (16KB) 複製到 iRAM 中;

-- 拷貝 BL2 : BL1 在 iRAM 中執行, 若是 BL2 小於 80K, 複製 BL2 到 iRAM 中; 若是 BL2 大於 80K, 複製 BL2 到 內存中; uboot 編譯後大於80K, 所以 BL2 複製到 內存中;                                                                                                                                                                                       






四. Bootloader 架構設計



H-Boot BL1 程序設計 : 彙編代碼編寫;

-- 1. 核心初始化 : a. 設置中斷向量表, b. 設置 CPU svc 模式, c. 關閉看門狗, d. 關閉中斷, e. 關閉 MMU 和 Cache, f. 外設基地址初始化 (f 爲6410獨有);

-- 2. C 語言編程環境設置 : a. 設置堆棧, b. 清除 BSS 段;

-- 3. LED 初始化 ;

-- 4. 初始化系統時鐘;

-- 5. 內存初始化 : a. 取消存儲保護區 (a 位 210 獨有), b. iRAM 和 iROM 初始化 (b 爲 210 獨有);

-- 6. 複製 nand flash 到內存 : a. 簡單初始化 nand flash, b. 複製代碼到內存, c. 跳轉到 BL2 入口;



H-Boot BL2 程序設計 : 彙編代碼編寫;

-- 1. MMU 初始化

-- 2. 中斷初始化 : a. 中斷初始化, b. 按鍵初始化;

-- 3. 初始化串口 : a. 串口初始化, b. 移植 printf 函數;

-- 4. 網卡初始化;

-- 5. LCD 初始化 : a. 觸摸板初始化, b. LCD 初始化;

-- 6. 解析執行用戶命令 : a. 移植 TFTP 命令, b. 移植 BOOTM 命令;




做者 : 韓曙亮

博客地址 http://blog.csdn.net/shulianghan/article/details/42462795

轉載請著名出處


相關資源下載 

-- u-boot 源碼 http://download.csdn.net/detail/han1202012/8342761

-- S3C2440 文檔 : http://download.csdn.net/detail/han1202012/8342701

-- S5PV210_iROM_ApplicationNote_Preliminary_20091126 文檔 : http://download.csdn.net/detail/han1202012/8342709

-- S3C6410_Internal_ROM_Bootin 文檔 : http://download.csdn.net/detail/han1202012/8342725

-- S3C6410X 文檔 : http://download.csdn.net/detail/han1202012/8342731

-- S5PV210_UM_REV1.1 文檔 : http://download.csdn.net/detail/han1202012/8342745

相關文章
相關標籤/搜索