ZYNQ-7000芯片用u-boot启动linux系统方法

0. 芯片启动概述

  • ZYNQ-7000系列芯片运行Linux操作系统需要BOOT.BIN文件、image.ub文件和rootfs。
  • BOOT.BIN文件由fsbl.elf、bitstream和u-boot.elf(裸机elf程序)文件组成。fsbl.elf是由xilinx设计的,由OCM加载执行,有两个主要功能。第一是用于加载bitstream到PL,第二是根据BOOT.BIN文件组成,执行u-boot或是裸机elf程序。bitstream文件是FPGA的配置文件。裸机elf程序用于在不启动操作系统的情况下运行一些软件。u-boot.elf是一种bootloader程序,可以根据不同的硬件情况,在不同的场景下引导操作系统镜像的执行。
  • image.ub文件是由操作系统的镜像文件uImage和设备树文件dtb组成。uImage由压缩过的操作系统镜像zImage和一段由u-boot在引导时会读取的头image_header_t(64B)组成,这个头用于储存u-boot在引导系统时所要获取的一些信息。zImage由未压缩的内核镜像vmlinux和解压代码组成。在u-boot引导内核时,会解压zImage到内存中执行。
  • rootfs是linux的根文件系统,在linux系统启动过程中,必须要挂载这样一个根文件系统。我们的可执行程序以及所用到的库文件、linux系统的配置文件等,都会存储在这样一个根文件系统中。

1. SD卡启动

  • SD卡启动的最大优点就是方便可携带,SD卡被分为两个分区。一个FAT32分区存放BOOT.BIN和image.ub文件,一个ext4分区存放rootfs。
  • zynq-7000有两个SD控制器,在blockdesign里配置zynq核时,根据硬件原理图显示(SD连到了PS端,电路接口与zynq的MIO40-45相连),选择SD0并选择正确的MIO口。
    在这里插入图片描述
    在这里插入图片描述
  • 输入 petalinux-config --get-hw-description -p ./配置硬件。
  • 选择SD0作为首选SDIO。
    在这里插入图片描述
  • 选择SD作为BOOT.BIN的存储介质。
    在这里插入图片描述
  • 默认FLASH作为u-boot环境变量的存储介质,u-boot会根据下面的FLASH分区表到指定的位置读取环境变量。忽略除bootenv外的其它部分,因为FLASH中根本就没有这些部分,它们都在SD卡上。在这里只会用到FLASH中的bootenv。
    在这里插入图片描述
    在这里插入图片描述
  • 根据前面所分析,内核镜像当然在SD卡上喽。
    在这里插入图片描述
  • 下面还有能设置文件系统的存储介质,这里我们不管它,因为我们不从FALSH加载文件系统,不对它进行设置。那我们在哪设置呢?
    在这里插入图片描述
  • 在如下目录,设置文件系统的类型和位置,我们的文件系统在SD卡的第二分区,所以选择文件系统类型为SD,设备节点设置为/dev/mmcblk0p2
    在这里插入图片描述
  • 可以看到,有这么多种文件系统类型。从上到下依次为,内存文件系统、ramdisk文件系统、闪存文件系统、网络文件系统、SD文件系统。
    在这里插入图片描述
  • 我们的设备树和系统镜像是绑定的,所以如下设置设备树。
    在这里插入图片描述
  • 输入petalinux-config -c u-boot配置u-boot支持的启动内核方式,内核在SD卡中,所以这里是从SD启动。
    在这里插入图片描述
  • 如上所示,从SD卡启动已配置完成,输入petalinux-build编译内核即可。
  • 我们用petalinux配置完后,petalinux会根据我们的配置生成u-boot的环境变量,进入u-boot后输入printenv查看环境变量。
    在这里插入图片描述
    在这里插入图片描述
  • 下面我简要分析一下u-boot的环境变量。
    bootcmd=run default_bootcmd bootcmd变量用于启动内核,在u-boot中输入run bootcmd即可启动内核。
    default_bootcmd=run cp_kernel2ram && bootm ${netstart}
    cp_kernel2ram=mmc dev 0 && mmcinfo && fatload mmc 0 ${netstart} ${kernel_img} cp_kernel2ram变量用于将内核加载到内存中,mmc dev 0用于切换到设备mmc0,mmcinfo用于打印mmc的信息,fatload用于从FAT32文件系统中加载文件到内存的给定位置。netstart=0x10000000给定了加载到的内存位置,kernel_img=image.ub指定了文件的名称。bootm用于从指定的内存地址启动系统镜像,在这里即从加载到的位置启动镜像。
  • 在系统启动过程中我们看到,挂载了SD卡上的rootfs。
    在这里插入图片描述

