在linux中配置编译u-boot方法,U-Boot的配置、编译、连接过程

10 #include 11

12 DECLARE_GLOBAL_DATA_PTR;

13

14 #define S3C2410_NFSTAT_READY (1<<0)

15 #define S3C2410_NFCONF_nFCE (1<<11)

16

17 #define S3C2440_NFSTAT_READY (1<<0)

18 #define S3C2440_NFCONT_nFCE (1<<1)

19

20

21 /* S3C2410:NAND Flash的片选函数 */

22 static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)

23 {

24 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

25

26 if (chip == -1) {

27 s3c2410nand->NFCONF |= S3C2410_NFCONF_nFCE;/* 禁止片选信号 */

28 } else {

29 s3c2410nand->NFCONF &= ~S3C2410_NFCONF_nFCE;/* 使能片选信号 */

30 }

31 }

32

33 /* S3C2410:命令和控制函数

34 *

35 * 注意,这个函数仅仅根据各种命令来修改“写地址”IO_ADDR_W 的值(这称为tglx方法),

36 * 这种方法使得平台/开发板相关的代码很简单。

37 * 真正发出命令是在上一层NAND Flash的统一的驱动中实现,

38 * 它首先调用这个函数修改“写地址”,然后才分别发出控制、地址、数据序列。

39 */

40 static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)

41 {

42 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

43 struct nand_chip *chip = mtd->priv;

44

45 switch (cmd) {

46 case NAND_CTL_SETNCE:

47 case NAND_CTL_CLRNCE:

48 printf("%s: called for NCE\n", __FUNCTION__);

49 break;

50

51 case NAND_CTL_SETCLE:

52 chip->IO_ADDR_W = (void *)&s3c2410nand->NFCMD;

53 break;

54

55 case NAND_CTL_SETALE:

56 chip->IO_ADDR_W = (void *)&s3c2410nand->NFADDR;

57 break;

58

59 /* NAND_CTL_CLRCLE: */

60 /* NAND_CTL_CLRALE: */

61 default:

62 chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;

63 break;

64 }

65 }

66

67 /* S3C2410:查询NAND Flash状态

68 *

69 * 返回值:0 – 忙, 1 – 就绪

70 */

71 static int s3c2410_nand_devready(struct mtd_info *mtd)

72 {

73 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

74

75 return (s3c2410nand->NFSTAT & S3C2410_NFSTAT_READY);

76 }

77

78

79 /* S3C2440:NAND Flash的片选函数 */

80 static void s3c2440_nand_select_chip(struct mtd_info *mtd, int chip)

81 {

82 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

83

84 if (chip == -1) {

85 s3c2440nand->NFCONT |= S3C2440_NFCONT_nFCE;/* 禁止片选信号 */

86 } else {

87 s3c2440nand->NFCONT &= ~S3C2440_NFCONT_nFCE;/* 使能片选信号 */

88 }

89 }

90

91 /* S3C2440:命令和控制函数,与s3c2410_nand_hwcontrol函数类似 */

92 static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)

93 {

94 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

95 struct nand_chip *chip = mtd->priv;

96

97 switch (cmd) {

98 case NAND_CTL_SETNCE:

99 case NAND_CTL_CLRNCE:

100 printf("%s: called for NCE\n", __FUNCTION__);

101 break;

102

103 case NAND_CTL_SETCLE:

104 chip->IO_ADDR_W = (void *)&s3c2440nand->NFCMD;

105 break;

106

107 case NAND_CTL_SETALE:

108 chip->IO_ADDR_W = (void *)&s3c2440nand->NFADDR;

109 break;

110

111 /* NAND_CTL_CLRCLE: */

112 /* NAND_CTL_CLRALE: */

113 default:

114 chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;

115 break;

116 }

117 }

118

119 /* S3C2440:查询NAND Flash状态

120 *

121 * 返回值:0 – 忙, 1 – 就绪

122 */

