CubieBoard中文论坛

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

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

[复制链接]
发表于 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正常驱动....
工具做好啦,工欲善其事,必先利其器-----就是这道理

本帖子中包含更多资源

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

x
回复

使用道具 举报

发表于 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,就行了
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-3-23 10:55:31 | 显示全部楼层
Earthman 发表于 2013-3-9 03:37
脚本版保存文件为write_uboot,添加可执行权限,当然必须在u-boot-sunxi-sunxi,即是编译根文件夹下
我的sd ...

这个太好啦,我不会写脚本,只会C.....憋了好久才写出来的
这个短小精湛,很好
回复 支持 反对

使用道具 举报

发表于 2013-5-30 20:47:34 | 显示全部楼层
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-30 21:33:57 | 显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

试过,不能从SD启动,我也不知道用来做什么的,使用sunxi-spl.bin吧
回复 支持 反对

使用道具 举报

 楼主| 发表于 2013-5-30 21:35:04 | 显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

试过,不能从SD启动,我也不知道用来做什么的,使用sunxi-spl.bin吧
回复 支持 反对

使用道具 举报

发表于 2015-7-20 22:30:37 | 显示全部楼层
感謝樓主分享
回复 支持 反对

使用道具 举报

发表于 2015-10-13 12:38:51 | 显示全部楼层
sun_richard 发表于 2013-5-30 20:47
楼主还知道u-boot-spl.bin 这个.bin是干什么用的?

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

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|粤ICP备13051116号|cubie.cc---深刻的嵌入式技术讨论社区

GMT+8, 2024-4-20 04:38 , Processed in 0.026329 second(s), 16 queries .

Powered by Discuz! X3.4

© 2001-2012 Comsenz Inc. | Style by Coxxs

返回顶部