目录

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

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

  • 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系统的配置文件等,都会存储在这样一个根文件系统中。
  • SD卡启动的最大优点就是方便可携带, SD卡被分为两个分区。一个FAT32分区存放BOOT.BIN和image.ub文件,一个ext4分区存放rootfs。

  • zynq-7000有两个SD控制器,在blockdesign里配置zynq核时,根据硬件原理图显示(SD连到了PS端,电路接口与zynq的MIO40-45相连),选择SD0并选择正确的MIO口。

    https://i-blog.csdnimg.cn/blog_migrate/b39e09f39d483c01955c9b578d476b16.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/b4360418133add78ef2b0e2d462eb24f.png#pic_center

  • 输入 petalinux-config --get-hw-description -p ./ 配置硬件。

  • 选择SD0作为首选SDIO。

    https://i-blog.csdnimg.cn/blog_migrate/63cc1c07c4829c3ac2e81b2ecfaf36da.png#pic_center

  • 选择SD作为BOOT.BIN的存储介质。

    https://i-blog.csdnimg.cn/blog_migrate/3b59c41d213ab97fca40912efe11ffef.png#pic_center

  • 默认FLASH作为u-boot环境变量的存储介质,u-boot会根据下面的FLASH分区表到指定的位置读取环境变量。忽略除bootenv外的其它部分,因为FLASH中根本就没有这些部分,它们都在SD卡上。在这里只会用到FLASH中的bootenv。

    https://i-blog.csdnimg.cn/blog_migrate/8d7d4155532d41fd0eab9ab9fddee002.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/d844edce17808c6c7712c4bb881ef134.png#pic_center

  • 根据前面所分析,内核镜像当然在SD卡上喽。

    https://i-blog.csdnimg.cn/blog_migrate/a2ea3c41dc1fc1767900d87a32f7a679.png#pic_center

  • 下面还有能设置文件系统的存储介质,这里我们不管它,因为我们不从FALSH加载文件系统,不对它进行设置。那我们在哪设置呢?

    https://i-blog.csdnimg.cn/blog_migrate/d346e267bb11bd52335fd4d26baefea7.png#pic_center

  • 在如下目录,设置文件系统的类型和位置,我们的文件系统在SD卡的第二分区,所以选择文件系统类型为SD,设备节点设置为 /dev/mmcblk0p2

    https://i-blog.csdnimg.cn/blog_migrate/afc379eadd154830b2e1befe63fb1127.png#pic_center

  • 可以看到,有这么多种文件系统类型。从上到下依次为,内存文件系统、ramdisk文件系统、闪存文件系统、网络文件系统、SD文件系统。

    https://i-blog.csdnimg.cn/blog_migrate/f74c9cf9fd5637f5393fb0043af65a48.png#pic_center

  • 我们的设备树和系统镜像是绑定的,所以如下设置设备树。

    https://i-blog.csdnimg.cn/blog_migrate/96a116b2e97562de153ee46197b76d37.png#pic_center

  • 输入 petalinux-config -c u-boot 配置u-boot支持的启动内核方式,内核在SD卡中,所以这里是从SD启动。

    https://i-blog.csdnimg.cn/blog_migrate/4f68abc4994ea7d5be1af7a5b0d231e6.png#pic_center

  • 如上所示,从SD卡启动已配置完成,输入 petalinux-build 编译内核即可。

  • 我们用petalinux配置完后,petalinux会根据我们的配置生成u-boot的环境变量,进入u-boot后输入 printenv 查看环境变量。

    https://i-blog.csdnimg.cn/blog_migrate/3a4b0a53d73c6dd8ee36535a70877801.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/530a048f5c7aad481650b9118ed27ce6.png#pic_center

  • 下面我简要分析一下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。

    https://i-blog.csdnimg.cn/blog_migrate/f66da5c9a00caf9053996fc33ec56d00.png#pic_center

  • 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)。

    https://i-blog.csdnimg.cn/blog_migrate/b23261083863d55d6532a7aae8bf56f6.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/129ba8b79920a88f3a8b8eae9ebf7408.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/925305ea6ac1c14ac15dc8000426bacb.png#pic_center

  • 我们要根据每个文件的大小对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根本放不下!!!!!

    https://i-blog.csdnimg.cn/blog_migrate/8dea2011b62c2e142070c2cad6f87d07.png#pic_center

  • BOOT.BIN,linux内核及文件系统都在FLASH里。

    https://i-blog.csdnimg.cn/blog_migrate/6b0020dcdc102c8e9e4aa6821874a4b5.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/a36d12969abb03b3a60a5a64e5f97c3a.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/2e0676e7e1453d155034d9fcfe835966.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/a52332516050d71c63d4ce2c76c22206.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/1c4dee8956f68754f13e8ef5058683c8.png#pic_center

  • 文件系统类型选择jfss2闪存文件系统。

    https://i-blog.csdnimg.cn/blog_migrate/c9af2fdc8b6da448128f600bdcf6f3ab.png#pic_center

  • 同样,U-boot选择从FLASH启动linux内核。

    https://i-blog.csdnimg.cn/blog_migrate/3836bd47f1daec3904a7b9f28f8bc3b7.png#pic_center

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

    https://i-blog.csdnimg.cn/blog_migrate/b6bb674ccef299a388be3218403f2b1b.png#pic_center

  • 用JTAG将BOOT.BIN下载至FLASH后,在u-boot启动后打印环境变量。

    https://i-blog.csdnimg.cn/blog_migrate/af434e3b67df33dd34d8c4fb3043ffa6.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/bc50c6714cad606ea66e9517c1c5e340.png#pic_center

  • 下面简要分析一下该环境变量。

    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

    https://i-blog.csdnimg.cn/blog_migrate/a18c821c3535568fa923971375d30e21.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/8c3a8753e627fa9b172725e792b83ea0.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/46ad8d41d02044dd33a43ed61154fb70.png#pic_center

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

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

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

    https://i-blog.csdnimg.cn/blog_migrate/24e1280fc3a7d272f0896b566c1f21aa.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/61fbd4279c7b219b598768ab44e2db35.png#pic_center

  • 大家最好还是别用这种方式了,如果有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可见 )

    https://i-blog.csdnimg.cn/blog_migrate/83b3698a35e2d54d73538b18c3e6bd26.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/9d8aaf151606e95b4c0646d76ee4dcb1.png#pic_center

    https://i-blog.csdnimg.cn/blog_migrate/ad4bec80ce93eb2cd0eaaab85f4e8901.png#pic_center