123 static int s3c2440_nand_devready(struct mtd_info *mtd)

124 {

125 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

126

127 return (s3c2440nand->NFSTAT & S3C2440_NFSTAT_READY);

128 }

129

130 /*

131 * Nand flash硬件初始化:

132 * 设置NAND Flash的时序, 使能NAND Flash控制器

133 */

134 static void s3c24x0_nand_inithw(void)

135 {

136 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

137 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

138

139 #define TACLS 0

140 #define TWRPH0 4

141 #define TWRPH1 2

142

143 if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410)

144 {

145 /* 使能NAND Flash控制器,初始化ECC,使能片选信号,设置时序 */

146 s3c2410nand->NFCONF = (1<<15)|(1<<12)|(1<<11)|(TACLS<<8)|(TWRPH0<<4)|(TWRPH1<<0);

147 }

148 else

149 {

150 /* 设置时序 */

151 s3c2440nand->NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);

152 /* 初始化ECC,使能NAND Flash控制器,使能片选信号 */

153 s3c2440nand->NFCONT = (1<<4)|(0<<1)|(1<<0);

154 }

155 }

156

157 /*

158 * 被drivers/nand/nand.c调用, 初始化NAND Flash硬件,初始化访问接口函数

159 */

160 void board_nand_init(struct nand_chip *chip)

161 {

162 S3C2410_NAND * const s3c2410nand = S3C2410_GetBase_NAND();

163 S3C2440_NAND * const s3c2440nand = S3C2440_GetBase_NAND();

164

165 s3c24x0_nand_inithw();/* Nand flash硬件初始化 */

166

167 if (gd->bd->bi_arch_number == MACH_TYPE_SMDK2410) {

168 chip->IO_ADDR_R = (void *)&s3c2410nand->NFDATA;

169 chip->IO_ADDR_W = (void *)&s3c2410nand->NFDATA;

170 chip->hwcontrol = s3c2410_nand_hwcontrol;

171 chip->dev_ready = s3c2410_nand_devready;

172 chip->select_chip = s3c2410_nand_select_chip;

173 chip->options = 0;/* 设置位宽等,位宽为8 */

174 } else {

175 chip->IO_ADDR_R = (void *)&s3c2440nand->NFDATA;

176 chip->IO_ADDR_W = (void *)&s3c2440nand->NFDATA;

177 chip->hwcontrol = s3c2440_nand_hwcontrol;

178 chip->dev_ready = s3c2440_nand_devready;

179 chip->select_chip = s3c2440_nand_select_chip;

180 chip->options = 0;/* 设置位宽等,位宽为8 */

181 }

182

183 chip->eccmode = NAND_ECC_SOFT;/* ECC较验方式:软件ECC */

184 }

185

186 #endif

文件中分别针对S3C2410、S3C2440实现了NAND Flash最底层访问函数,并进行了一些硬件的设置(比如时序、使能NAND Flash控制器等)。新的代码对NAND Flash的封装做得很好,只要向上提供底层初始化函数board_nand_init来设置好平台/开发板相关的初始化、提供底层接口即可。

最后,只要将新建的nand_flash.c文件编入U-Boot中就可以擦除、读写NAND Flash了。如下修改cpu/arm920t/s3c24x0/Makefile文件即可:

COBJS = i2c.o interrupts.o serial.o speed.o \

usb_ohci.o

改为:

COBJS = i2c.o interrupts.o serial.o speed.o \

usb_ohci.o nand_flash.o

现在,可以使用新编译的u-boot.bin烧写内核映像到NAND Flash去了,请参考15.2.6。

[编辑] 5. 支持烧写yaffs文件系统映像

在实际生产中,可以通过烧片器等手段将内核、文件系统映像烧入固态存储设备中,Bootloader不需要具备烧写功能。但为了方便开发,通常在Bootloader中增加烧写内核、文件系统映像文件的功能。

