1.1 BootLoader介紹
什麼是BootLoader?
軟件層次
一個嵌入式系統從軟件角度來看分爲三個層次:
1. 引導加載程序
包括固化在固件(firmware)中的 boot 程序(可選),和 BootLoader 兩大部分。
2. Linux 內核
特定於嵌入式平臺的定製內核。
3. 文件系統
包括了系統命令和應用程序。
一個同時裝有 BootLoader、內核的啓動參數、內核映像和根文件系統映像的固態存儲設備的典型空間分配結構圖:
PC機中的引導加載程序由BIOS(其本質是一段固件程序)和
GRUB或LILO一起組成。BIOS在完成硬件檢測和資源分配後,將硬盤中的引導程序讀到系統內存中然後將控制權交給引導程序。引導程序的主要任務是將內核從硬盤上讀到內存中,然後跳轉到內核的入口點去運行,即啓動操作系統。
定義
在嵌入式系統中,通常沒有像BIOS那樣的固件程序,因此整個系統的加載啓動任務就完全由BootLoader來完成。比如在一個基
於 ARM7TDMI core的嵌入式系統中,系統在上電或復位時都從地址 0x00000000開始執行。而在這個地址處安排的通常就是系統的BootLoader程序。
簡單地說,BootLoader就是在操作系統運行之前運行的一段小程序。通過這段小程序,可以初始化硬件設備,從而將系統的軟硬件環境帶到一個合適的狀態,以便爲最終調用操作系統做好準備。
安裝
系統加電或復位後,所有的CPU通常都從CPU製造商預先安排地址開始執行。比如,S3C2410在復位後從地址0x00000000起開始執行。而嵌入式系統則將固態存儲設備(比如:FLASH)安排在這個地址上,而bootloader程序又安排在固態存儲器的最前端,這樣就能保證在系統加電後,CPU首先執行BootLoader程序。
爲什麼需要進行bootloader移植?
每種不同的CPU體系結構都有不同的BootLoader。除了依賴於CPU的體系結構外,BootLoader 還依賴於具體的嵌入式板級設備的配置,比如板卡的硬件地址分配,外設芯片的類型等。這也就是說,對於兩塊不同的開發板而言,即使它們是基於同一種CPU而構建的,但如果他們的硬件資源或配置不一致的話,要想在一塊開發板上運行的BootLoader程序也能在另一塊板子上運行,還是需要作修改。
流程
BootLoader 的啓動過程可分爲單階段(Single-Stage)和多階段(Multi-Stage)兩種,通常多階段的 BootLoader 具有更復雜的功能,更好的可移植性。從固態存儲設備上啓動的BootLoader 大多采用兩階段,即啓動過程可以分爲 stage 1和 stage2;stage1完成初始化硬件,爲stage2準備內存空間,並將stage2複製到內存中,設置堆棧,然後跳轉到stage2。
BootLoader 的 stage1 通常包括以下步驟:
·硬件設備初始化
·爲加載 BootLoader 的 stage2 準備 RAM 空間
·拷貝 BootLoader 的 stage2 到 RAM 空間中
·設置好堆棧(why??)
·跳轉到 stage2 的 C 入口點
BootLoader 的 stage2 通常包括以下步驟:
·初始化本階段要使用到的硬件設備
·將內核映像和根文件系統映像從 flash 上讀到RAM 中
·調用內核
內存分佈
1.2 Uboot介紹
作用
Uboot是德國DENX小組開發的用於多種嵌入式CPU( MIPS、x86、ARM、XScale等)的bootloader程序,UBoot不僅支持嵌入式Linux系統的引導,還支持VxWorks, QNX等多種嵌入式操作系統。
下載
從下面地址可以下載到uboot的源代碼:
ftp://ftp.denx.de/pub/u-boot/
目錄結構
進入到UBOOT目錄,可以得到如下的目錄結構:
| board
| common
| cpu
| disk
| doc
| drivers
| dtt
| examples
| fs
| include
| lib_arm
| lib_generic
| lib_i386
| lib_m68k
| lib_microblaze
| lib_mips
| lib_nios
| lib_nios2
| lib_ppc
| net
| post
| rtc
| tools
Board
和開發板有關的文件。每一個開發板都以一個子目錄出現在當
前目錄中,比如:SMDK2410,子目錄中存放與開發板相關的文
件。
Common
實現Uboot支持的命令。
Cpu
與特定CPU架構相關的代碼,每一款Uboot下支持的CPU在該
目錄下對應一個子目錄,比如有子目錄arm920t等。
Disk
對磁盤的支持。
Doc
文檔目錄。Uboot有非常完善的文檔,推薦大家參考閱讀。
Drivers
Uboot支持的設備驅動程序都放在該目錄,比如各種網卡、
支持CFI的Flash、串口和USB等。
Fs
文件系統的支持。
Include
Uboot使用的頭文件。該目錄下configs目錄有與開發板相關的配置頭文件,如smdk2410.h。該目錄下的asm目錄有與CPU體系結構相關的頭文件。
Net
與網絡協議棧相關的代碼,例如:TFTP協議、RARP協議的實現。
Tools
生成Uboot的工具,如:mkimage, crc等等。
編譯
Uboot的Makefile從功能上可以分成兩個
部分:
1、執行每種board相關的配置
2、編譯生成uboot.bin文件
Uboot.bin的生成也分爲兩步,以smdk2410爲例來說明,如下:
1. 選擇要使用的board:
$makesmdk2410_config
2. 編譯生成u-boot.bin:
$makeCROSS_COMPILE=arm-linux-
1.3 Uboot命令
常用命令
儘管UBOOT提供了豐富的命令集,但不同的單板所支持的命令並不一定一樣(可配置,How?後面章節),help 命令可用於察看當前單板所支持的命令。
【2410】 # help
autoscr -run scriptfrom memory
base -print or setaddress offset
bdinfo -print BoardInfo structure
bootm -bootapplication image from memory
環境變量相關
printenv 查看環境變量
usage:
printenv
- print values ofall environment variables
printenv name ...
- print value ofenvironment variable 'name'
Uboot> printenv
ipaddr=192.168.1.1
ethaddr=12:34:56:78:9A:BC
serverip=192.168.1.5
setenv 添加、修改、刪除環境變量
setenv name value...
- set environmentvariable 'name' to 'value ...‘
setenv name
- delete environmentvariable 'name'
Uboot> setenvmyboard AT91RM9200DK
Uboot> printenv
serverip=192.168.1.5
myboard=AT91RM9200DK
saveenv 保存環境變量
將當前定義的所有變量及其值存入flash中。
文件下載
tftp 通過網絡下載文件
注意:使用tftp,需要先配置好網絡
Uboot> setenv ethaddr12:34:56:78:9A:BC
Uboot> setenvipaddr 192.168.1.1
Uboot> setenvserverip 192.168.1.254 (tftp服務器的地址)
例:
Uboot> tftp32000000 uImage
把server(IP=環境變量中設置的serverip)中服務目錄 下的
uImage通過TFTP讀入到0x32000000處。
內存操作
md(memory display) 顯示內存區的內容。
md採用十六進制和ASCII碼兩種形式來顯示存儲單元的內容。
這條命令還可以採用長度標識符 .l, .w和.b :
md [.b, .w, .l]address
md.w 100000
00100000: 2705 19565050 4342 6f6f 7420 312e 312e
00100010: 3520 284d6172 2032 3120 3230 3032 202d
mm(memory modify) 修改內存,地址自動遞增。
mm [.b, .w, .l]address
mm 提供了一種互動修改存儲器內容的方法。它會顯示地址和當前值,然後提示用戶輸入。如果你輸入了一個合法的十六進制數,
這個新的值將會被寫入該地址。然後提示下一個地址。如果你沒
有輸入任何值,只是按了一下回車,那麼該地址的內容保持不
變。如果想結束輸入,則輸入空格,然後回車。
=> mm 100000
00100000: 27051956 ?0
00100004: 50504342 ?AABBCCDD
Flash操作
flinfo 查看Flash扇區信息
Usage:Uboot>flinfo
protect Flash寫保護
打開或關閉扇區寫保護
用法:
protect off all
關閉所有扇區的寫保護
protect on all
打開所有扇區的寫保護
protect off startend
關閉從start 到 end 扇區的寫保護(start爲要關閉的第1個扇區的起始
地址,end爲要關閉的最後一個扇區的結束地址)
protect on start end
打開從start 到 end 扇區的寫保護
erase 擦除flash扇區
用法: erase start end
擦除從start 到 end 的扇區,start 爲要擦除的第1個扇區的起始地址,end 爲要擦除的最後一個扇區的結束地址(在使用cp命令向Nor型Flash寫入數據之前必須先使用erase 命令擦除flash,因爲
nor flash 按字節寫入時,無法寫入1,所以必須通過擦除來寫入1)。
例:erase 30000 1effff
cp 數據拷貝。
cp [.b, .w, .l]saddress daddress len
cp 提供了一種內存與內存,內存與Flash之間數據拷貝的方法。
例:
cp.b 31000000 50000d0000
將內存地址0x31000000處的數據(長度爲0xd0000)拷貝到
地址0x50000處(Flash中)
cp.b 32000000 120000c0000
將內存地址0x32000000處的數據(長度爲0xc0000)拷貝到
地址0x120000處(Flash中)
執行程序
go 執行內存中的二進制代碼,一個簡單的跳轉到指定地址
go addr [arg ...]
- start applicationat address 'addr‘,
passing 'arg' asarguments
bootm 執行內存中的二進制代碼
bootm [addr [arg...]]
- boot applicationimage stored in memory
passing arguments'arg ...'; when booting a Linux kernel, 'arg' can be the address of an initrdimage
要求二進制代碼有固定格式的文件頭。
開發板信息
bdinfo – 顯示開發板信息
bdinfo命令(簡寫爲bdi)將在終端顯示諸如內存地址和大小、時鐘頻率、MAC地址等信息。這些信息在傳遞給Linux內核一些
參數時可能會用到。
自動啓動
1. 設置自動啓動
bootdelay時間內未打斷自啓動則開始執行bootcmd裏的命令
mini2440=>setenvbootcmd tftp
31000000 uImage \;bootm 31000000
mini2440=>saveenv
1.4 Uboot工作流程
工作模式
大多數BootLoader都包含兩種不同的操作模式:“啓動模式” 和“下載模式”,這種區別僅對於開發人員纔有意義,但從最終用戶
的角度看,BootLoader的作用就是用來加載操作系統,而不存在所謂的啓動模式與下載模式。
啓動模式
這種模式也稱爲“自主” 模式,是指BootLoader 從目標機上的某個固態存儲設備上將操作系統自動加載到 RAM 中運行,整個過程並沒有用戶的介入。這種模式是BootLoader 的正常工作模式,因此在嵌入式產品發佈的時侯,BootLoader 顯然必須工作在這種模式下。
下載模式
在這種模式下,目標機上的BootLoader 將通過串口或網絡等通
信手段從主機(Host)下載文件 ,然後控制啓動流程。
代碼導讀
參考文檔《uboot啓動流程》
1.5 Uboot移植
爲什麼需要對Uboot進行移植?
BootLoader 依賴於:
具體的CPU體系、具體的板級設備配置
(芯片級移植、板級移植)
具體的板級設備的配置在哪裏?
板級設備的配置文件位於
include/configs/<board_name>.h
<board_name>用相應的BOARD定義代替(例:smdk2410.h)
Smdk2410.h
#defineCONFIG_ARM920T 1
/* CPU 類型 */
#define CONFIG_S3C24101
/* MCU類型 */
#defineCONFIG_SMDK2410 1
/* 開發板型號 */
#define USE_920T_MMU1
/* 使用MMU */
#undefCONFIG_USE_IRQ
/* 不使用 IRQ/FIQ */
/* malloc 池大小*/
#defineCFG_MALLOC_LEN (CFG_ENV_SIZE +
128*1024)
/* 數據段大小 128字節 */
#defineCFG_GBL_DATA_SIZE 128
/* 使用 CS8900 網卡 */
#defineCONFIG_DRIVER_CS8900 1
/* CS8900A 基地址 */
#define CS8900_BASE0x19000300
/* 使用串口1 */
#defineCONFIG_SERIAL1 1
/* 波特率 */
#defineCONFIG_BAUDRATE 115200
#defineCONFIG_COMMANDS \
(CONFIG_CMD_DFL |\
CFG_CMD_CACHE |\
/*CFG_CMD_NAND |*/ \
/*CFG_CMD_EEPROM |*/\
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE
|\
CFG_CMD_ELF)
/*定義使用的命令,可添加額外命令,如PING*/
/* 自動啓動等待時間 */
#defineCONFIG_BOOTDELAY 3
/* 內核啓動參數 */
#defineCONFIG_BOOTARGS
"root=ramfsdevfs=mount console=ttySA0,9600“
#defineCONFIG_ETHADDR 08:00:3e:26:0a:5b
#defineCONFIG_NETMASK 255.255.255.0
#defineCONFIG_IPADDR 10.0.0.110
#defineCONFIG_SERVERIP 10.0.0.1
#defineCONFIG_BOOTCOMMAND "tftp; bootm"
#define CFG_PROMPT"SMDK2410 # "
#define PHYS_SDRAM_10x30000000 /* SDRAM Bank #1 */
#definePHYS_SDRAM_1_SIZE 0x04000000 /* 64 MB */
#defineCFG_LOAD_ADDR 0x33000000
/* 默認的啓動地址 */
#defineCFG_BAUDRATE_TABLE { 9600, 19200, 38400, 57600,115200 } /*可用的波特率*/
/* 有一片SDRAM */
#defineCONFIG_NR_DRAM_BANKS 1
/* FLASH No1的基地址 */
#define PHYS_FLASH_10x00000000
/* FLASH 的基地址 */
#defineCFG_FLASH_BASE
PHYS_FLASH_1
移植
開始移植之前,首先要分析U-Boot已經支持的開發板,選擇出硬件配置最接近的開發板。選擇的原則是,首先選擇MCU相同的開發板,如果沒有,則選擇MPU相同的開發板。
以mini2440開發板爲例,該開發板採用s3c2440芯片。根據選擇原則,首先選擇MCU爲s3c2440的開發板,但 UBoot 各版本均不支持採用s3c2440芯片的開發板。因此根據第二原則,選擇MPU相同,即ARM核爲arm920T的開發板,Uboot支持SMDK2410開發板,並且SMDK2410採用s3c2410芯片,s3c2410採用的正好是arm920T,因此選取SMDK2410開發板作爲移植參考板。
移植U-Boot的基本步驟如下:
1.在頂層Makefile中爲開發板添加新的配置選項,使用已有的
配置項目爲例
smdk2410_config :
unconfig @./mkconfig$(@:_config=) arm arm920t smdk2410 NULL s3c24x0
參考上面2行,添加下面2行:
mini2440_config :
unconfig
@./mkconfig$(@:_config=) arm arm920t mini2440 NULL s3c24x0
arm: CPU 架構
arm920t: CPU 類型,對應cpu/arm920t目錄
mini2440: 開發板型號,對應board/mini2440目錄
NULL:開發者
s3c24x0: 片上系統(SOC)
2. 在board目錄中創建一個屬於新開發板的目錄,並添加文件:
mkdir –pboard/mini2440
cp –rfboard/smdk2410/* board/mini2440
3. 爲開發板添加新的配置文件
先複製參考開發板的配置文件,再修改。例如:
$cpinclude/configs/smdk2410.h include/configs/mini2440.h
4. 選擇板級配置
$ makemini2440_config
5. 編譯U-Boot
執行make CROSS_COMPILE=arm-linux- 命令,編譯成功可以得到U-Boot映像。
6.燒寫Uboot