U-BOOT的啟動流程及移植

U-BOOT的啟動流程及移植
摘要:嵌入式系統一般沒有通用的bootloader,u-boot是功能強大的bootloader開發軟件,但相對也比較復雜。文中對u-boot的啟動流程作了介紹,詳細給出了u-boot在S3C2410開發板上的移植方法和步驟。  
關鍵詞:bootloader;u-boot;嵌入式系統;移植;S3C44B0
1.Bootloader及u-boot簡介
Bootloader代碼是芯片復位后進入操作系統之前執行的一段代碼,主要用於完成由硬件啟動到操作系統啟動的過渡,從而為操作系統提供基本的運行環境,如初始化CPU、堆棧、存儲器系統等。Bootloader 代碼與CPU 芯片的內核結構、具體型號、應用系統的配置及使用的操作系統等因素有關,其功能類似於P機的BIOS程序。由於Bootloader和CPU及電路板的配置情況有關,因此不可能有通用的Bootloader ,開發時需要用戶根據具體情況進行移植。嵌入式Linux系統中常用的Bootloader有armboot、redboot、blob、u-boot等,其中u-boot是當前比較流行,功能比較強大的Bootloader,可以支持多種體系結構,但相對也比較復雜。Bootloader的實現依賴於CPU的體系結構,大多數Bootloader都分為stage1和stag2兩大部分。Bootloader的基本原理見參考文獻。
u-boot是sourceforge網站上的一個開放源代碼的項目。它可對 PowerPC、Mpc5xx、Mpc8xx、Mpc82xx、Mpc7xx、Mpc74xx、arm(ARM7、ARM9、StrongARM、Xscale)、MIPS(4kc、5kc)、X86等處理器提供支持,支持的嵌入式操作系統有Linux、Vx-Works、NetBSD、QNX、RTEMS、ARTOS、LynxOS等,主要用來開發嵌入式系統初始化代碼Bootloader。軟件的主站點是http://sourceforge.net/projects/  u-boot。u-boot最初是由denx(www.denx.de)的PPC-boot發展而來的,它對PowerPC系列處理器的支持最完善,對Linux 操作系統的支持最好。源代碼開放的u-boot軟件項目經常更新,是學習硬件底層代碼開發的很好樣例。
2 u-boot系統啟動流程
大多數Bootloader都分為stage1和stage2兩大部分,u-boot也不例外。依賴於CPU體系結構的代碼(如設備初始化代碼等)通常都放在stage1且可以用匯編語言來實現,而stage2則通常用C語言來實現,這樣可以實現復雜的功能,而且有更好的可讀性和移植性。
2.1 stage1 (start.s代碼結構)
u-boot的stage1代碼通常放在start.s文件中,它用匯編語言寫成,其主要代碼部分如下:
(1) 定義入口 。由於一個可執行的Image必須有一個入口點,並且只能有一個全局入口,通常這個入口放在ROM(Flash)的0x0地址,因此,必須通知編譯器以使其知道這個入口,該工作可通過修改連接器腳本來完成。
(2)設置異常向量(Exception Vector)。
(3)設置CPU的速度、時鐘頻率及中斷控制寄存器。
(4)初始化內存控制器 。
(5)將ROM中的程序復制到RAM中。
(6)初始化堆棧 。
(7)轉到RAM中執行,該工作可使用指令ldr pc來完成。
2.2 stage2  C語言代碼部分
lib arm/board.c中的start armboot是C語言開始的函數,也是整個啟動代碼中C語言的主函數,同時還是整個u-boot(armboot)的主函數,該函數主要完成如下操作:
(1)調用一系列的初始化函數。
(2)初始化Flash設備。
(3)初始化系統內存分配函數。
(4)如果目標系統擁有NAND設備,則初始化NAND設備。
(5)目標系統有顯示設備,則初始化該類設備。
(6)相關網絡設備,填寫IP、MAC地址等。
(7)令循環(即整個boot的工作循環),接受用戶從串口輸入的命令,然后進行相應的工作。
3 移植實例
3.1 u-boot文件下載
u-boot文件的下載有兩種方法,第一種是在Linux環境下通過CVS下載最新的文件,方法是:
server:anonymous@cvs.sourceforge.net:/cvsroot/u-boot login
[/img]
cvs -z3 -d server:anonymous@cvs.sourceforge.net:/cvsroot/u-boot checkout -P u-boot
第二種是通過ftp://ftp.denx.de/pub/u-boot/下載正式發布的壓縮文件。
3.2 u-boot文件的結構
初次下載的文件有很多,解壓后存放在u-boot文件目錄下,具體內容已在readme文件中做了詳細的介紹,其中與移植相關的主要文件夾有:
(1)CPU它的每個子文件夾里都有如下文件:
makefile
config.mk
cpu.c 和處理器相關的代碼
interrupts.c 中斷處理代碼
serial.c 串口初始化代碼
start.s 全局開始啟動代碼
(2)BOARD它的每個子文件夾里都有如下文件:
makefile
config.mk
smdk2410.c 和板子相關的代碼(以smdk2410為例)
Flash.c Flash操作代碼
memsetup.s 初始化SDRAM代碼
u-boot.lds 對應的連接文件
(3)lib arm體系結構下的相關實現代碼,比如memcpy等的匯編語言的優化實現。
3.3 交叉編譯環境的建立
要得到下載到目標板的u-boot二進制啟動代碼,還需要對下載的u-boot進行編譯。u-boot的編譯一般在Linux系統下進行,可用ARM-LINUX-GCC進行編譯。一步一步建立交叉編譯環境通常比較復雜,最簡單的方法是使用別人編譯好的交叉編譯工具,方法如下:
(1)在http://handhelds.org/download   下載 arm-linux-gc-x.x.x-tar.gz  
(2)以用戶名root登錄,將arm-linux-gcc-x.x.x.tar.bz2 解壓到 /root目錄下
# tar jxvf arm-linux-gcc-x.x.x.tar.bz2
這樣就建立了arm linux 交叉編譯環境。
(4)增加/root/usr/local/arm/x.x.x/bin到路徑環境變量
path=$path:/root/usr/local/arm/x.x.x/bin 可以檢查路徑變量是否設置正確。
AVICOM (10/100M) 網卡
USB HOST一個
配置自已的主板:
閱讀Makefile文件,在Makefile文件中添加兩行:
s3c2410_config: unconfig  
@./mkconfig $(@:_config=) arm arm920t s3c2410
其中ARM是CPU的種類, arm920t是ARM CPU對應的代碼目錄,s3c2410是自已主板對應的目錄。在board目錄中建立s3c2410目錄,復制smdk2410目錄中的內容(cp smdk2410/* s3c2410)。在include/configs/目錄下復制smdk2410.h(cp smdk2410.h s3c2410.h)修改ARM編譯器的目錄名及前綴.
本人ARM編譯器的目錄是在:/opt/host/armv4l/bin/armv4l-unknown-linux-
把CROSS-COMPILE = arm-linux- 改為實際目錄:如
CROSS-COMPILE = /opt/host/armv4l/bin/arm4l-unknown-linux-
完成之后,可以測試一下你的配置:
[/img]
make s3c2410_config  
標記符0, 原來存在的標記符)
用SJF軟件通過jtag口下載編譯的u-boot, 啟動!讀取環境塊時CRC出錯,然后進入SMDK[/img]

把MIZI vivi中的PrintHexWord, PrintWord拷過來, 這樣可以在調試匯編時可以打印一些信息,但其中有的PrintHexNibble中有缺陷,ldr r0, [r2, r0] 應改為ldrb r0, [r2, r0],這樣可以在四字節對齊的系統中使用。
INTEL nor flash操作功能
INTEL 的28F128,在board目錄中找到CMI主板有此FLASH,把cmi中flash.c拷到s3c2410目錄代換原來的flash.c。
cmi中的flash.c在寫入時要交換字節,所以刪除它的write_short()和wirte_buff()函數,把ep7312主板目錄中flash.c的wirte_word()和wirite_buff()函數復制過來。把flash.c中的FLASH_BASE0_PRELIM改為CFG_FLASH_BASE。把FLASH_BLOCK_SIZE改為0x20000,(E28F128J3A flash中塊的大小是128K)。
l把s3c2410.h中的flash內容由原來的:
1.
1 */
2.
define CONFIG_AMD_LV4001
4.
define CONFIG_AMD_LV8001
6.
define CFG_MAX_FLASH_BANKS1/* max number of memory banks */
8.
define PHYS_FLASH_SIZE0x00100000 /* 1MB */
10.
define CFG_ENV_ADDR(CFG_FLASH_BASE + 0x0F0000) /* addr of environment */
12.
ifdef CONFIG_AMD_LV400
14.
define CFG_MAX_FLASH_SECT(11)/* max number of sectors on one chip */
16.
define PHYS_FLASH_10x00000000 /* Flash Bank
define PHYS_FLASH_SIZE0x01000000 /* 16 MB */
3.
define CFG_MONITOR_BASE  PHYS_FLASH_1
6.
define CFG_MAX_FLASH_SECT 128/* max number of sectors on one chip*/
8.
define CFG_FLASH_WRITE_TOUT(2*CFG_HZ) /* Timeout for Flash Write */
10.
define CFG_ENV_ADDR(PHYS_FLASH_1 + 0x60000)
12.
;
    return 0;
}
以使mw和mm命令不能修改flash中的數據,而只開放cp修改flash中的數據。
改board/s3c2410/flash.c中的flash_erase(),把start = get_timer(0)移到for(), 以去掉flash_erase timeout 錯誤。
設置FLASH和SDRAM時序
根據28F128J3A-150,這是一150ns的flash, 所以把flash時序設為最慢。把s3c2410設成202.8MHZ, 並且工作在異步模式, 修改memsetup.S。  
實現網卡功能
本人的網卡是DM9000,在uboot中沒有相應的驅動,所以自已寫了一個網卡驅動。
1.把驅動拷到drivers/dm9000.c
2.在drivers/Makefile中加入dm9000.o
3.在lib_arm/board.c中修改CS8900=>DM9000
4.在include/configs/s3c2410中加入以下幾句
[/img]
define CONFIG_DRIVER_DM90001/* we have a CS8900 on-board */

