请选择 进入手机版 | 继续访问电脑版
查看: 2778|回复: 1

[分享] IMX6ULL开发板使用busybox构建根文件系统

[复制链接]
  • TA的每日心情
    开心
    2024-3-26 15:16
  • 签到天数: 266 天

    [LV.8]以坛为家I

    3298

    主题

    6545

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    31998
    最后登录
    2024-4-9
    发表于 2020-6-3 13:30:53 | 显示全部楼层 |阅读模式
    IMX6ULL开发板使用busybox构建根文件系统
    1. 为什么使用busybox?
    现在可以用于构建根文件系统的软件有很多,比如buildroot,yocto,而且这些软件构建的根文件系统软件更全,为什么要使用busybox呢,因为比较简单,对于我这种初学者来说,从简单开始学习才是最好的,可以了解原理,原理清楚了,再使用其他软件来构建就简单多了。
    2. 编译busybox构建根文件系统
    2.1 构建环境:
      1.gcc: 100ask_imx6ull-sdk\ToolChain\gcc-linaro-6.2.1-2016.11-x86_64_arm-linux- gnueabihf
      2.linux: linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
      3.主机系统: ubuntu18.04
    gcc可以在百问网提供的bsp包找到,busybox使用的版本是nxp官方的busybox-1.29.0.tar.bz2, 点击下载busybox-1.29.0.tar.bz2。
    2.2 配置编译busybox
    1.解压busybox-1.29.0.tar.bz2:
    1. tar -vxjf busybox-1.29.0.tar.bz2
    复制代码
    2.修改Makefile,添加编译器,打开busybox的根目录中的Makefile,将164行修改为:
    1. CROSS_COMPILE ?= /home/book/share/100ask_imx6ull-sdk/ToolChain/gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
    复制代码
    将路径修改为自己的交叉编译工具的绝对路径,将190行修改为:
    1. ARCH ?= arm
    复制代码
    3.配置busybox,busybox有三种配置选项:
    defconfig,默认配置
    allyesconfig,全选配置,使能busybox中的所有功能
    allnoconfig,最小配置
    使用默认配置,执行:
    1. make defconfig
    复制代码
    然后打开图形配置界面,执行:
    1. make menuconfig
    复制代码
    分别配置下面的路径:
    1. <p>
    2. </p><p>Location:</p><p>  -> Settings</p><p><span style="white-space:pre">        </span>-> Build static binary (no shared libs) //取消选中,动态编译,不然编译出来的根文件系统很大</p><p>Location:</p><p>  -> Settings</p><p><span style="white-space:pre">        </span>-> vi-style line editing commands  //选中</p><p>Location:</p><p>  -> Linux Module Utilities</p><p><span style="white-space:pre">        </span>-> Simplified modutils   //取消选中</p><p>Location:</p><p>  -> Linux System Utilities</p><p><span style="white-space:pre">        </span>-> mdev (16 kb) //确保下面的全部选中,默认都是选中的</p>
    复制代码
    4.配置完busybox就可以编译了,执行:
    1. make install CONFIG_PREFIX=/home/book/nfs_rootfs/blogrootfs
    复制代码
    CONFIG_PREFIX指定输出路径,指向nfs服务器的路径即可。编译完成后可以查看rootfs路径下的文件:
    1.png
    5.向根文件系统添加lib库
    在rootfs下创建lib文件夹,在usr下创建lib文件夹。
    进入交叉编译器存放的目录,将arm-linuxgnueabihf/libc/lib下的*so*和*.a拷贝到rootfs/lib下:
    1. cp *so* *.a ~/nfs_rootfs/blogrootfs/lib/ -d
    复制代码
    后面的“-d”表示拷贝符号链接。在rootfs中lib执行ls ld-linux-armhf.so.3 -l,可以看到ld-linux-armhf.so.3是一个软链接,所以需要重新复制一下。先删除rootfs/lib下的ld-linux-armhf.so.3,然后进入arm-linuxgnueabihf/libc/lib执行:

    1. cp ld-linux-armhf.so.3 ~/nfs_rootfs/blogrootfs/lib/
    复制代码
    再次查看rootfs/lib下的ld-linux-armhf.so.3,已经不是软链接了。
    进入交叉编译器存放的目录,将arm-linuxgnueabihf/lib下的*so*和*.a拷贝到rootfs/lib下:
    1. cp *so* *.a ~/nfs_rootfs/blogrootfs/lib/ -d
    复制代码
    进入交叉编译器存放的目录,将arm-linuxgnueabihf/libc/usr/lib下的*so*和*.a拷贝到rootfs/usr/lib下:
    1. cp *so* *.a ~/nfs_rootfs/blogrootfs/usr/lib/ -d
    复制代码
    可能会有警告,不用管。
    6.创建其它文件夹
    在rootfs根目录下创建文件夹:dev、 proc、 mnt、 sys、 tmp、root,创建完后如下图示:
    2.png
    7.测试根文件系统
    测试根文件系统一般都使用NFS,在内核启动时指定使用的nfs服务器以及路径,在uboot启动后,设置bootargs为:
    1. <p>setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rootwait rw nfsroot=192.168.101.5:/home/book/nfs_rootfs/rootfs ip=192.168.101.6:192.168.101.5:192.168.101.1:255.255.255.0::eth0:off'</p><p>/* root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>*/</p>
    复制代码
    设置好后保存环境变量,然后使用tftp加载内核和设备树并启动:
    1. <p>tftp 80800000 zImage</p><p>tftp 83000000 imx6ull-100ask-emmc.dtb</p><p>bootz 80800000 - 83000000</p>
    复制代码
    启动完成后如下图:
    3.png
    可以执行基本的命令了,但是提示没有/etc/init.d/rcS文件,所以需要完善一下文件系统。
    3. 完善根文件系统
    3.1 创建/etc/init.d/rcS文件
    linux启动后需要运行一些服务,而 /etc/init.d/rcS文件就是规定启动哪些服务,创建该文件并添加如下内容:
    1. <p>#!/bin/sh</p><p>
    2. </p><p>PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH</p><p>LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib</p><p>export PATH LD_LIBRARY_PATH</p><p>
    3. </p><p>mount -a</p><p>mkdir /dev/pts</p><p>mount -t devpts devpts /dev/pts</p><p>
    4. </p><p>echo /sbin/mdev > /proc/sys/kernel/hotplug #通过这两行,linux内核就可以在/dev目录下自动创建设备节点</p><p>mdev -s</p>
    复制代码
    将rcS添加可执行权限chmod 777 rcS。


    3.2 创建/etc/fstab文件
    fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区,创建该文件并添加如下内容:
    1. <p>#<file system> <mount point> <type> <options> <dump> <pass></p>
    复制代码
    3.3 创建/etc/inittab文件
    init 程序会读取/etc/inittab这个文件, inittab 由若干条指令组成,创建该文件并添加如下内容:
    1. <p>::sysinit:/etc/init.d/rcS</p>
    复制代码
    3.4 创建/etc/resolv.conf文件
    /etc/resolv.conf文件用于配置域名服务器,没有域名服务器就不能将网址转换成ip地址,创建该文件并添加如下内容:
    1. <p>nameserver 114.114.114.114</p>
    复制代码
    创建完以上三个文件后,重启linux,发现没有错误提示了。ping一下百度也可以ping通,网络也可以使用了,此时可以通过交叉编译器来编译可以在100ASK开发板上运行的linux程序了。


    4. 添加自己的开机log
    其实并没有修改内核在启动的时候显示的小企鹅,只是在linux启动完后,运行一个app,这个app可以显示bmp图片,设置该app开机自动运行即可(在rcS中添加两行代码就可以了)。
    bmp图片的格式网上有详解,编写代码displaybmp.c:
    1. #include <stdio.h>
    2. #include <sys/types.h>
    3. #include <sys/stat.h>
    4. #include <fcntl.h>
    5. #include <unistd.h>
    6. #include <stdlib.h>

    7. #define SCREEN_HEIGHT 600
    8. #define SCREEN_WIDTH 1024

    9. #pragma pack(1) // 让编译器做1字节对齐

    10. struct bmp_file     //BMP文件头结构
    11. {
    12.         char type[2];                       //位图文件的类型,必须为BM,我这里类型不对,所以显示有误。
    13.         unsigned int size;                  //位图文件的大小,以字节为单位
    14.         short rd1;                          // 位图文件保留字,必须为0
    15.         short rd2;                          // 位图文件保留字,必须为0
    16.         unsigned int offset;            // 位图数据的起始位置,以相对于位图
    17. };

    18. struct bmp_info   //图像信息区
    19. {
    20.         unsigned int bsize;                      //本结构体所占用字节数,即40个字节
    21.         int width;                               // 位图的宽度,以像素为单位,像素数量是4字节对齐的
    22.         int height;                              // 位图的高度,以像素为单位,如果该位为正,说明图像是倒向的,为负则说明是正向,大多数都是正向,但是QQ截图保存的BMP好像都是正向的
    23.         unsigned short planes;                     // 目标设备的级别,必须为1
    24.         unsigned short count;                      // 每个像素所需的位数,必须是1(双色)// 4(16色),8(256色)或24(真彩色)之一
    25.         unsigned int compression;            // 位图压缩类型,必须是 0(不压缩),// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一
    26.         unsigned int sizeimage;              // 位图的大小,以字节为单位
    27.         unsigned int xmeter;                      // 位图水平分辨率,每米像素数
    28.         unsigned int ymeter;                 // 位图垂直分辨率,每米像素数
    29.         unsigned int cused;                  // 位图实际使用的颜色表中的颜色数
    30.         unsigned int cimportant;             // 位图显示过程中重要的颜色数

    31. };

    32. struct bmp_head {
    33.         struct bmp_file file;
    34.         struct bmp_info info;
    35. };

    36. #pragma pack() // 取消1字节对齐,恢复为默认对齐

    37. struct bmp_head bmphead;
    38. unsigned char *bmpBuff = NULL;
    39. unsigned int *fbBuff = NULL;

    40. int bmp_width = 0;
    41. int bmp_height = 0;
    42. int actual_width = 0, actual_height = 0; /* 实际显在屏幕上的大小,如果BMP图片比屏幕大,那么就只显示屏幕分辨率的大小*/
    43. int flag = 0; /* 指示图像是否是倒向的,倒向为0,正向为1 */
    44. int pix_count = 0; /* 指示每个像素占用的大小,字节为单位 */

    45. void draw_screenbuf_point(int x, int y, unsigned int color) //在LCD buf上x, y处画一个点
    46. {
    47.         if(flag)
    48.                 fbBuff[y * SCREEN_WIDTH + x] = color;
    49.         else
    50.                 fbBuff[(SCREEN_HEIGHT - 1 - y) * SCREEN_WIDTH + x] = color;
    51. }

    52. unsigned int read_bmp_point(int x, int y) //从bmp文件中取出x,y坐标处的点
    53. {
    54.         unsigned int color = 0;
    55.         unsigned char R,G,B;
    56.         if(pix_count == 24) {  /* bmp图片count不一样,数据区的格式就不一样 */
    57.                 B = bmpBuff[(x + y*bmp_width)*3];
    58.                 G = bmpBuff[(x + y*bmp_width)*3+1];
    59.                 R = bmpBuff[(x + y*bmp_width)*3+2];  /* (x + y*bmp_width)*4+3存放alpha值,不使用 */
    60.                 color = B | G<<8 | R<<16 | 0x80<<24; /* 0x80为透明度 */
    61.                 return color;
    62.         }
    63.         else if(pix_count == 32) {
    64.                 B = bmpBuff[(x + y*bmp_width)*4];
    65.                 G = bmpBuff[(x + y*bmp_width)*4+1];
    66.                 R = bmpBuff[(x + y*bmp_width)*4+2];  /* (x + y*bmp_width)*4+3存放alpha值,不使用 */
    67.                 color = B | G<<8 | R<<16 | 0x80<<24; /* 0x80为透明度 */
    68.                 return color;
    69.         }
    70.         else
    71.                 return 0x800000ff;
    72. }

    73. int main(int argc,char *argv[])
    74. {
    75.        
    76.         if(2 != argc) {
    77.                 printf("Usage:%s xxx.bmp\n",argv[0]);
    78.                 return -1;
    79.         }

    80.         int bmpfd = open(argv[1],O_RDWR);
    81.         if(-1 == bmpfd) {
    82.                 perror("open faild\n");
    83.                 return -1;
    84.         }

    85.         int fbdev = open("/dev/fb0",O_RDWR);
    86.         if(-1 == fbdev) {
    87.                 perror("open failed\n");
    88.                 return -1;
    89.         }

    90.         if (-1 == read(bmpfd, &bmphead, sizeof(bmphead))) {
    91.                 perror("read failed\n");
    92.                 return -1;
    93.         }

    94.         pix_count = bmphead.info.count;
    95.         if((pix_count != 24) && (pix_count != 32) ) {
    96.                 printf("This format is not supported! pix_count:pix_count:%d\n", pix_count);
    97.                 return 0;
    98.         }

    99.         bmp_width = bmphead.info.width;

    100.         if(bmphead.info.height < 0) {
    101.                 bmp_height = 0-bmphead.info.height; //换成正数
    102.                 flag = 1;
    103.         }
    104.         else {
    105.                 bmp_height = bmphead.info.height;
    106.                 flag = 0;
    107.         }

    108.         actual_width = bmp_width;
    109.         actual_height = bmp_height;
    110.         if(bmp_width > SCREEN_WIDTH) {
    111.                 actual_width = SCREEN_WIDTH;
    112.         }
    113.         if(bmp_height > SCREEN_HEIGHT) {
    114.                 actual_height = SCREEN_HEIGHT;
    115.         }

    116.         // printf("%s:%dx%d, flag:%d\n", argv[1], bmp_width, bmp_height, flag);
    117.         // printf("screen size:%dx%d\n", SCREEN_WIDTH, SCREEN_HEIGHT);
    118.         // printf("display size:%dx%d\n", actual_width, actual_height);

    119.         bmpBuff = (unsigned char *)malloc(bmphead.file.size - sizeof(struct bmp_head));
    120.         if(NULL == bmpBuff) {
    121.                 perror("malloc failed\n");
    122.                 return -1;
    123.         }

    124.         fbBuff = (unsigned int *)malloc(SCREEN_WIDTH*SCREEN_HEIGHT*sizeof(int));
    125.         if(NULL == fbBuff) {
    126.                 perror("malloc failed\n");
    127.                 return -1;
    128.         }

    129.         if (-1 == read(bmpfd, bmpBuff, bmphead.file.size - sizeof(struct bmp_head))) {
    130.                 perror("read failed\n");
    131.                 return -1;
    132.         }

    133.         int x = 0,y = 0;
    134.         unsigned int color;
    135.         for(y=0; y < actual_height; y++) {
    136.                 for(x=0; x < actual_width; x++) {
    137.                         color = read_bmp_point(x, y);
    138.                         draw_screenbuf_point(x, y, color);
    139.                 }
    140.         }

    141.         write(fbdev, fbBuff, SCREEN_WIDTH*SCREEN_HEIGHT*4); /* 写入frambuffer */

    142.         free(fbBuff);
    143.         free(bmpBuff);

    144.         close(fbdev);
    145.         close(bmpfd);
    146.         return 0;
    147. }
    复制代码

    该程序的原理就是根据bmp的格式读取RGB数据,然后写入linux的framebuffer就可以显示了,只支持位图数据为32位或者24位的bmp图像显示。
    编译测试:
    1. <p>arm-linux-gnueabihf-gcc disbmp.c -o displaybmp</p>
    复制代码
    使用QQ或者起他工具截图并保存为bmp格式,然后将bmp图片放入roots目录下,执行:
    1. displaybmp xxx.bmp
    复制代码
    一切正常的话LCD上应该就显示截图了。然后在/etc/init.d/rcS末尾添加:
    1. ./displaybmp xxx.bmp &
    复制代码
    重启后就会自动显示了。



    文章出处:CSDN


    签到签到
    回复

    使用道具 举报

  • TA的每日心情

    2021-2-4 09:24
  • 签到天数: 190 天

    [LV.7]常住居民III

    38

    主题

    591

    帖子

    28

    金牌会员

    Rank: 6Rank: 6

    积分
    2193
    最后登录
    2023-12-1
    发表于 2020-6-3 19:51:38 | 显示全部楼层
    谢谢管管分享
    哎...今天够累的,签到来了~
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2024-4-16 15:24 , Processed in 0.115857 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表