|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?注册
x
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 芯片的内核结构、具体型号、应用系统的配置及使用的操作系统等因素有关,其功能类似于PC机的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处。 |
|