分类: LINUX
2010-07-15 15:07:38
U-boot简介
一般来说,引导加载程序是系统加电后运行的第一段代码(at91sam芯片除外,其加电第一段程序是BOOTROM,其次是Bootstrap)。大家熟悉的PC中的引导程序一般由BIOS和位于MBR的操作系统BootLoader(例如LILO或者GRUB)一起组成。然而在嵌入式系统中通常没有像BIOS那样的固件程序,因此整个系统的加载启动任务就完全由BootLoader来完成。在嵌入式Linux中,引导加载程序即等效为BootLoader。简单地说,BootLoader就是在操作系统内核运行前执行的一段小程序。通过这段小程序,我们可以初始化必要的硬件设备,创建内核需要的一些信息并将这些信息通过相关机制传递给内核,从而将系统的软硬件环境带到一个合适的状态,最终调用操作系统内核,真正起到引导和加载内核的作用。
BootLoader是依赖于硬件实现的,特别是在嵌入式系统中。不同体系结构需求的BootLoader是不同的,除了体系结构,BootLoader还依赖于具体的嵌入式板级设备的配置。也就是说,对于两块不同的嵌入式板而言,即使它们基于相同的CPU构建,运行在其中一块电路板上的BootLoader,未必能够运行在另一块电路开发板上。
Bootloader的启动过程可以是单阶段的,也可以是多阶段的。大多数单阶段的BootLoader应用于简单的系统,比如没有操作系统的系统。通常多阶段的BootLoader能提供更为复杂的功能以及更好的可移植性。从固态存储设备上启动的BootLoader大多数是两阶段的启动过程,也就是启动过程可以分为stage 1和stage 2两部分。依赖于CPU体系结构的代码,比如设备初始化代码 等,通常都放在stage1中,而且通常都用汇编语言来实现,以达到短小精悍的目的。而stage2则通常用C语言来实现,这样可以实现更复杂的功能,而且代码会具有更好的可读性和可移植性。
大多数BootLoader都包含两种不同的操作模式:启动加载(Boot loading)模式和下载(Down loading)模式,这种区别仅对于开发人员才有意义。但从最终用户的角度看,BootLoader的作用就是用来加载操作系统,而并不存在所谓的启动加载模式与下载工作模式的区别。
(1)启动加载模式:这种模式也称为自主(Autonomous)模式,即BootLoader从目标机上的某个固态存储设备上将操作系统加载到RAM中运行,整个过程没有用户的介入。这种模式是BootLoader的正常工作模式。因此在嵌入式产品发布的时候,BootLoader显然必须工作在这种模式下。
(2)下载模式:在这种模式下,目标机上的BootLoader将通过串口连接或网络连接等通信手段从主机上下载文件,比如下载应用程序、数据文件、内核映像等。从主机下载的文件通常首先被BootLoader保存到目标机的RAM中然后再被BootLoader写到目标机上的固态存储设备中,BootLoader的这种模式通常在系统更新时使用。工作于这种模式下的BootLoader通常都会向它的终端用户提供一个简单的命令行接口,比如U-Boot、Blob、VIVI等。
U-Boot是德国DENX小组开发的用于多种嵌入式CPU的BootLoader程序,它可以运行在基于PowerPC、ARM、MIPS等多种嵌入式开发板上。从 或 站点都可以下载U-Boot的源代码,U-Boot源代码的主要目录解释如下。
· board 目标板相关文件,主要包含SDRAM、Flash驱动;
· common 独立于处理器体系结构的通用代码,如内存大小探测与故障检测;
· cpu 与处理器相关的文件,如mpc8xx子目录下含串口、网口、LCD驱动及中断初始化等文件;
· driver 通用设备驱动,如CFI Flash驱动(目前对Intel Flash支持较好);
· doc U-Boot的说明文档;
· examples 可在U-Boot下运行的示例程序,如hello_world.c、timer.c;
· include U-Boot头文件,尤其是configs子目录下与目标板相关的配置头文件是移植过程中经常要修改的文件;
· lib_xxx 处理器体系相关的文件,如lib_ppc、lib_arm目录分别包含与PowerPC、ARM体系结构相关的文件;
· net 与网络功能相关的文件目录,如bootp、nfs、tftp;
· post 上电自检文件目录,尚有待于进一步完善;
· rtc RTC(Real Time Clock,实时时钟)驱动程序;
· tools 用于创建U-Boot S-RECORD和BIN镜像文件的工具。
开发环境
? Linux环境:Ubuntu 10.4。
? Windows环境:Windows XP SP3。
? U-boot版本:v1.3.4。
? 交叉编译工具:arm-linux-gcc 4.3.2。
U-boot源代码及ATMEL补丁
U-boot-1.3.4源代码下载地址:
ftp://ftp.denx.de/pub/u-boot/u-boot-1.3.4.tar.bz2
AT91 U-boot 功能补丁下载地址:
ftp://
安装补丁及修改编译U-boot
1. 解压U-boot-1.3.4
将u-boot-1.3.4.tar.bz2压缩包拷贝到/opt/目录,在提示符下输入:
/opt# tar jxf u-boot-1.3.4.tar.bz2
将压缩包解压在当前目录。如图1所示:
图 1
2. 安装补丁文件
将补丁文件u-boot-1.3.4-exp.diff和u-boot-1.3.4-exp.5.diff复制到U-boot的根目录下。
/opt/u-boot-1.3.4# cat u-boot-1.3.4-exp.5.diff | patch -p1
3. 修改U-boot源代码
增加对DM9000的支持:
修改board\atmel\at91sam9g20ek\at91sam9g20ek.c文件,在其中添加 DM9000的硬件初始化:
#ifdef CONFIG_DRIVER_DM9000
static void at91sam9263ek_dm9000_hw_init(void)
{
/* Configure SMC CS2 for DM9000 */
at91_sys_write(AT91_SMC_SETUP(2),
AT91_SMC_NWESETUP_(2) | AT91_SMC_NCS_WRSETUP_(0) |
AT91_SMC_NRDSETUP_(2) | AT91_SMC_NCS_RDSETUP_(0));
at91_sys_write(AT91_SMC_PULSE(2),
AT91_SMC_NWEPULSE_(4) | AT91_SMC_NCS_WRPULSE_(8) |
AT91_SMC_NRDPULSE_(4) | AT91_SMC_NCS_RDPULSE_(8));
at91_sys_write(AT91_SMC_CYCLE(2),
AT91_SMC_NWECYCLE_(16) | AT91_SMC_NRDCYCLE_(16));
at91_sys_write(AT91_SMC_MODE(2),
AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
AT91_SMC_EXNWMODE_DISABLE |
AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16 |
AT91_SMC_TDF_(1));
/* Configure Reset signal as output */
at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS2*/
/* Configure Interrupt pin as input, no pull-up */
at91_set_gpio_input(AT91_PIN_PB25, 0);
}
#endif
229行添加:
#ifdef CONFIG_DRIVER_DM9000
at91sam9263ek_dm9000_hw_init();
#endif
250行修改:
#if defined(CONFIG_MACB) || defined(CONFIG_DRIVER_DM9000)
增加烧写YAFFS的功能:
修改common/cmd_nand.c文件,在其349行添加:
#if defined(ENABLE_CMD_NAND_YAFFS)
} else if ( s != NULL &&
(!strcmp(s, ".yaffs") || !strcmp(s, ".yaffs1"))){
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.noecc = 1;
opts.pad = 0;
opts.writeoob = 1;
opts.blockalign = 1;
opts.quiet = quiet;
opts.autoplace = 1;
if (s[6] == '1')
opts.forceyaffs = 1;
#if defined(ENABLE_CMD_NAND_YAFFS_SKIPFB)
opts.skipfirstblk = 1;
#endif
ret = nand_write_opts(nand, &opts);
}
#endif
在504行添加如下红色代码:
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|partition size - read/write `size' bytes starting\n"
" at offset `off' to/from memory address `addr'\n"
#if defined(ENABLE_CMD_NAND_YAFFS)
"nand write[.yaffs[1]] - addr off|partition size - write `size' byte yaffs image\n"
" starting at offset `off' from memory address `addr' (.yaffs1 for 512+16 NAND)\n"
#endif
"nand erase [clean] [off size] - erase `size' bytes from\n"
" offset `off' (entire device if not specified)\n"
"nand bad - show bad blocks\n"
修改drivers/mtd/nand/nand_util.c文件,在356行添加如下红色代码:
/* force OOB layout for jffs2 or yaffs? */
if (opts->forcejffs2 || opts->forceyaffs) {
struct nand_oobinfo *oobsel =
opts->forcejffs2 ? &jffs2_oobinfo : &yaffs_oobinfo;
#if definde(CFG_NAND_YAFFS1_NEW_OOB_LAYOUT)
/* jffs2_oobinfo matches 2.6.18+ MTD nand_oob_16 ecclayout */
oobsel = &jffs2_oobinfo;
#endif
if (meminfo->oobsize == 8) {
if (opts->forceyaffs) {
printf("YAFSS cannot operate on "
"256 Byte page size\n");
goto restoreoob;
在456行添加如下红色代码:
/* read OOB data from input memory block, exit
* on failure */
memcpy(oob_buf, buffer, meminfo->oobsize);
buffer += meminfo->oobsize;
if (opts->forceyaffs) {
#if define(CFG_NAND_YAFFS1_NEW_OOB_LAYOUT)
/* translate OOB for yaffs1 on Linux 2.6.18+ */
oob_buf[15] = oob_buf[12];
oob_buf[14] = oob_buf[11];
oob_buf[13] = (oob_buf[7] & 0x3f)
| (oob_buf[5] == 'Y' ? 0 : 0x80)
| (oob_buf[4] == 0 ? 0 : 0x40);
oob_buf[12] = oob_buf[6];
oob_buf[11] = oob_buf[3];
oob_buf[10] = oob_buf[2];
oob_buf[9] = oob_buf[1];
oob_buf[8] = oob_buf[0];
memset(oob_buf, 0xff, 8);
#else
/* set the ECC bytes to 0xff so MTD will
calculate it */
int i;
for (i = 0; i < meminfo->oobinfo.eccbytes; i++)
oob_buf[meminfo->oobinfo.eccpos[i]] = 0xff;
#endif
}
/* write OOB data first, as ecc will be placed
* in there*/
result = meminfo->write_oob(meminfo,
mtdoffset,
修改include/command.h文件,添加:
define ENABLE_CMD_NAND_YAFFS 1
define ENABLE_CMD_NAND_YAFFS_SKIPFB 1
define CFG_NAND_YAFFS1_NEW_OOB_LAYOUT 0
解决目标板的一个BUG:
将board/atmel/at91sam9g20ek/at91sam9g20ek.c文件的159行屏蔽:
//at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_EXTRST);
4. 编译U-boot生成BIN文件
在提示符下输入以下命令:
/opt/u-boot-1.3.4# make distclean
/opt/u-boot-1.3.4# make ARCH=arm at91sam9g20ek_nandflash_config
/opt/u-boot-1.3.4# make ARCH=arm CROSS_COMPILE=arm-linux-
如图2所示:
图 2
在U-boot的根目录下,可以看到刚刚出生的u-boot.bin文件。
下载U-boot到目标板
打开SAM-BA程序,按照图3所示的步骤,将u-boot.bin文件烧写到NANDFLASH当中。
图 3