CubieBoard博客-HomeCubieTech公司网站

cubie.cc CubieBoard中文论坛

 找回密码
 立即注册
搜索
热搜: unable
查看: 9508|回复: 8

U-boot的SD启动卡写入工具

[复制链接]

11

主题

2

好友

1162

积分

金牌会员

Rank: 6Rank: 6

贡献
195
金钱
513
威望
195
买家信用
卖家信用
积分
1162
发表于 2013-1-28 22:01:59 |显示全部楼层
本帖最后由 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正常驱动....
工具做好啦,工欲善其事,必先利其器-----就是这道理

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

代码之前,众生平等
回复

使用道具 举报

8

主题

0

好友

1705

积分

金牌会员

Rank: 6Rank: 6

贡献
316
金钱
681
威望
316
买家信用
卖家信用
积分
1705
发表于 2013-3-9 03:37:38 |显示全部楼层
本帖最后由 Earthman 于 2013-3-9 03:40 编辑

脚本版
  1. #!/bin/sh

  2. device=null

  3. test -b /dev/$1 && device=$1 || (echo Error && exit)

  4. echo

  5. echo write u-boot to /dev/$device : Y/N

  6. echo

  7. read yesno

  8. (test $yesno = y || test $yesno = Y ) && \

  9. dd if=/dev/zero of=/dev/$device bs=1M count=1 && \

  10. dd if=spl/sunxi-spl.bin of=/dev/$device bs=1024 seek=8 && \

  11. dd if=u-boot.bin of=/dev/$device bs=1024 seek=32 && \

  12. echo Success!
复制代码
保存文件为write_uboot,添加可执行权限,当然必须在u-boot-sunxi-sunxi,即是编译根文件夹下
我的sd卡是/dev/sdc,所以敲 sudo ./write_uboot sdc,然后会要求确认,按y,就行了
回复

使用道具 举报

11

主题

2

好友

1162

积分

金牌会员

Rank: 6Rank: 6

贡献
195
金钱
513
威望
195
买家信用
卖家信用
积分
1162
发表于 2013-3-23 10:55:31 |显示全部楼层
Earthman 发表于 2013-3-9 03:37
脚本版保存文件为write_uboot,添加可执行权限,当然必须在u-boot-sunxi-sunxi,即是编译根文件夹下
我的sd ...

这个太好啦,我不会写脚本,只会C.....憋了好久才写出来的
这个短小精湛,很好
代码之前,众生平等
回复

使用道具 举报

2

主题

0

好友

561

积分

高级会员

Rank: 4

贡献
113
金钱
206
威望
113
买家信用
卖家信用
积分
561
发表于 2013-5-30 20:47:34 |显示全部楼层
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?
回复

使用道具 举报

11

主题

2

好友

1162

积分

金牌会员

Rank: 6Rank: 6

贡献
195
金钱
513
威望
195
买家信用
卖家信用
积分
1162
发表于 2013-5-30 21:33:57 |显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

试过,不能从SD启动,我也不知道用来做什么的,使用sunxi-spl.bin吧
代码之前,众生平等
回复

使用道具 举报

11

主题

2

好友

1162

积分

金牌会员

Rank: 6Rank: 6

贡献
195
金钱
513
威望
195
买家信用
卖家信用
积分
1162
发表于 2013-5-30 21:35:04 |显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

试过,不能从SD启动,我也不知道用来做什么的,使用sunxi-spl.bin吧
代码之前,众生平等
回复

使用道具 举报

0

主题

0

好友

3171

积分

论坛元老

Rank: 8Rank: 8

贡献
583
金钱
1420
威望
583
买家信用
卖家信用
积分
3171
发表于 2015-7-20 22:30:37 |显示全部楼层
感謝樓主分享
回复

使用道具 举报

1

主题

0

好友

1万

积分

论坛元老

Rank: 8Rank: 8

贡献
2430
金钱
6024
威望
2430
买家信用
卖家信用
积分
13323
发表于 2015-10-13 12:38:51 |显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

u-boot-spl.bin 應該是boot0,是要為了將Boot1載入的小程式。
回复

使用道具 举报

9#
无效楼层,该帖已经被删除
您需要登录后才可以回帖 登录 | 立即注册

QQ|Archiver|手机版|邮件群发|cubie.cc---深刻的嵌入式技术和应用讨论中文社区 ( 粤ICP备13051116号-1  

GMT+8, 2019-9-18 17:00 , Processed in 0.024456 second(s), 15 queries , Apc On.

Powered by Discuz! X2.5

© 2001-2012 Comsenz Inc. | Style by Coxxs

回顶部