增加了NAND Flash功能的U-Boot 1.1.6已经可以通过“nand write ……”、“nand write.jffs2 ……”等命令来烧写内核,cramfs、jffs2文件系统映像文件。但是在NAND Flash上,yaffs文件系统的性能更佳,下面增加“nand write.yaffs ……”命令以烧写yaffs文件系统映像文件。

“nand write.yaffs ……”字样的命令中,“nand”是具体命令,“write.yaffs ……”是参数。nand命令在common/cmd_nand.c中实现:

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 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命令的处理函数do_nand中增加对“write.yaffs ……”的支持。do_nand函数仍在common/cmd_nand.c中实现,代码修改如下:

331 (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) {

……

354 }else if ( s != NULL && !strcmp(s, ".yaffs")){

355 if (read) {

356 /* read */

357 nand_read_options_t opts;

358 memset(&opts, 0, sizeof(opts));

359 opts.buffer = (u_char*) addr;

360 opts.length = size;

361 opts.offset = off;

362 opts.readoob = 1;

363 opts.quiet = quiet;

364 ret = nand_read_opts(nand, &opts);

365 } else {

366 /* write */

367 nand_write_options_t opts;

368 memset(&opts, 0, sizeof(opts));

369 opts.buffer = (u_char*) addr;/* yaffs文件系统映像存放的地址 */

370 opts.length = size;/* 长度 */

371 opts.offset = off;/* 要烧写到的NAND Flash的偏移地址 */

372 /* opts.forceyaffs = 1; *//* 计算ECC码的方法,没有使用 */

373 opts.noecc = 1; /* 不需要计算ECC,yaffs映像中有OOB数据 */

374 opts.writeoob = 1;/* 写OOB区 */

375 opts.blockalign = 1;/* 每个“逻辑上的块”大小为1个“物理块” */

376 opts.quiet = quiet;/* 是否打印提示信息 */

377 opts.skipfirstblk = 1;/* 跳过第一个可用块 */

378 ret = nand_write_opts(nand, &opts);

379 }

380 } else {

……

385 }

386

第354~379行就是针对命令“nand read.yaffs ……”、“nand write.yaffs ……”增加的代码。有兴趣的读者可以自己分析“if (read)”分支的代码,下面只讲解“else”分支,即“nand write.yaffs ……”命令的实现。

NAND Flash每一页大小为(512+16)字节(还有其他格式的NAND Flash,比如每页大小为(256+8)、(2048+64)等),其中的512字节就是一般存储数据的区域,16字节称为OOB(Out Of Band)区。通常在OOB区存放坏块标记、前面512字节的ECC较验码等。

cramfs、jffs2文件系统映像文件中并没有OOB区的内容,如果将它们烧入NOR Flash中,则是简单的“平铺”关系;如果将它们烧入NAND Flash中,则NAND Flash的驱动程序首先根据OOB的标记略过坏块,然后将一页数据(512字节)写入后,还会计算这512字节的ECC较验码,最后将它写入OOB区,如此循环。cramfs、jffs2文件系统映像文件的大小通常是512的整数倍。

而yaffs文件系统映像文件的格式则跟它们不同,文件本身就包含了OOB区的数据(里面有坏块标记、ECC较验码、其他yaffs相关的信息)。所以烧写时,不需要再计算ECC值,首先检查是否坏块(是则跳过),然后写入512字节的数据,最后写入16字节的OOB数据,如此循环。yaffs文件系统映像文件的大小是(512+16)的整数倍。

注意:烧写yaffs文件系统映像时,分区上第一个可用的(不是坏块)块也要跳过。

下面分析上面的代码。

第369~371行设置源地址、目的地址、长度。烧写yaffs文件系统映像前,一般通过网络将它下载到内存某个地址处(比如 0x30000000),然后通过类似“nand write.yaffs 0x30000000 0x00A00000 $(filesize)”的命令烧到NAND Flash的偏移地址0x00A00000处。对于这个命令,第369行中opts.buffer等于0x30000000,第370行中 opts.length等于$(filesize)的值,就是前面下载的文件的大小,第371行中的opts.offset等于0x00A00000。

