BootLoader依赖于具体的嵌入式板级设备的配置。每种不同的CPU体系结构都有不同的BootLoader。除了依赖于CPU的体系结构外,BootLoader 还依赖于具体的嵌入式板级设备的配置,比如板卡的硬件地址分配,外设芯片的类型等。这也就是说,对于两块不同的开发板而言,即使它们是基于同一种CPU而构建的,但如果他们的硬件资源或配置不一致的话,要想在一块开发板上运行的BootLoader程序也能在另一块板子上运行,还是需要作修改。
这是进行U-Boot 移植首先要明确的。可以根据目标板上CPU、FLASH、SDRAM 的情况,以尽可能相一致为原则,先找出一个与所移植目标板为同一个或同一系列处理器的U-Boot支持板为移植参考板。对U-Boot 移植新手,建议依照循序渐进的原则,目标板文件名暂时先用移植参考板的名称,在逐步熟悉U-Boot 移植基础上,再考虑给目标板重新命名。在实际移植过程中,可用Linux 命令查找移植参考板的特定代码,如 grep –r 2410 ./ 可确定出在U-Boot 中与smdk2410 板有关的代码,依此对照目标板实际进行屏蔽或修改。同时应不局限于移植参考板中的代码,要广泛借鉴U-Boot 中已有的代码更好地实现一些具体的功能。还要验证一下这个参考开发板的U-Boot,至少能够配置编译通过。
不同目标板,对U-Boot在FLASH中存放地址要求不尽相同。事实上,这是由处理器中断复位向量来决定的,与主板硬件相关 。也就是说,U-Boot烧写具体位置是由硬件决定的,而不是程序设计来选择的。
根据CPU处理器系列、类型不同,寄存器名称与作用有一定差别。必须根据目标板的实际,进行合理配置。一个较为可行和有效的方法,就是借鉴参考移植板的配置,再根据目标板实际进行合理修改。这是一个较费时间和考验耐力的过程,需要仔细对照处理器各寄存器定义、参考设置、目标板实际作出选择并不断测试。
能从串口输出信息,即使是乱码,也可以说U-Boot 移植取得了实质性突破。 依据调试经历,串口是否有输出,除了与串口驱动相关外,还与FLASH 相关的寄存器设置有关。因为U-Boot 是从FLASH 中被引导启动的,如果 FLASH 设置不正确,U-Boot 代码读取和执行就会出现一些问题。因此,还需要就FLASH 的相关寄存器设置进行一些参数调试。同时,要注意串口收发芯片相关引脚工作波形。依据调试情况,如果串口无输出,可能就是该芯片损坏或工作不正常或串口线的连接不够牢固。如果出现乱码,有一种可能就是波特率等参数设置有问题。
U-Boot1.1.6并不支持所使用的微处理器S3C2440,但是对于同一系列的S3C2410却有很完善的支持,本文的U-Boot移植工作是在微处理器S3C2410和对应的SMDK2410开发板的基础上展开。
本文所使用的开发板的主要硬件配置如下表:
我们在虚拟机VMWare上安装了Ubuntu11.10,并安装了交叉编译工具链arm-linux-gcc 3.4.1。
1.下载源码 http://ftp.denx.de/pub/u-boot/
2.解压源码包
root@czu:~# tar jxvf /root/桌面/u-boot-1.1.6.tar.bz2,解压后在/root 目录下生成u-boot-1.1.6 目录
3.建立自己的目标板
4.编译测试
U-Boot移植操作,实际上就是根据嵌入式系统硬件资源,对相关的文件进行修改。
移植U-Boot到新的嵌入式系统板上包括两个层面的移植,第一层面是针对CPU的移植,第二层面是针对BOARD的移植,同时需要移植相关的头文件。与BOARD相关的文件位于board/smdk2410目录下,复制smdk2410目录并修改文件lowlevel_init.S,flash.c,smdk2410.c。lowlevel_init.S文件是完成系统板外部存储空间的配置;smdk2410.c是通用I/O口的初始化,flash.c是FLASH芯片的驱动程序。与CPU相关的文件位于cpu/arm920t目录及其子目录s3c24x0下,文件start.S主要完成底层硬件初始化和代码搬运任务。头文件也分为CPU和BOARD两个层次,与BOARD相关的头文件主要是include/configs/smdk2410.h和include/flash.h,二者完成系统板参数的基本配置。与CPU相关的头文件是include/s3c2410.h和s3c24x0.h,二者主要完成CPU内部寄存器和中断向量表设置。
除以上需要修改的文件外,公共代码(common目录下的文件)、网络传输代码(net目录)、驱动程序(drivers目录)3部分根据不同的移植要求修改.一般情况下,对U-Boot的功能进行扩充或添加不支持的设备时,需要修改相应的程序。
加入S3C2440 相关代码,使得u-boot可以在s3c2440上正常工作:
1、修改SDRAM 配置 进入 board/czu2440目录修改lowlevel_init.S 文件
2、时钟设置,S3c2440 的时钟计算公式和s3c2410 不一样
本开发板中的Nor Flash型号为SST39VF1601,而配置文件include/configs/czu2440.h中默认型号为AM29LV400。因为本开发板Nor Flash为2MB,和AM29LV800 很相似,且U-Boot也指出,所以对Nor Flash配置修改一下就可以了。
本例中Nor Flash的操作函数在board/czu2440/flash.c中实现,它支持AM29LV400 和AM29LV800。
#if 0
#define CONFIG_AMD_LV400 1 /* uncomment this if you have a LV400 flash */
#endif
#define CONFIG_AMD_LV800 1 /* uncomment this if you have a LV800 flash */
--------------------------------------------------------------------------------------------------------------------------------------------
#define PHYS_FLASH_SIZE 0x00200000 /* 2MB */
--------------------------------------------------------------------------------------------------------------------------------------------
#define CFG_ENV_ADDR (CFG_FLASH_BASE + 0x1F0000) /* addr of environment */
--------------------------------------------------------------------------------------------------------------------------------------------
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
U-Boot1.1.6对Nand Flash的支持有新旧两套产品,新代码在drivers/nand目录下,旧代码在drivers/nand_legacy目录下。新代码来自Linux内核2.6.12,更加智能,可以自动识别更多型号的Nand Flash,之所以还保留旧代码是因为NETTA和NETTA_ISDN开发板使用JFFS文件系统,它们还依赖旧代码。选择使用哪一套代码由相应的宏决定。本文使用新代码,需要增加CFG_CMD_NAND宏。
Nand Flash的初始化函数是lib_arm/board.c中的start_armboot函数调用的nand_init函数。该函数在/drivers/nand/nand.c中实现,它调用相同文件中的nand_init_chip函数;nand_init_chip函数首先调用board_nand_init函数来初始化Nand Flash设别,最后才是统一的识别过程。board_nand_init函数和平台/开发板相关,需要自己编写。
讲解完基本原理后,接下来讲解移植过程。
修改配置文件 include/configs/czu2440.h, 修对 Flash 的配置和增加 NAND
//#define CFG_ENV_IS_IN_FLASH 1
#define CFG_ENV_IS_IN_NAND 1
#define CFG_ENV_OFFSET 0x80000
#define CFG_ENV_SIZE64 0xc000 /* Total Size of Environment Sector */
#define CFG_ENV_SIZE 0x20000 /* Total Size of Environment Sector */
/*-----------------------------------------------------------------------
* NAND flash settings
*/
#define CFG_NAND_BASE 0 //基地址 这个在board_nand_init中会重新指定
#define CFG_MAX_NAND_DEVICE 1 //设备数目
#define NAND_MAX_CHIPS 1 //每个设备由一个芯片组成
修改配置文件 include/configs/czu2440.h,增加 NAND 命令
#define CONFIG_COMMANDS \
(CONFIG_CMD_DFL | \
CFG_CMD_CACHE | \
CFG_CMD_NAND | \
/*CFG_CMD_EEPROM |*/ \
/*CFG_CMD_I2C |*/ \
/*CFG_CMD_USB |*/ \
CFG_CMD_REGINFO | \
CFG_CMD_DATE | \
CFG_CMD_ELF)
增加 :cpu/arm920t/s3c24x0/nand_flash.c文件,实现board_nand_init函数。
同时修改cpu/arm920t/s3c24x0目录下的 Makefile
修改该目录下的 Makefile:29 行
COBJS = i2c.o interrupts.o serial.o speed.o \
usb_ohci.o nand_flash.o
修改 include目录下的s3c24x0.h和s3c2410.h文件
在 include/s3c24x0.h 中定义 S3C2440_NAND结构体:168 行
/* NAND FLASH */
typedef struct {
S3C24X0_REG32 NFCONF;
S3C24X0_REG32 NFCONT;
S3C24X0_REG32 NFCMD;
S3C24X0_REG32 NFADDR;
S3C24X0_REG32 NFDATA;
S3C24X0_REG32 NFMECCD0;
S3C24X0_REG32 NFMECCD1;
S3C24X0_REG32 NFSECCD;
S3C24X0_REG32 NFSTAT;
S3C24X0_REG32 NFESTAT0;
S3C24X0_REG32 NFESTAT1;
S3C24X0_REG32 NFMECC0;
S3C24X0_REG32 NFMECC1;
S3C24X0_REG32 NFSECC;
S3C24X0_REG32 NFSBLK;
S3C24X0_REG32 NFEBLK;
} /*__attribute__((__packed__))*/ S3C2440_NAND;
同时在 include/s3c2410.h中仿照S3C2410_GetBase_NAND函数添加S3C2440_GetBase_NAND函数:
static inline S3C2440_NAND * const S3C2440_GetBase_NAND(void)
{
return (S3C2440_NAND * const)S3C2410_NAND_BASE;
}
U-Boot1.1.6已经支持CS8900网卡,我们设置一些参数就可以使用了,修改include/config/czu2440.h文件:
#define CONFIG_ETHADDR 08:00:3e:26:0a:5b
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_IPADDR 192.168.1.5
#define CONFIG_SERVERIP 192.168.1.1
在实际生产中,可以通过烧片器等工具将内核、文件系统的镜像文件烧入存储器中,BootLoader不需要具备烧写功能。但为了开发方便,通常要增加烧写 内核和文件系统镜像的功能。
U-Boot增加了Nand Flash功能后就可以通过“nand write...”、“nand write.jeffs2..”等命令烧写内核,烧写cramfs、jeffs2文件系统镜像系统。
但在Nand Flash上,yaffs文件系统的性能更加。下面我们来增加“nand write.yaffs..”命令烧写yaffs文件系统镜像。
“nand write.yaffs..”中“nand”是具体的命令,“write.yaffs..”是参数。
U_BOOT_CMD(nand, 5, 1, do_nand,
"nand - NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2] - addr off|partition size\n"
"nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand dump[.oob] off - dump page\n"
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off - mark bad block at offset (UNSAFE)\n"
"nand biterr off - make a bit error at offset (UNSAFE)\n"
"nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section\n");
在 commom/cmd_nand.c 中增加"nand write.yaffs" 的使用说明
U_BOOT_CMD(nand, 5, 1, do_nand,
"nand - NAND sub-system\n",
"info - show available NAND devices\n"
"nand device [dev] - show or set current device\n"
"nand read[.jffs2] - addr off|partition size\n"
"nand write[.jffs2] - addr off|partiton size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
"nand read.yaffs addr off size - read the `size' byte yaffs image starting\n"
" at offset `off' to memory address `addr'\n"
"nand write.yaffs addr off size - write the `size' byte yaffs image starting\n"
" at offset `off' from memory address `addr'\n"
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
"nand dump[.oob] off - dump page\n"
"nand scrub - really clean NAND erasing bad blocks (UNSAFE)\n"
"nand markbad off - mark bad block at offset (UNSAFE)\n"
"nand biterr off - make a bit error at offset (UNSAFE)\n"
"nand lock [tight] [status] - bring nand to lock state or display locked pages\n"
"nand unlock [offset] [size] - unlock section\n");
Nand Flash每一页大小为(2048+64)B(当然还有其他格式),其中的2048B是一般存储数据的区域,64B称为OOB(Out Of Band)区。通常在OOB区存放着坏块标记、前面2048B的ECC校验码等。
camfs、jffs2文件系统镜像没有OOB取的内容,如果将其烧写到Nor Flash时,则是简单的“平铺”,如果烧写到Nand Flash中,则Nand Flash的驱动程序首先会根据OOB的标记掠过坏块,然后将一页数据,也就是2048B写入后,还要计算刚写入的2048B数据的ECC值,并写入OOB区,如此循环。camfs、jffs2文件系统镜像的大小通常是512的整数倍。
yaffs文件系统镜像文件本身就包含了OOB区的数据,这里面有坏块标记,ECC校验码和其他yaffs相关的信息。所以烧写时,不需要再计算ECC值,首先检查是否是坏块,是则跳过,然后写入2048B的数据,最后写入64B的OOB数据,如此循环。yaffs文件系统镜像文件的大小是(2048+64)的整数。要注意的是:烧写yaffs文件系统镜像时,分区上的第一个可用的(不是坏块)块要跳过。
在 nand 命令的处理函数 do_nand 中增加对"nand yaffs"的支持(左边的代码)。
}else if ( s != NULL && !strcmp(s, ".yaffs")){
if (read) {
/* read */
nand_read_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
opts.readoob = 1;
opts.quiet = quiet;
ret = nand_read_opts(nand, &opts);
} else {
/* write */
nand_write_options_t opts;
memset(&opts, 0, sizeof(opts));
opts.buffer = (u_char*) addr;
opts.length = size;
opts.offset = off;
/* opts.forceyaffs = 1; */
opts.noecc = 1;//不计算ECC
opts.writeoob = 1;//烧入文件中的OOB
opts.blockalign = 1;
opts.quiet = quiet;
opts.skipfirstblk = 1;//跳过第一个可用的逻辑块
ret = nand_write_opts(nand, &opts);
}
}
上述代码中,opts.skipfirstblk 是新增加的项,表示烧写时跳过第一个可用的逻辑块, 这是由yaffs文件系统的特性决定的。下面给opts.skipfirstblk 新增加项重新定义 nand_write_options_t结构,并在下面调用的 nand_write_opts 函数中对他进行处理。在 include/nand.h 中进行如下修改,增加 skipfirstblk 成员:
struct nand_write_options {
u_char *buffer; /* memory block containing image to write */
ulong length; /* number of bytes to write */
ulong offset; /* start address in NAND */
int quiet; /* don't display progress messages */
int autoplace; /* if true use auto oob layout */
int forcejffs2; /* force jffs2 oob layout */
int forceyaffs; /* force yaffs oob layout */
int noecc; /* write without ecc */
int writeoob; /* image contains oob data */
int pad; /* pad to page size */
int blockalign; /* 1|2|4 set multiple of eraseblocks to align to */
int skipfirstblk;
};
在 drivers/nand/nand_util.c修改nand_write_opts 函数,增加对skipfirstblk 成员的支持。
int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)
{
int imglen = 0;
int pagelen;
int baderaseblock;
int blockstart = -1;
loff_t offs;
int readlen;
int oobinfochanged = 0;
int percent_complete = -1;
struct nand_oobinfo old_oobinfo;
ulong mtdoffset = opts->offset;
ulong erasesize_blockalign;
u_char *buffer = opts->buffer;
size_t written;
int result;
int skipfirstblk = opts->skipfirstblk;
if (opts->pad && opts->writeoob) {
printf("Can't pad when oob data is present.\n");
return -1;
}
/* skip the first good block when wirte yaffs image */
if (skipfirstblk) {
mtdoffset += erasesize_blockalign;
skipfirstblk = 0;
continue;
}
readlen = meminfo->oobblock;
if (opts->pad && (imglen < readlen)) {
readlen = imglen;
memset(data_buf + readlen, 0xff,
meminfo->oobblock - readlen);
}
进行上面移植后,u-boot 已经支持 yaffs 文件系统映象的烧写,由于前面设"opts.noecc=1"不使用 ECC 校验码,烧写时会提示很多提示信息。修改 drivers/nand/nand_base.c 文件中的 nand_write_page 函数, 将其注释掉
case NAND_ECC_NONE:
//printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");
this->write_buf(mtd, this->data_poi, mtd->oobblock);
break;
U-Boot详细移植过程:https://download.csdn.net/download/ce123/12452602