一、 步骤五:U-boot支持TFTP、nfs网络下载
前面我们实现了使用串口下载并更新系统的功能,但是嵌入式系统的内核跟根文件系统都比较大,使用串口下载速度太慢,u-boot提供了通过TFTP、nfs等网络下载的功能支持,本节我们完成此项功能的移植与修改。
1) u-boot默认支持的是cs8900网卡,我们的开发板使用的是DM9000网卡,所以要做相应的修改。
首先要修改include/configs/unsp2440.h中的相关代码:
#define CONFIG_NET_MULTI //#define CONFIG_CS8900 /* we have a CS8900 on-board */ //#define CONFIG_CS8900_BASE 0x19000300 //#define CONFIG_CS8900_BUS16 /* the Linux driver does accesses as shorts */ //屏蔽掉与cs8900有关的宏定义 #define CONFIG_DRIVER_DM9000 1 #define CONFIG_DM9000_NO_SROM 1 #define CONFIG_DM9000_BASE 0x18000300 //网卡片选地址 //网卡地址的选择:S3C2440片外寻址分成8个BLANK,每个BLANK的大小为128M, //我们的开发板的网卡接在了BLANK3上,因此地址等于:128M*3*1024*1024=0x18000000,由于DM9000网卡本身的特性,IO地址需要从0x18000300开始,数据地址需要从0x18000304开始。 #define DM9000_IO 0x18000300 #define DM9000_DATA (0x18000300 + 4) //网卡数据地址 #define CONFIG_DM9000_USE_16BIT 1
2) 使用TFTP、NFS等服务必须配置相应的IP地址、网关等信息,我们同样需要修改include/congifs/unsp2440.h文件相应内容:
//给u-boot加上ping命令,用来测试网络通不通 #define CONFIG_CMD_PING / /恢复被注释掉的网卡MAC地址和修改你合适的开发板IP地址 #define CONFIG_ETHADDR 08:00:3e:26:0a:5b //开发板MAC地址 #define CONFIG_NETMASK 255.255.255.0 #define CONFIG_IPADDR 192.168.1.105 //开发板IP地址 #define CONFIG_SERVERIP 192.168.1.103 //Linux主机IP地址
下面需要修改u-boot的源码以完成对unsp2440的支持:
3) 首先要修改dm9000网卡的总线宽度:board/samsung/unsp2440/lowlevel_init.S
将56行左右的
#define B3_BWSCON (DW16 + WAIT + UBLB)修改为: #define B3_BWSCON (DW16)
4) 编译下载u-boot已测试网络情况
#ping 192.168.220.103
dm9000 i/o: 0x18000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:31:22:22:02:51 operating at 100M full duplex mode Using dm9000 device host 192.168.220.103 is alive
代表网络连接正确,为了验证TFTP是否可以使用,我们使用tftp更新u-boot.bin
首先在PC机上开启一个TFTP服务器,这里我们选取tftpd32.exe这款小软件作为TFTP服务器,首先双击打开此软件,显示以下界面,将要下载的文件u-boot.bin文件拷到与tftpd32.exe同一个目录下。
打开开发板终端:
#tftp 0x33000000 172.20.223.63:u-boot.bin #define CONFIG_SERVERIP 192.168.1.103 //unsp2440.h中此宏所定义的地址
终端中有如下显示:
dm9000 i/o: 0x18000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:31:22:22:02:51 operating at 100M full duplex mode Using dm9000 device TFTP from server 172.20.223.63; our IP address is 172.20.223.22 Filename 'u-boot.bin'. Load address: 0x33000000 Loading: T ########## done Bytes transferred = 144644 (23504 hex)
表示下载成功。
二、 步骤六:U-boot支持TFTP下载启动linux内核、根文件系统
Linux内核的下载过程跟上节下载u-boot.bin基本一致,但是启动linux需要一些其他知识,下面我们来分析一下。
1) 首先是准备uzImage镜像
u-boot采用的linux镜像与我们使用make zImage编译出的镜像稍有不同,u-boot采用uzImage格式的镜像,uzImage是由zImage + 0x40字节的文件头组成。
经过编译后的u-boot在根目录下的tools目录中,会有个叫做mkimage的工具,他可以给zImage添加一个header,也就是说使得通常我们编译的内核zImage添加一个数据头信息部分。
使用: 中括号括起来的是可选的 mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image 选项: -A:set architecture to 'arch' //用于指定CPU类型,比如ARM -O:set operating system to 'os' //用于指定操作系统,比如Linux -T:set image type to 'type' //用于指定image类型,比如Kernel -C:set compression type 'comp' //指定压缩类型 -a:set load address to 'addr' (hex) //指定image的载入地址 -e:set entry point to 'ep' (hex) //内核的入口地址,一般为image的载入地址+0x40(信息头的大小) -n:set image name to 'name' //image在头结构中的命名 -d:use image data from 'datafile' //无头信息的image文件名 -x:set XIP (execute in place) //设置执行位置
先将u-boot下的tools中的mkimage复制到主机的/usr/local/bin目录下,这样就可以在主机的任何目录下使用该工具了。
现在我们进入kernel生成目录(一般是arch/arm/boot目录),然后执行如下命令,就会在该目录下生成 一个uImage.img的镜像文件,把他复制到tftp目录下,这就是我们所说的uImage
mkimage -n 'linux-2.6.34' -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -d zImage uImage.img
2) linux内核启动参数
前一节我们已经得到了u-boot所需要的linux镜像,下面我们设置linux启动所需要的参数,首先u-boot中机器号(match type)与内核必须统一,linux内核中的机器号为:
在kernel的arch/arm/tools/mach-types文件中针对不同的CPU定义了非常多的MACH_TYPE,我们找到379行左右:
s3c2440 ARCH_S3C2440 S3C2440 362
同时arch/arm/mach-s3c2440/mach-smdk2440.c文件中smdk2440_machine_init函数
MACHINE_START(S3C2440, "SMDK2440") 决定了当前内核的match type是362.
下面我们修改u-boot中的match-types与之匹配
在u-boot的include/asm-arm/mach-types.h文件中针对不同的CPU定义了非常多的MACH_TYPE,可以找到下面这个定义:
#define MACH_TYPE_S3C2440 362
我们增加以下定义:
#define MACH_TYPE_UNSP2440 362
修改 board/samsung/unsp2440/unsp2440.c文件中board_init函数
gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; 为: gd->bd->bi_arch_number = MACH_TYPE_UNSP2440;
重新编译,我们就能得到支持我们开发板内核的u-boot了。
3) 下载uzImage镜像:
下载linux内核到NAND FLASH中的具体地址,由内核中的FLASH分区表决定:
在arch/arm/plat-s3c24xx/common-smdk.c文件中可找到以下信息:
static struct mtd_partition smdk_default_nand_part[] = { [0] = { .name = "bootloader", .offset = 0, //boorloade分区起始地址 .size = 0x30000, //bootloader分区的大小 }, //bootloader分区与kernel分区之间0x30000---0x50000的地址用作存放linux参数分区 //这个地址范围要与前面我们移植NAND驱动时定义的CONFIG_ENV_OFFSET保持统一 [1] = { .name = "kernel", .offset = 0x50000, //kernel分区起始地址 .size = 0x300000, //kernel分区的大小 }, [2] = { .name = "root", .offset = 0x350000, //root分区起始地址 .size = 0x3cac000, //root分区起始地址 }, };
下面我们使用命令行更新并下载内核:
#tftp 0x33000000 172.20.223.63:uImage.img #nand erase 0x50000 0x300000 //注意这两个数据的大小一定要跟上述表中的 kernel分区保持一致 #nand write 0x33000000 0x50000 0x300000 //将0x33000000中数据写入NAND FLASH中 启动内核: #从ram中启动kernel #bootm 0x33000000 #从NAND FLASH中启动 #nand read 0x33000000 0x50000 0x300000 # bootm 0x33000000 #u-boot提供了另一个命令用来启动内核 #nboot 0x33000000 0 0x50000 //nboot代表从nand中启动内核,0x33000000表示内核拷贝的地址,0 代表第一块FLASH,0x50000代表kernel镜像的起始位置,不用指定大小,这个命令会自动判断内核镜像的大小 # bootm 0x33000000
如果没有问题的话,在终端中可以看到内核启动信息。
4)下载linux根文件系统
Linux根文件系统有各种各样的格式,有基于norFLASH的jffs2,基于NAND的cramfs与yaffs,基于网络的nfs等。
a) 这里首先我们先使用nfs根文件系统来启动我们的系统。
需要修改u-boot传递给linux 内核的启动参数,我们可以修改include/configs/unsp2440.h文件中的宏:
#define CONFIG_BOOTARGS "noinitrd root=/dev/nfs nfsroot=/home/dengwei/linux_system/root_src/rootfs_test/,rsize=1024,wsize=1024 ip=172.20.223.118:172.20.223.151:172.20.223.254:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0"
或者直接在终端下通过命令行完成:
setenv bootargs noinitrd root=/dev/nfs nfsroot=/home/dengwei/linux_system/root_src/rootfs_test/,rsize=1024,wsize=1024 ip=172.20.223.118:172.20.223.151:172.20.223.254:255.255.255.0::eth0:off init=/linuxrc console=ttySAC0
b) 下面我们启动NAND FLASH中的根文件系统
NAND FLASH中常用两种格式的根文件系统:cramfs、yaffs
cramfs是压缩的只读根文件系统,u-boot直接支持
yaffs/yaffs2是未压缩的可读可写的文件系统,u-boot需要修改之后才能支持。
这里我们先烧写cramfs格式的根文件系统,下节再修改、移植支持yaffs格式根文件系统的u-boot。
cramfs格式的根文件系统制作请参考其它相关文章,假设我们现在已经有了此格式的根文件系统,并且名字为:rootfs.cramfs。
#tftp 0x33000000 172.20.223.63:rootfs.cramfs
#nand erase 0x350000 0x3cac000 //注意这两个数据的大小一定要跟上述表中的 root分区保持一致
#nand write 0x33000000 0x350000 0x3cac000 //将0x33000000中数据写入NAND FLASH中
启动内核,如果顺利的话可以观察到我们的根文件系统也顺利的启动起来了。