define DM9000_BUS161 /* the Linux driver does accesses as shorts */

define CONFIG_NETMASK          255.255.255.0

define CONFIG_SERVERIP192.168.2.122  
實現USB功能
1.在include/configs/s3c2410中的CONFIG_COMMANDS中加入:
lCFG_CMD_USB  |\
lCFG_CMD_FAT  |\
2.並在文件中加入以下設置:
l
define CONFIG_USB_STORAGE
l
define CONFIG_DOS_PARTITION
l
define CONFIG_SUPPORT_VFAT
l
define cp936
l在fat_getenv()中有一個對齊錯誤,修改fat.h使fatbuff字對齊。
l在do_fat_read()中加入兩句,以消除列根目錄錯誤。
l在board/cmd_fat.c中加入兩句,以消除沒有usb storage設備時的錯誤:
if(!dev_desc)
printf("Not init storage usb device:\n usb start\n usb info\n usb scan\n";
5.修改fs/fat/fat.c
get_cluster()函數中加入 if(size / FS_BLOCK_SIZE > 0), 以防讀文件時不能成功讀出。
引導LINUX
現在我們可以引導LINUX了。
要引導bzip2的linux核,把CFG_MALLOC_SIZE改為大於4M
把編譯好的LINUX內存,通過uboot/tools/mkimage轉換成uboot格式
1.mkimage -A arm -O linux -T kernel -C bzip2 -a 30000000 -e 30008000 -n 'linux kernel'      -d vmlinux1.bz2 c
2.mkimage -A arm -O linux -T kernel -C gzip -a 30000000 -e 30008000 -n 'linux kernel' -d vmlinux.gz b
3.mkimage -A arm -O linux -T ramdisk -C gzip -a 0 -e 0 -n 'init ramdisk' -d ramdisk.image.gz ramdisk
在include/configs/s3c2410.h中加入:
1.
define CONFIG_BOOTFILE"vmlinux_for_uboot.gz"  
3.
defineCFG_LOAD_ADDR0x30800000/* default load address*/
l在lib_arm/armlinux.c的do_bootm_linux中加入:
1.memcpy ((char *)CFG_LOAD_ADDR, (char *)data, len);
2.data = CFG_LOAD_ADDR;
把ramdisk復制到0x30800000位置的RAM中
3.定義以下配置,把信息傳入LINUX核心的TAG區

define CONFIG_INITRD_TAG
[img][/img]
ne CONFIG_CMDLINE_TAG  
常用U-BOOT命令介紹
1.?得到所有命令列表
2.help: help usb, 列出USB功能的使用說明
3.ping:注:只能開發板PING別的機器
4.setenv: 設置互環境變量:
5.setenv serverip 192.168.0.1
6.setenv ipaddr 192.168.0.56
7.setenv bootcmd 'tftp 32000000 vmlinux; kgo 32000000'
8.saveenv: 保存環境變量
9.在設置好環境變量以后, 保存變量值
10.tftp: tftp 32000000 vmlinux, 把server(IP=環境變量中設置的serverip)中/tftpdroot/ 下的vmlinux通過TFTP讀入到物理內存32000000處。
11.kgo: 起動沒有壓縮的linux內核,kgo 32000000
12.bootm:起動UBOOT  TOOLS制作的壓縮LINUX內核, bootm 3200000
13.protect: 對FLASH進行寫保護或取消寫保護, protect on 1:0-3(就是對第一塊FLASH的0-3扇區進行保護),protect off 1:0-3取消寫保護
14.erase: 刪除FLASH的扇區, erase 1:0-2(就是對每一塊FLASH的0-2扇區進行刪除)
15.cp: 在內存中復制內容, cp 32000000 0 40000(把內存中0x32000000開始的0x40000字節復制到0x0處)
16.mw: 對RAM中的內容寫操作, mw 32000000 ff 10000(把內存0x32000000開始的0x10000字節設為0xFF)
17.md: 修改RAM中的內容, md 32000000(內存的起始地址)
18.usb:  
lusb start: 起動usb 功能
lusb info: 列出設備
lusb scan: 掃描usb storage(u 盤)設備
19.fatls:列出DOS FAT文件系統, 如:fatls usb 0列出第一塊U盤中的文件
20.fatload: 讀入FAT中的一個文件,如:fatload usb 0:0 32000000 aa.txt
21.把USB中的aa.txt 讀到物理內存0x32000000處!
22.flinfo: 列出flash的信息
23.loadb:準備用KERMIT協議接收來自kermit或超級終端傳送的文件。
24.nfs: nfs 32000000 192.168.0.2:aa.txt , 把192.168.0.2(LINUX 的NFS文件系統)中的NFS文件系統中的aa.txt 讀入內存0x32000000處。

留言

這個網誌中的熱門文章

python serial 模組使用方法 #1

USB HID 教學 #1(轉載)

USB HID 教學 #2 (轉載)