本帖最后由 andy 于 2013-1-28 22:06 编辑
原文在我博客:http://blog.csdn.net/andy_wsj/article/details/8550247
在制作U-boot的SD启动卡时,由于每次编译完都要输一串命令写入.bin文件,为了方便行事,故写了一个小工具,专为写U-boot使用
该工具只适用于Cubieboard,若要用于其他开发板,请自行修改代码
源代码:
开发环境:RHEL5
开发工具:VIM
编译器 : GCC-----版本没注意看,应该2.6内核以上使用的GCC都可以吧
代码+说明:
#define _LARGEFILE64_SOURCE
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#define STAGE1_OFFSET (8 * 1024) //Cubieboard在启动时,第一阶段bootloader在SD卡8K位置开始
#define STAGE2_OFFSET (32 * 1024) //Cubieboard在启动时,第二阶段bootloader在SD卡32K位置开始
#define STAGE1_SIZE_LIMIT (24 * 1024) //由上面可知,第一阶段的长度限制在8K到32K之间,因此是24K
#define STAGE2_SIZE_LIMIT (992 * 1024) //由上面可知,第二阶段的长度限制在32K到1M之间,因此是992K
#define STAGE1_FLAG 0 //写第一阶段标志
#define STAGE2_FLAG 1 //写第二阶段标志
#define UNDEFINE_FLAG 2 //用户没有输入写第几段时,未定义标志
int main(int argc, char *argv[])
{
unsigned int file_size; //写入文件的size
off64_t sd_size; //SD卡的size
int flag = STAGE1_FLAG; //写入标志
int temp = 0;
int ret = -1;
int ifd; //输入文件描述符 ,编译好的U-boot文件
int ofd; //输出文件描述符,就是SD卡
char input_file[STAGE2_SIZE_LIMIT] = {0}; //输入文件缓冲区,由于最大的输入文件是第二阶段,因此限制为992K
if( (argc < 3) || (strncmp(argv[2], "/dev/", 5))){ //命令输入参数少于3个或者输出文件不是SD所在目录,提示用户操作
fprintf(stderr, "Usage: sd_write <Input file> <Output file>\n");
return -1;
}
ofd = open(argv[2], O_WRONLY | O_LARGEFILE); //打开SD卡所在的文件
if(ofd == -1){
perror(argv[2]);
goto err0;
}
ifd = open(argv[1], O_RDONLY); //打开输入文件,就是bootloader
if(ifd == -1){
perror(argv[1]);
goto err1;
}
if(argc == 4){ //如果用户输入了4个参数,则最后一个参数为1表示是第一阶段,为2是第二阶段,否则是未定义,
temp = atoi(argv[3]); //程序将自行决定写在什么位置
if( 1 == temp ){
flag = STAGE1_FLAG;
}
else if( 2 == temp ){
flag = STAGE2_FLAG;
}
else{
flag = UNDEFINE_FLAG;
}
}
else{ //如果输入参数不是4个,也是未定义,,程序将执行决定写在什么位置
flag = UNDEFINE_FLAG;
}
/*************************************************************************/
if((file_size = lseek(ifd, 0, SEEK_END)) == -1){ //获取输入文件长度
perror("lseek()");
goto err2;
}
if(file_size == 0){ // 输入文件为空,直接退出
fprintf(stderr, "Error: File size == 0\n");
goto err2;
}
if(lseek(ifd, 0, SEEK_SET) == -1){ //将文件偏移量移到开始位置,准备读取
perror("lseek()");
goto err2;
}
if( flag == STAGE1_FLAG ){ //输入文件长度不能超过设置好的限制值
if( file_size > STAGE1_SIZE_LIMIT ){
fprintf(stderr, "Error: File size > %uK.\n", STAGE1_SIZE_LIMIT / 1024);
goto err2;
}
}
else if( flag == STAGE2_FLAG ){
if( file_size > STAGE2_SIZE_LIMIT ){
fprintf(stderr, "Error: File size > %uK.\n", STAGE2_SIZE_LIMIT / 1024);
goto err2;
}
}
else{ //若没有输入写第几阶段,则当输入文件小于24K时写在8K开始的地方,大于24K小于992K时,写在32K开始的地方
if( file_size < STAGE1_SIZE_LIMIT ){
flag = STAGE1_FLAG;
}
else if( file_size < STAGE2_SIZE_LIMIT ){
flag = STAGE2_FLAG;
}
else{ //这是我刚加的,原来没写这里,有这句保险一点
fprintf(stderr, "Error: File size > %uK.\n", STAGE2_SIZE_LIMIT / 1024);
goto err2;
}
fprintf(stdout, "file_size = %uK flag = %u .\n", file_size /1024, flag);
}
if(read( ifd, input_file, file_size ) == -1){ // 读取整个输入文件
perror("read()");
goto err2;
}
/*************************************************************************/
if((sd_size = lseek64(ofd, 0, SEEK_END)) == -1){ //读取SD卡size
perror("lseek64()");
goto err2;
}
if( sd_size < 0x100000 ){ //如果SD卡小于1M,则不写
fprintf(stderr, "Error: SD card < 1M.\n");
goto err2;
}
//上面这里应该可以写的更好一点,可以将SD卡的分区表读出来,等写完了在写到U-boot后面,
//这样不需要对SD卡做命令处理就可以直接使用这个工具了
//不同的SD卡,2G、4G、8G.....分区表大小可能不同,因此还要考虑程序如何支持不同的SD卡....等等,有兴趣的同学可以试试
/*************************************************************************/
if(lseek64(ofd, 0, SEEK_SET) == -1){ //将SD卡文件偏移量复位,准备开始写
perror("lseek64()");
goto err2;
}
if(flag == STAGE1_FLAG){
if( lseek64(ofd, STAGE1_OFFSET, SEEK_SET) == -1){ //写第一阶段,将SD卡的文件偏移量移动到8K,从8K往后写
perror("lseek64()");
goto err2;
}
fprintf(stdout, "write in stage1, offset = %uK.\n", STAGE1_OFFSET / 1024);
}
else{
if(lseek64(ofd, STAGE2_OFFSET, SEEK_SET) == -1){ //写第二阶段,将SD卡的文件偏移量移动到32K,从32K往后写
perror("lseek64()");
goto err2;
}
fprintf(stdout, "write in stage2, offset = %uK.\n", STAGE2_OFFSET / 1024);
}
if(write(ofd, input_file, file_size) != file_size){ //U-boot写入SD卡
fprintf(stderr, "write failed.\n");
goto err2;
}
/*************************************************************************/
fsync(ofd); //写完收工,记得SD卡是外部慢速设备,同步一下,等同于shell的sync命令
printf(" Done.\n");
ret = 0;
err2:
close(ifd);
err1:
close(ofd);
err0:
return ret;
}
我机器上SD卡文件是/dev/sdc
SD卡处理,只需要处理一次,正确后以后就不用再输入这些啦
dd if=/dev/zero of=/dev/sdc bs=1M count=1 //将前面1M写0
cat <<EOT | sfdisk -uM /dev/sdc //剩下的作为一个分区,如果不行拔出SD卡再插入
2,,L //必须是大于1,表示从2M开始到SD结束作为一个区使用1时分区表会被弄丢了,
//弄丢了没关系,再用这几条命令在linux下可修复
EOT
拔出SD卡,再插入,继续处理,这时候SDka变成了/dev/sdc和/dev/sdc1
mkfs.vfat /dev/sdc1 //将余下的部分格式化,可以当U盘使用
编译SD卡工具:
gcc sd_write.c -o sd_write
mv sd_write /work/uu-boot-sunxi-sunxi/ 放到u-boot目录备用
效果演示: //以后可以就只用使用这个来写入
[root@localhost u-boot-sunxi-sunxi]# ./sd_write spl/sunxi-spl.bin /dev/sdc
file_size = 20K flag = 0 .
write in stage1, offset = 8K.
Done.
[root@localhost u-boot-sunxi-sunxi]# ./sd_write u-boot.bin /dev/sdc
file_size = 171K flag = 1 .
write in stage2, offset = 32K.
Done.
取出SD卡,先插入XP台式机试试,确认没问题可当U盘用,将SD卡插入Cubieboard,上电,minicom打印U-boot正常驱动....
工具做好啦,工欲善其事,必先利其器-----就是这道理
|