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

来源:互联网 发布:插屏广告过滤软件 编辑:程序博客网 时间:2024/05/25 08:15

在制作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};   //输入文件缓冲区,由于最大的输入文件是第二阶段bootloarder,因此限制为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{  //若没有输入写第几阶段bootloader,则当输入文件小于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

cat <<EOT | sfdisk  -uM  /dev/sdc

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正常驱动....

工具做好啦,工欲善其事,必先利其器-----就是这道理

原创粉丝点击