2. QSPI_FLASH 启动

  • QSPI_FLASH 启动时,FLASH被分为四个分区。partition0存放BOOT.BIN文件,partition1存放u-boot的环境变量,partition2存放image.ub,partition3存放文件系统。

  • 一般情况下,当应用程序需要使用一些库,如Qt库时,文件系统所占空间会比较大。当FPGA逻辑部分比较复杂时,bitstream文件也会比较大,故BOOT.BIN文件会很大。我的硬件FLASH只有32MB,在这种情况下是肯定放不下的。所以一般不使用这种方式。

  • 下面我简要介绍一下这种方式的实现。

  • QSPI_FLASH启动时,我们要用到FLASH芯片了,我们要在blockdesign里配置QSPI用于读写FLASH。我们使用的核心板上两块FLASH芯片并行连接成8bit宽,每个FLASH为4bit宽,即4线spi(QSPI)。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 我们要根据每个文件的大小对FLASH的分区进行设置,一般情况下,FLASH是放不下这些文件的。每个分区大小设置如下,其实已大于FLASH的总大小32MB。下面估计每个文件的大小:
    Boot.BIN 17.9MB 分配18MB 0x1200000
    bootenv 分配128KB 0x20000
    image.ub 3.7MB 分配4MB 0x400000
    jffs2 分配8MB 0x800000 实际14.1MB
    我们看到,32MB的FLASH根本放不下!!!!!
    在这里插入图片描述

  • BOOT.BIN,linux内核及文件系统都在FLASH里。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 文件系统类型选择jfss2闪存文件系统。
    在这里插入图片描述

  • 同样,U-boot选择从FLASH启动linux内核。
    在这里插入图片描述

  • 镜像编译完成后,我们反编译设备树,可以看到FLASH的分区如下所示,已经超出了FLASH的32MB存储范围。
    在这里插入图片描述

  • 用JTAG将BOOT.BIN下载至FLASH后,在u-boot启动后打印环境变量。
    在这里插入图片描述
    在这里插入图片描述

  • 下面简要分析一下该环境变量。
    bootcmd=run default_bootcmddefault_bootcmd=run cp_kernel2ram && bootm ${netstart} 如前文所述,不再叙述。
    cp_kernel2ram=sf probe 0 && sf read ${netstart} ${kernelstart} ${kernelsize}
    cp_kernel2ram用于将内核镜像从存储介质复制到内存执行。 sf probe 0用于初始化与给定SPI总线相连接的FLASH设备。sf read用于从给定的内存地址读取数据并保存到FLASH上。netstart=0x10000000为镜像加载的内存地址,kernelstart=0x1220000为给内核分配的FLASH起始地址,kernelsize=0x400000为给内核分配的FLASH存储空间。

  • 如下图,设置板子和主机的ip地址,连接以太网并打开tftp服务器,通过通过tftp下载image.ub和jfss2到FLASH中,并启动内核。注意到,内核不一定能启动成功,因为FLASH放不下jffs2。
    set serverip 192.168.10.124
    set ipaddr 192.168.10.1
    tftp 0x10000000 image.ub
    sf probe 0
    sf erase 0x01220000 0x400000
    sf write 0x10000000 0x01220000 0x400000
    tftp 0x10000000 rootfs.jffs2
    sf erase 0x1620000 0xd6e770
    sf write 0x10000000 0x1620000 0xd6e770
    sf erase 0x1620000 0x800000
    sf write 0x10000000 0x1620000 0x800000
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 可以看到,完整的jffs2根本就无法下载到FLASH中,只能将不完整的jffs2文件系统下载到FLASH中。

  • 现在,FLASH中已经有BOOT.BIN,image.ub,jffs2了,重启后,u-boot会从FLASH中读取内核并挂载jffs2,可能启动失败,因为文件系统不完整!!

  • 我们看到,在系统启动过程中,打印了许多jffs2错误和空间不足等信息,这是我们预料之中的。最神奇的是,我们竟然能登录进入系统。不得不说,Linux真的牛逼!!虽然系统能够进去,但使用肯定是不正常的,因为外存空间不足了。
    在这里插入图片描述
    在这里插入图片描述

  • 大家最好还是别用这种方式了,如果有EMMC的话,它不香吗?

3. QSPI_FLASH + EMMC启动

  • 在项目中,我一般使用这种方式,QSPI_FLASH + EMMC启动最大的优点是EMMC芯片稳定、可靠性高、能适用于震动等环境相对恶劣的场合。
  • QSPI_FLASH + EMMC启动时,BOOT.BIN文件存放在FLASH中,大容量(8GB)EMMC芯片被分为两个分区,第一个FAT32分区存放image.ub,第二个ext4分区存放rootfs。
  • 我所使用的开发板EMMC接在了PL端,PS端通过EMIO接口路由到PL端,我们要在PL端进行约束,从而使得PS能与EMMC通信。(关于MIO与EMIO可见ZYNQ-7000 GPIO使用
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

4. QSPI_FLASH + RAMFS启动

5. QSPI_FLASH + NFS启动

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页