这里列出不使用的第372行,是因为opts.forceyaffs这个名字很有欺骗性,它其实是指计算ECC较验码的一种方法。烧写yaffs文件系统映像时,不需要计算ECC较验码。

第373、374行指定烧写数据时不计算ECC较验码、而是烧入文件中的OOB数据。

第375行指定“逻辑块”的大小,“逻辑块”可以由多个“物理块”组成,在yaffs文件系统映像中,它们是1:1的关系。

第377行的opts.skipfirstblk是新加的项,nand_write_options_t结构中没有skipfirstblk成员。它表示烧写时跳过第一个可用的逻辑块──这是由yaffs文件系统的特性决定的。

既然skipfirstblk是在nand_write_options_t结构中新加的项,那么就要重新定义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; /* 新加,烧写时跳过第一个可用的逻辑块 */

};

typedef struct nand_write_options nand_write_options_t;

然后,修改nand_write_opts函数增加对skipfirstblk成员的支持。它在drivers/nand/nand_util.c文件中,下面的第301、第430~435行是新加的:

285 int nand_write_opts(nand_info_t *meminfo, const nand_write_options_t *opts)

286 {

……

300 int result;

301 int skipfirstblk = opts->skipfirstblk;

……

430 /* skip the first good block when wirte yaffs image, by */

431 if (skipfirstblk) {

432 mtdoffset += erasesize_blockalign;

433 skipfirstblk = 0;

434 continue;

435 }

……

进行了上面的移植后,U-Boot已经可以烧yaffs文件系统映像了。由于前面设置“opts.noecc = 1”不使用ECC较验码,在烧写过程中会出现很多的提示信息:

Writing data without ECC to NAND-FLASH is not recommended

可以修改drivers/nand/nand_base.c文件的nand_write_page函数将它去掉:

917 case NAND_ECC_NONE:

918 printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");

改为:

917 case NAND_ECC_NONE:

918 //printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n");

[编辑] 6. 修改默认配置参数以方便使用

前面移植网卡芯片CS8900时,已经设置过默认IP地址等。为了使用U-Boot时减少一些设置,现在修改配置文件include/configs/100ask24x0.h增加默认配置参数,其中一些在移植过程中已经增加的选项这里也再次说明。

(1)Linux启动参数。

增加如下3个宏:

#define CONFIG_SETUP_MEMORY_TAGS 1/* 向内核传递内存分布信息 */

#define CONFIG_CMDLINE_TAG 1/* 向内核传递命令行参数 */

/* 默认命令行参数 */

#define CONFIG_BOOTARGS "noinitrd root="/dev/mtdblock2" init="/linuxrc" console="ttySAC0""

(2)自动启动命令。

增加如下2个宏:

/* 自动启动前延时3秒 */

#define CONFIG_BOOTDELAY3

/* 自动启动的命令 */

#define CONFIG_BOOTCOMMAND “nboot 0x32000000 0 0; bootm 0x32000000”

自动启动时(开机3秒内无输入),首先执行“nboot 0x32000000 0 0”命令将第0个NAND Flash偏移地址0上的映像文件复制到内存0x32000000中;然后执行“bootm 0x32000000”命令启动内存中的映像。

(3)默认网络设置。

根据具体网络环境增加、修改下面4个宏:

#define CONFIG_ETHADDR08:00:3e:26:0a:5b

#define CONFIG_NETMASK 255.255.255.0

#define CONFIG_IPADDR192.168.1.17

#define CONFIG_SERVERIP192.168.1.11

[编辑] 15.2.6 U-Boot的常用命令

[编辑] 1. U-Boot的常用命令的用法

进入U-Boot控制界面后,可以运行各种命令,比如下载文件到内存,擦除、读写Flash,运行内存、NOR Flash、NAND Flash中的程序,查看、修改、比较内存中的数据等。

使用各种命令时,可以使用其开头的若干个字母代替它。比如tftpboot命令,可以使用t、tf、tft、tftp等字母代替,只要其他命令不以这些字母开头即可。

当运行一个命令之后,如果它是可重复执行的(代码中使用U_BOOT_CMD定义这个命令时,第3个参数是1),若想再次运行可以直接输入回车。

U-Boot接受的数据都是16进制,输入时可以省略前缀0x、0X。

下面介绍常用的命令:

(1)帮助命令help。

运行help命令可以看到U-Boot中所有命令的作用,如果要查看某个命令的使用方法,运行“help 命令名”,比如“help bootm”。

可以使用“?”来代替“help”,比如直接输入“?”、“? bootm”。

(2)下载命令。

U-Boot支持串口下载、网络下载,相关命令有:loadb、loads、loadx、loady和tftpboot、nfs。

前几个串口下载命令使用方法相似,以loadx命令为例,它的用法为“loadx [ off ] [ baud ]”。中括号“[]”表示里面的参数可以省略,off表示文件下载后存放的内存地址,baud表示使用的波特率。如果baud参数省略,则使用当前的波特率;如果off参数省略,存放的地址为配置文件中定义的宏CFG_LOAD_ADDR。

tftpboot命令使用TFTP协议从服务器下载文件,服务器的IP地址为环境变量serverip。用法为“tftpboot [loadAddress] [bootfilename]”,loadAddress表示文件下载后存放的内存地址,bootfilename表示要下载的文件的名称。如果 loadAddress省略,存放的地址为配置文件中定义的宏CFG_LOAD_ADDR;如果bootfilename省略,则使用单板的IP地址构造一个文件名,比如单板IP为192.168.1.17,则缺省的文件名为C0A80711.img。

nfs命令使用NFS协议下载文件,用法为“nfs [loadAddress] [host ip addr:bootfilename]”。loadAddress、bootfilename的意义与tftpboot命令一样,host ip addr表示服务器的IP地址,默认为环境变量serverip。

下载文件成功后,U-Boot会自动创建或更新环境变量filesize,它表示下载的文件的长度,可以在后续命令中使用“$(filesize)”来引用它。

(3)内存操作命令。

常用的命令有:查看内存命令md、修改内存命令md、填充内存命令mw、拷贝命令cp。这些命令都可以带上后缀“.b”、“.w”或“.l”,表示以字节、字(2个字节)、双字(4个字节)为单位进行操作。比如“cp.l 30000000 31000000 2”将从开始地址0x30000000处,拷贝2个双字到开始地址为0x31000000的地方。

md命令用法为“md[.b, .w, .l] address [count]”,表示以字节、字或双字(默认为双字)为单位,显示从地址address开始的内存数据,显示的数据个数为count。

mm命令用法为“mm[.b, .w, .l] address”,表示以字节、字或双字(默认为双字)为单位,从地址address开始修改内存数据。执行mm命令后,输入新数据后回车,地址会自动增加,Ctrl+C退出。

mw命令用法为“mw[.b, .w, .l] address value [count]”,表示以字节、字或双字(默认为双字)为单位,往开始地址为address的内存中填充count个数据,数据值为value。

cp命令用法为“cp[.b, .w, .l] source target count”,表示以字节、字或双字(默认为双字)为单位,从源地址source的内存拷贝count个数据到目的地址的内存。

(4)NOR Flash操作命令。

常用的命令有查看Flash信息的flinfo命令、加/解写保护命令protect、擦除命令erase。由于NOR Flash的接口与一般内存相似,所以一些内存命令可以在NOR Flash上使用,比如读NOR Flash时可以使用md、cp命令,写NOR Flash时可以使用cp命令(cp根据地址分辨出是NOR Flash,从而调用NOR Flash驱动完成写操作)。

直接运行“flinfo”即可看到NOR Flash的信息,有NOR Flash的型号、容量、各扇区的开始地址、是否只读等信息。比如对于本书基于的开发板,flinfo命令的结果如下:

Bank # 1: AMD: 1x Amd29LV800BB (8Mbit)

Size: 1 MB in 19 Sectors

Sector Start Addresses:

00000000 (RO) 00004000 (RO) 00006000 (RO) 00008000 (RO) 00010000 (RO)

00020000 (RO) 00030000 00040000 00050000 00060000

00070000 00080000 00090000 000A0000 000B0000

000C0000 000D0000 000E0000 000F0000 (RO)

其中的RO表示该扇区处于写保护状态,只读。

对于只读的扇区,在擦除、烧写它之前,要先解除写保护。最简单的命令为“protect off all”,解除所有NOR Flash的写保护。

erase命令常用的格式为“erase start end”──擦除的地址范围为start至end、“erase start +len”──擦除的地址范围为start至(start + len – 1),“erase all”──表示擦除所有NOR Flash。

注意:其中的地址范围,刚好是一个扇区的开始地址到另一个(或同一个)扇区的结束地址。比如要擦除Amd29LV800BB的前5个扇区,执行的命令为“erase 0 0x2ffff”,而非“erase 0 0x30000”。

(5)NAND Flash操作命令。

NAND Flash操作命令只有一个:nand,它根据不同的参数进行不同操作,比如擦除、读取、烧写等。

“nand info”查看NAND Flash信息。

“nand erase [clean] [off size]”擦除NAND Flash。加上“clean”时,表示在每个块的第一个扇区的OOB区加写入清除标记;off、size表示要擦除的开始偏移地址和长度,如果省略 off和size,表示要擦除整个NAND Flash。

“nand read[.jffs2] addr off size”从NAND Flash偏移地址off处读出size个字节的数据,存放到开始地址为addr的内存中。是否加后缀“.jffs”的差别只是读操作时的ECC较验方法不同。

“nand write[.jffs2] addr off size”把开始地址为addr的内存中的size个字节数据,写到NAND Flash的偏移地址off处。是否加后缀“.jffs”的差别只是写操作时的ECC较验方法不同。

“nand read.yaffs addr off size”从NAND Flash偏移地址off处读出size个字节的数据(包括OOB区域),存放到开始地址为addr的内存中。

“nand write.yaffs addr off size”把开始地址为addr的内存中的size个字节数据(其中有要写入OOB区域的数据),写到NAND Flash的偏移地址off处。

“nand dump off”,将NAND Flash偏移地址off的一个扇区的数据打印出来,包括OOB数据。

(6)环境变量命令。

“printenv”命令打印全部环境变量,“printenv name1 name2 ...”打印名字为name1、name2、……”的环境变量。

“setenv name value”设置名字为name的环境变量的值为value。

“setenv name”删除名字为name的环境变量。

上面的设置、删除操作只是在内存中进行,“saveenv”将更改后的所有环境变量写入NOR Flash中。

(7)启动命令。

不带参数的“boot”、“bootm”命令都是执行环境变量bootcmd所指定的命令。

“bootm [addr [arg ...]]”命令启动存放在地址addr处的U-Boot格式的映像文件(使用U-Boot目录tools下的mkimage工具制作得到),[arg ...]表示参数。如果addr参数省略,映像文件所在地址为配置文件中定义的宏CFG_LOAD_ADDR。

“go addr [arg ...]”与bootm命令类似,启动存放在地址addr处的二进制文件, [arg ...]表示参数。

“nboot [[[loadAddr] dev] offset]”命令将NAND Flash设备dev上偏移地址off处的映像文件复制到内存loadAddr处,然后,如果环境变量autostart的值为“yes”,就启动这个映像。如果loadAddr参数省略,存放地址为配置文件中定义的宏CFG_LOAD_ADDR;如果dev参数省略,则它的取值为环境变量 bootdevice的值;如果offset参数省略,则默认为0。

[编辑] 2. U-Boot命令使用实例

下面通过一个例子来演示如何使用各种命令烧写内核映像文件、yaffs映像文件,并启动系统。

(1)制作内核映像文件。

对于本书使用的Linux 2.6.22.6版本,编译内核时可以直接生成U-Boot格式的映像文件uImage。

对于不能直接生成uImage的内核,制作方法在U-Boot根目录下的README文件中有说明,假设已经编译好的内核文件为vmlinux,它是ELF格式的。mkimage是U-Boot目录tools下的工具,它在编译U-Boot时自动生成。执行以下3个命令将内核文件vmlinux制作为U-Boot格式的映像文件uImage,它们首先将vmlinux转换为二进制格式,然后压缩,最后构造头部信息(里面包含有文件名称、大小、类型、 CRC较验码等):

① arm-linux-objcopy -O binary -R .note -R .comment -S vmlinux linux.bin

② gzip -9 linux.bin

③ mkimage -A arm -O linux -T kernel -C gzip -a 0x30008000 -e 0x30008000 -n "Linux Kernel Image" -d linux.bin.gz uImage

(2)烧写内核映像文件uImage。

首先将uImage放在主机上的tftp或nfs目录下,确保已经开启tftp或nfs服务。

然后运行如下命令下载文件,擦除、烧写NAND Flash:

① tftp 0x30000000 uImage 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/uImage

② nand erase 0x0 0x00200000

③ nand write.jffs2 0x30000000 0x0 $(filesize)

第3条命令之所以使用“nand write.jffs2”而不是“nand write”,是因为前者不要求文件的长度是页对齐的(512字节对齐)。也可以使用“nand write”,但是需要将命令中的长度参数改为$(filesize)向上进行512取整后的值。比如uImage的大小为1540883,向上进行 512取整后为1541120(即0x178400),可以使用命令“nand write 0x30000000 0x0 0x178400”进行烧写。

(3)烧写yaffs文件系统映像。

假设yaffs文件系统映像的文件名为yaffs.img,首先将它放在主机上的tftp或nfs目录下,确保已经开启tftp或nfs服务;然后执行如下命令下载、擦除、烧写:

① tftp 0x30000000 yaffs.img 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/yaffs.img

② nand erase 0xA00000 0x3600000

③ nand write.yaffs 0x30000000 0xA00000 $(filesize)

这时,重启系统,在U-Boot倒数3秒之后,就会自动启动Linux系统。

(4)烧写jffs2文件系统映像。

假设jffs2文件系统映像的文件名为jffs2.img,首先将它放在主机上的tftp或nfs目录下,确保已经开启tftp或nfs服务;然后执行如下命令下载、擦除、烧写:

① tftp 0x30000000 jffs2.img 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/jffs2.img

② nand erase 0x200000 0x800000

③ nand write.jffs2 0x30000000 0x200000 $(filesize)

系统启动后,就可以使用“mount -t jffs2 /dev/mtdblock1 /mnt”挂接jffs2文件系统。

[编辑] 15.2.7 使用U-Boot来执行程序

在前面的硬件实验中使用JTAG烧写程序到NAND Flash,烧写过程十分缓慢。如果使用U-Boot来烧写NAND Flash,效率会高很多。烧写二进制文件到NAND Flash中所使用的命令与上面烧写内核映像文件uImage的过程类似,只是不需要将二进制文件制作成U-Boot格式。

另外,可以将程序下载到内存中,然后使用go命令执行它。假设有一个程序的二进制可执行文件test.bin,连接地址为0x30000000。首先将它放在主机上的tftp或nfs目录下,确保已经开启tftp或nfs服务;然后将它下载到内存0x30000000处,最后使用go命令执行它:

① tftp 0x30000000 test.bin 或 nfs 0x30000000 192.168.1.57:/work/nfs_root/test.bin

② go 0x30000000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值