1. 程式人生 > >國嵌視訊學習第九天——UBOOT基礎

國嵌視訊學習第九天——UBOOT基礎

BootLoader

軟體層次

一個嵌入式系統從軟體角度來看分為三個層次:

1.      引導載入程式

包括固化在韌體(fireware)中的boot程式(可選)(比如CMOS中的BIOS),和BootLoader(比如grub)兩大部分

2.Linux核心

特定嵌入式平臺的定製核心

3.檔案系統

包括了系統命令和應用程式

PC機的引導載入程式由BIOS(其本質是一段韌體程式)和GRUB和 LILO一起組成。BIOS在完成硬體檢測和資源分配後,將硬碟中的載入程式讀到系統記憶體中然後將控制權交給載入程式。載入程式的主要任務是將核心從硬碟上讀到記憶體中,然後跳轉到核心的入口點去執行,即啟動作業系統

定義

在嵌入式系統中,通常沒有想BIOS那樣的韌體程式,因此整個系統的載入啟動任務就完全由BootLoader來完成。比如在一個基於ARM7TDMI core的嵌入式系統中,系統在上電或復位時都從地址0x00000000開始執行。而在這個地址處安排的通常就是系統的BootLoader程式

簡單地說,BootLoader就是在作業系統執行之前執行的一段小程式。通過這段小程式,可以初始化硬體裝置,從而將系統的軟硬體環境帶到一個合適的狀態,以便為最終呼叫作業系統做好準備。

安裝

系統加電或復位後,所有的CPU通常都從CPU製造商預先安排地址開始執行。比如,S3C6410在復位後從地址0x00000000起開始執行。而嵌入式系統則將固態儲存裝置(比如:FLASH)安排在這個地址上,而bootloader程式又安排在固態儲存器的最前端,這樣就能保證在系統加電後,CPU首先執行BootLoader程式

流程

BootLoader的啟動過程可分為單階段(Single-Stage)和多階段(Muti-Stage)兩種,通常多階段的BootLoader具有更復雜的功能,更好的可移植性。從固態儲存裝置上啟動的BootLoader大多采用兩階段,即啟動過程可以分為stage1和stage2:stage1完成初始化硬體,為stage2準備記憶體空間,並將stage2複製到記憶體中,設定堆疊,然後跳轉到stage2.

BootLoader的stage1通常包括以下步驟:

----硬體裝置初始化

----為載入BootLoader的stage2準備RAM空間

----拷貝BootLoader的stage2到RAM空間中

----設定好堆疊(目的是為stage2中的C程式的執行搭建環境)

----跳轉到stage2的C入口點

該階段的程式主要是由彙編程式碼寫成

BootLoader的stage2通常包括以下步驟:

----初始化本階段要使用的硬體裝置(板載硬體,比如串列埠、網口)

----將核心映像和根檔案系統映像從flash上讀到RAM中

----呼叫核心

該階段的程式主要是由C程式碼寫成

工作模式

大多數BootLoader都包含兩種不同的工作模式:“啟動模式”和“下載模式”,這種區別僅對於開發人員才有意義,從終端使用者的角度來看,BootLoader的作用就是用來載入作業系統,而不存在所謂的啟動模式與下載模式。

啟動模式:處理器一旦上電後,不需要干預便能自動地啟動bootloader,並通過bootloader啟動核心

下載模式:CPU上電後,目標機上的BootLoader將通過串列埠或網路等通訊手段從主機(Host)下載檔案,然後控制啟動流程(常用於開發時)。

所以,使用者常見的是啟動模式

交叉工具鏈

工具鏈:gcc、gdb、ld等工具的集合便是工具鏈(sets)

交叉:軟體產生於宿主機,運行於目標機的開發模式

安裝

進行嵌入式開發前,首先需安裝交叉工具鏈,步驟如下:
1.解壓工具鏈到某一目錄下,例:

