2010年7月29日 星期四

U-boot 初探

來源: welkin的小窩 U-boot的一些指令

來源:大體上跟著 http://www.denx.de/wiki/publish/DULG/DULG-tqm8xxl.html 作一次就 OK 了!!

1. 在安裝 U-boot 之前要先安裝它的 ELDK 套件(全名為 Embedded Linux Development Kits),主要包含了 cross compiler 工具。
除了 cross compiler 之外,ELDK 還包含許多套件。


2. U-boot 的 compile
-----------------------------------------------------------------
2-1. 下載 u-boot-1.20,tar.bz2, 解壓縮
2-2. cd u-boot
2-3. make distclean
2-4. grep -Rl arm9 * (找出 arm9 的 board)
2-5. make netstar_config
2-6. make all
2-7. make ap946es_config
----------------------------------------------------------------
make netstar_config
是針對你要 compile 的目標。(這個 target 可以在 u-boot/Makefile 找到)
你可以把它當成 Linux kernel 的 configuration。

以 board/integratorap/ 裏的 ap946es_config 為例:

1. 決定 include/config.h 以下三個 macro:
#define CONFIG_INTEGRATOR
#define CONFIG_ARCH_INTEGRATOR 1
#define CONFIG_CM946E_S 1
2. 選擇並修改
board/integratorap/u-boot.lds
因為 integrator 支援好幾種 CPU,所以它會呼叫 boards/integratorap/split_by_variant.sh 來針對 arm946es 修改。
u-boot.lds, 就是要它去找 start.o 時,要去找 cpu/arm946es/start.o 等會我們會再探討,start.o 就是 U-boot 的 entry point。
3. 呼叫 u-boot/mkconfig 來設定一些等會 make all 時會用到的參數,
其中以 ARCH, CPU, BOARD, VENDOR, SOC 最重要!
因為它會影響到 cross compiler 的選用 (如果你不只一個 cross compiler),
compile 和 link flag 的設定,以及到哪個目錄去找你要的東西。

在 u-boot 下面,有不少和以上參數有關的目錄和檔案:
u-boot/
ppc_config.mk
i386_config.mk
....
include/
lib_arm/
lib_avr32/
....
cpu/
74xx_7xx/
arm1136/
....
....
這些參數指引 make 到哪些目去抓

make all
會真正 build 出 u-boot.bin,它的 object 最主要由下面幾個 component 組成:
start.o
start16.o resetvec.o
reset.o
routine get from libraries
最後會產生 u-boot.hex 和 u-boot.srec 及 u-boot.bin。

由上可以看出,中間左邊是 i386,右邊是 power pc,還有其它,那是和 CPU 有關的一些 routine。
最主要就是 start.o 和一些其它所用的函式。
其它所有東西都 build 成 library,在 configure 之後,在 link 時從 library 抓進就可以了。

----------------------------------------------------------------
開機流程,以 cpu/arm946es/start.S 為例:

U-boot 的 start_armboot 到 _bss_start,從 Flash 複製到 RAM,然後 setup 好 stack,
然後就到 start_armboot。(start_armboot 在 lib_arm/board.c 中)

因為 stack 已經設好了,所以這段是用 C 寫了。

進入 start_armboot(),一堆 #ifdef / #ifndef CFG_xxxx,表示要用哪些 ap,driver,都是一些 initialization 的 code,

然後最後就進入一個 main_loop() 中!!
----------------------------------------------------------------

1.jpg


開機流程簡圖


其中左上方是 assembly,而從 start_armboot 之後就是 C code。

值得注意的有以下幾點:
1.
因為這個 bootcode 是由 ARM 的 integrator 提供。

這個 bootcode 有一個假設:
它認為在板子或 CPU 架構中,有一塊 RAM 的位址是 hardware boot 時就可以動了。
因此它有一個 copy 到 RAM 的動作。

在 CPU 或 ASIC 內部先包一塊 RAM 在某些 architecture 有,但是有的 ASIC 並沒有。

對於沒有一開機就有可用的 RAM,勢必要修改這段 code。

此外如果在開機階段有做 memory remapping 的 board 而言,有兩種方法
(1) 一開始就 remapping,再 copy U-boot 到 RAM。
(2) copy 到一個不受 remapping 影響的位址。

U-boot 可以改寫成 XIP 嗎?

但是我目前所知,它是要在 RAM 中執行。


2.
在進入 C code 的 start_armboot()之後,它第一件事就是初始化一個稱為 gd 的 global 指標。
(它的實作是十分 architecture dependent 的)。

參考 include/asm-arm/global_data.h

它的宣告是:

register volatile gd_t *gd asm("r8")

是一個放在 register 的指標!!

它將這個指標指到 RAM 的指定位址,然後清為 0

之所以指定它為 register,是要讓它在這個最初階段,可以讓我們任意指定它指到 RAM 的位址初使化它。

這個 global variable 在 u-boot 中用來存放一些最開始初始化時所需要用的參數。(這些動作一定要在 RAM 完成)


3.
第一階段的初始化:藉由一個個執行 init_sequence[] 所指到的函式來完成。

目前有的函式為:
cpu_init
board_init
interrupt_init
env_init
init_baudrate
serial_init
console_init_f
display_banner
dram_init
display_dram_config

其中每個函式都回傳 0 表示正確執行,其中 env_init 是去哪裏取得環境變數,

可以是一個固定的陣列,flash,環境變數的資料,會放在 gd 所指的資料結構之中。

由以上看來,因為每個都是 function pointer,各分別屬於在 configuration 階段會指定的目錄中。

如 CPU, BOARD 所指定的目錄,
換言之,我們只要為這些 function pointer 實作出適合我們板子的內容,就可以把融入 U-boot 之中。


4.
在 init_sequence[] 之後, 我把它稱作是第二階段的 initialization。

看來有點亂,一堆 #ifdef,而且有的和前面似乎有重複或矛盾,想是不同 board 的差異太太的關係。

大體上就是 initialize 更多的 device 或是前面 intialization 的第二階段。

沒有留言:

張貼留言