tar xvzf arm-linux-gcc-4.5.1-v6-vfp.tgz –C/ (-C表示解壓到後面指定的目錄。如果沒有-C則是預設解壓到當前目錄。解壓後可以進入/4.5.1/bin/,可見很多工具)

2.修改/etc/profile,新增

export PATH=$PATH: /4.5.1/bin(如果不修改/etc/profile,那麼每次執行工具如arm-linux-gcc則必須使用全路徑:/4.5.1/bin/arm-linux-gcc)

3.讓第二步對環境變數的修改生效

執行source /etc/profile

上述三步驟之後,可以在任何目錄下執行arm-linux-gcc

工具使用

----編譯器:arm-linux-gcc

arm-linux-gcc hello.c –o hello

和gcc的用法完全一樣,不過gcc編譯的執行在X86上,而arm-linux-gcc編譯的執行在arm上

----反彙編工具:arm-linux-objdump

arm-linux-objdum –D –S hello

將二進位制檔案程式設計彙編程式碼

arm-linux-objdum–D –S hello > log 匯出到log檔案中

----ELF檔案檢視工具:arm-linux-readelf

arm-linux-readelf –a hello

檢視的資訊中,常用的是:Data項的大小端模式

                                          Machine項

arm-linux-readelf –d hello 檢視hello使用的動態庫

UBoot

用於多種嵌入式CPU(MIPS、X86、ARM、XScale等)的bootloader程式,UBoot不僅支援嵌入式Linux系統的引導,還支援VxWorks,QNX等多種嵌入式作業系統。

U-BOOT啟動流程

開發板上電後,執行U-BOOT的第一條指令,然後順序執行U-BOOT啟動函式。看一下board/smdk2410/u-boot.lds這個連結指令碼,可以知道目標程式的各部分連結順序,第一個喲連結的是cpu/arm920t/start.o,那麼U-BOOT的入口指令一定位於這個程式中

下載

從下面地址可以下載到uboot的原始碼:

目錄結構

進入到UBOOT目錄,可以得到如下的目錄結構:

|--board

|--common

|--cpu

|--disk

|--doc

|--drivers

|--dtt

|--examples

|--fs

|--include

----board:和開發板有關的檔案。每一個開發板都以一個子目錄出現在當前目錄中,比如:smdk2410,子目錄中存放於開發板相關的檔案

----common:實現Uboot支援的命令

----cpu:與特定CPU架構相關的程式碼,每一款Uboot下支援的CPU在該目錄下對應一個子目錄,比如有子目錄arm920t等

----disk:對磁碟的支援

----doc:文件目錄,uboot有非常完善的文件,推薦閱讀

----drivers:uboot支援的裝置驅動程式都放在該目錄,比如各種網絡卡、支援CFI的Flash、串列埠、USB等

.....

----tools:uboot的工具,如:mkimage、crc等等

編譯

Uboot的Makefile從功能上可以分成兩個部分:

1.執行每種board相關的配置

2.編譯生成uboot.bin檔案

uboot.bin的生成也分為兩步,以mini2440開發板為例來說明,如下(申明:該演示所使用的u-boot為經過移植後的u-boot,未經移植的u-boot並不支援該6410開發板,移植過程將在嵌入式linux系統移植專題班講解):

可以在/4.5.1/根目錄下檢視Makefile,來知道uboot支援哪些開發板(比如在這裡可以檢視smdk6410):

1.       選擇要使用的board:

       $make mini2440_config

2.       編譯生成u-boot.bin:

       #makeCROSS_COMPILE=arm-linux-

編譯好後有個uboot.bin檔案。之後將該檔案燒寫到開發板中去

UBoot命令

常用命令

儘管UBOOT提供了豐富的命令集,但不同的單板所支援的命令並不一定一樣(可配置),help命令可用於檢視當前單板所支援的命令。

不同的board支援的命令不一定一樣(可配置)

環境變數相關

print(Printenv) 檢視環境變數

——用法:

      printenv:

-print values of all environment variables

      printenv name ...

-print value of environment variable `name`

setenv:新增、修改、刪除環境變數(存在於記憶體中,只在本次單板開機中有效)

——用法:

      setenv name value...

-set environment variable `name` to `value...`

      setenv name

-delete environment varible `name`

saveenv儲存環境變數(存在於flash中)。將當前定義的所有變數及其值存入flash中

檔案下載

tftp:通過網路下載檔案(開發板必須有ip地址ipaddr和serverip)可以通過ping serverip看網路是否連通

注意:使用tftp,需要先配置好網路

如:

Uboot>setenv ethaddr 12:34:45:78:9A:BC

Uboot>setenv ipaddr 192.168.1.1

Uboot>setenv serverip 192.168.1.254(tftp伺服器的地址)

例:

Uboot>tftp c0800000 uImage

把serber(ip=環境變數中設定的serverip)中服務目錄下的uImage通過TFTP讀入到0xc0800000處

loadb:通過串列埠下載(速度慢,少用)

記憶體操作

md顯示記憶體區的內容。

md採用十六進位制和ASCII碼兩種形式來顯示儲存單元的內容。這條命令還可以採用長度識別符號 .l ,.w和.b;

 md[.b , .w , .l]address

如:

md.w 100000

00100000:(顯示的內容)

00100010:(顯示的內容)

mm:修改記憶體,地址自動遞增

mm [.b , .w ,.l] address

mm提供了一種互動修改儲存器內容的方法。它會顯示地址和當前值,然後提示使用者輸入。如果你輸入了一個合法的十六進位制數,這個新的值將會被寫入該地址。然後提示下一個地址。如果你沒有輸入任何值,只是按了一下回車,那麼該地址的內容保持不變。如果想結束輸入,則輸入空格,然後回車

如:mm 100000

00100000:(顯示的內容)

00100004:(顯示的內容)

FLASH操作

flinfo:檢視flash扇區資訊

用法:Uboot>flinfo

protect :flash防寫

  開啟或關閉扇區防寫

——用法:

protect off all

   關閉所有扇區的防寫

protect on  all

   開啟所有扇區的防寫

protect off  start end

   關閉從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(預設是.l,即32位的拷貝)

cp提供了一種記憶體與記憶體,記憶體與flash之間資料拷貝的方法

例:

cp.b 31000000 50000 d0000

   將記憶體地址0x31000000處的資料(長度為0xd0000)拷貝到地址0x50000處(flash中)

cp.b 32000000 120000 c0000

   將記憶體地址0x32000000處的資料(長度為0xc0000)拷貝到地址0x120000處(flash中)

注意:必須先用erase命令擦除flash,才能用cp命令執行成功

執行程式

go:執行記憶體中的二進位制程式碼,一個簡單的跳轉到指定地址

——go addr [arg...]

        -start application at address `addr` , passing `arg` as arguments

bootm:執行記憶體中的二進位制程式碼

——bootm [addr[arg...]]

         -boot application image stored in memory passing arguments `arg..`;when booting a linux kernel , `arg`can be the address of an initrd image

bootm要求所有可執行的二進位制程式碼前部有固定格式的檔案頭,那麼如何做這個檔案頭呢?——uboot下tools中有個mkimage工具可以

注意:bootm可以沒有addr地址,這時它自動執行個預設的地址

開發板資訊

bdinfo——顯示開發板資訊

bdinfo命令(簡寫為bdi)將在終端顯示諸如記憶體地址和大小、時鐘頻率、MAC地址等資訊。這些資訊在傳遞給linux核心一些引數時可能會用到

自動啟動

1.設定自動啟動——通過設定環境變數:

比如:Mini2440=>setenv bootcmd tftp 31000000 uImage \; bootm 31000000

           Mini2440=>saveenv

           ——執行了兩個操作並儲存