概述

本文将以Zynq开发板为示例,介绍多种使用QSPI的方式启动PetaLinux的流程,并针对一些可能出现的问题提出解决方法。

1. Petalinux启动过程

总的来说,操作系统启动主要包括三个步骤:启动u-boot、加载内核、挂载根文件系统

使用petalinux-package命令可以选择将哪些内容打包到BOOT.BIN中。例如,当使用以下命令时:

1
petalinux-package --boot --force --u-boot --fsbl --fpga

则将fsbl.elf、system.bit(FPGA比特流文件)、u-boot.elf、system.dtb(设备树文件)打包到BOOT.BIN中,使用该BOOT.BIN可以启动至u-boot,还需要image.ub和boot.scr才能完整启动OS。

image.ub内部不仅包含内核 (Image),当Root filesystem type选择为INITRAMFS方式时,还包含了文件系统(rootfs.cpio)。内核启动时会在内存中解压这个文件系统,系统启动完成后所看到的根目录完全存在于DDR内存中。

boot.scr是u-boot启动后,用于加载内核的脚本。

使用QSPI启动时,内核文件可以通过petalinux-package命令打包到BOOT.BIN中并烧写到Flash上。另一种方式是先将不含内核的BOOT.BIN文件烧写到Flash中,启动至u-boot后再通过SD卡或网络读取内核文件。这正是本文第3、4、5章将要详细介绍的内容。

2. 在PS配置中打开QSPI

使用QSPI,需要在Zynq IP核配置中打开QSPI功能,并根据手册选择对应的MIO引脚。

3. PetaLinux QSPI Flash启动

📝概述

将启动文件和内核等内容全部写入Flash中,系统启动时从Flash读取内容到内存并启动。

3.1 flash分区管理

这里需要对flash的分区进行管理,通常包括boot、bootenv、kernel、bootscr分区。

petalinux-config -> Subsystem AUTO Hardware Settings -> Flash Settings中可以设置各分区的大小。

boot分区用于启动u-boot通常包括fsbl.elf、system.bit、u-boot.elf、system.dtb,也就是使用petalinux-package --boot --force --u-boot --fsbl --fpga命令打包到BOOT.BIN中的文件,boot分区的大小需要大于这些文件大小总和。

bootenv分区存放u-boot的环境变量。

kernel分区存放image.ub。

bootscr分区存放boot.scr。

通常boot分区和kernel分区需要设置较大值,根据文件的大小决定,注意这些分区总大小不要超过flash的大小。

3.2 设置fit image offset

虽然设置了flash中各个分区的大小,但是仍需要在配置中指定各个分区的偏移和大小,其中boot分区偏移默认从0开始,无需设置。

petalinux-config -> u-boot Configuration -> u-boot script configuration -> QSPI/OSPI image offsets中设置fit image offset,fit image指的就是image.ub,所以就是kernel分区的偏移0x1640000(0x1500000+0x100000+0x40000)。

Kernel offset和Ramdisk offset也可以设置一下,虽然应该没什么用。

3.3 设置Boot script offset

设置petalinux-config -c u-boot -> ARM architecture -> Boot script offset,默认为0x9C0000,这里需要更改为bootscr分区的偏移0x1600000(0x1500000+0x100000)。

3.4 设置u-boot环境变量

然后在petalinux-config -c u-boot -> Environment中:

(1)取消勾选Environment is not stored、Environment is in a FAT filesystem、Environment in a NAND device。

(2)可选:取消勾选Enable redundant environment support。(避免混淆)

(3)设置offset和size,与前面flash setting中的bootenv分区设置一致。

3.5 打包启动文件

petalinux-build之后,使用:

1
petalinux-package --boot --force --u-boot --fsbl --fpga --kernel

此时,image.ub和boot.scr也会被打包进BOOT.BIN中。

但出现offset重叠的问题:

观察petalinux-config -c u-boot->Boot script offset,发现自动更改回默认值,观察project-spec/meta-user/recipes-bsp/u-boot,其中files文件夹下存有用户配置文件,先前所修改的Boot script offset的配置保存在该文件中,在u-boot-xlnx_%.bbappend中,引用了该文件,所以先前的修改的配置理应生效。

3.6 解决offset重叠问题

这里有两种方法可以解决该问题:

(1)修改images/linux/bootgen.bif文件

将boot.scr的offset修改为0x1600000。

然后使用以下命令指定该bootgen.bif运行:

1
petalinux-package --boot --force --u-boot --fsbl --fpga --kernel --bif bootgen.bif

(2)在命令中指定offset

bootgen.bif其实是运行petalinux-package所产生的,所以在petalinux-package时就可以指定boot.scr的偏移:

1
petalinux-package --boot --force --u-boot --fsbl --fpga --kernel --boot-script --offset 0x1600000

这两种方法都会出现以下warning:

这是因为fsbl.elf、system.bit、u-boot.elf、system.dtb都在boot分区中,它们的偏移都从0开始,所以这里提示有交叠。这里可以修改bootgen.bit或在命令行中指定fsbl等的偏移,但实际上运行以下指令以打印详细信息:

1
petalinux-package --boot --force --u-boot --fsbl --fpga --kernel --boot-script --offset 0x1600000 --bootgen-extra-args "-log trace"

在shell窗口或bootgen_log.txt中可以看到:

这里它自动给各个文件分配了offset和length,只有boot.scr和image.ub是我们先前手动指定的offset。

所以这个warning只是提示的作用,可以忽略。

另外,也可以使用以下命令生成MCS格式的启动文件:

1
petalinux-package --boot --force --u-boot --fsbl --fpga --kernel --boot-script --offset 0x1600000 --format MCS

运行后在images/linux下出现boot.mcs文件。

3.7 烧录启动文件到Flash

接下来使用Vivado或Vitis将BOOT.BIN或boot.mcs写入板子的flash中。

3.7.1 使用Vivado烧录

Open Target后点击Add Configuration Memory Device:

这里我的Zynq是2片256MB大小的Quad-SPIFLASH芯片(型号为W25Q256FVEI)组成8位带宽数据总线,所以需要选择qspi-x8-dual_parallel:

不过Vivado中并没有该型号,可以选择一个近似的比如w25q128fv,也可以手动添加,在Vivado/2023.1/data/xicom目录下找到xicom_cfgmem_part_table.csv,添加一栏:

998 0 w25q256fv-qspi-x8-dual_parallel zynq7000 - w25q256fv qspi 256 x8-dual_parallel Winbond 1 w25q256fv-qspi-x8-dual_parallel w25q

重新启动Vivado即可看到该新增的型号:

在Hardware界面中选中该memory,点击Program Configuration Memory Device

然后选择需要烧写的文件即可:

这里需要一个fsbl,在Vitis中创建一个platform build后就可以找到fsbl。

3.7.2 Vitis烧录

点击上方的Vitis -> Program Flash

只需要指定Image File的路径指向BOOT.BIN或boot.mcs,然后指定Flash Type。

3.8 启动

将板子设置成QSPI启动模式,打开串口调试,启动板子。由于u-boot配置中,Boot script offset默认为0x9c0000,所以这里启动时仍然从0x9c0000读取boot.scr,然而在petalinux-package时已经把boot.scr放到了0x1600000的位置上,所以这里会启动失败。

这里需要修改环境变量setenv script_offset_f 0x1600000并通过saveenv保存:

然后重新启动板子即可。如果环境变量有问题,无法使用先前设定的环境变量,可能会出现以下提示:

可以在u-boot中手动执行boot.scr的内容,加载位于Flash 0x1640000位置的内核镜像到内存0x10000000的位置上,然后启动该位置的内核:

1
2
3
sf probe 0 0 0
sf read 0x10000000 0x1640000 0x1500000
bootm 0x10000000

如果不想每次都进入u-boot界面,希望一次性启动OS,可以修改project-spec/meta-user/recipes-bsp/u-boot/files/bsp.cfg,将0x9c0000改成0x1600000。也可以参考第九节设定自定义启动命令。

4. PetaLinux QSPI Flash+SD卡启动

📝概述

先将不带内核的BOOT.BIN烧写到Flash中,启动u-boot后从SD卡读取内核并启动内核。

这样做理论上不需要去手动划分各个分区,并设置分区的偏移和大小,直接使用petalinux-package --boot --force --u-boot --fsbl --fpga即可得到不带内核的BOOT.BIN。

如果前面烧写了带内核的BOOT.BIN,这里烧写时应选择Entire Configuration Memory Device,否则只erase一部分flash,之前烧写的内核依然在flash中,启动时仍然可能会直接启动整个OS。

将image.ub拷贝到sd卡中(FAT32分区)。

可选:在u-boot中查看sd卡设备信息,及其文件系统中是否有image.ub:

加载内核并启动:

1
2
3
mmc dev 0
load mmc 0:1 0x10000000 image.ub
bootm 0x10000000

5. PetaLinux QSPI Flash+TFTP启动

📝概述

同样先将不带内核的BOOT.BIN烧写到Flash中启动u-boot,然后通过TFTP的方式获取内核并启动内核。

5.1 配置TFTP服务器

参考网站配置tftp服务器:

petalinux-config -> Image Packaging Configuration中设置tftp文件夹路径:

这样就可以将images/linux下的文件自动拷贝到tftp文件夹中。当然,也可以自己手动将image.ub复制到tftp文件夹中。

5.2 网络配置

为了让板子能够连接到虚拟机,虚拟机需要配置桥接模式的网卡:

然后打开编辑 -> 虚拟网络编辑器:

点击右下角”更改设置”,然后将VMnet0的网卡选择为以太网的网卡。

分别设置主机和虚拟机的网络地址,使其在同一子网下:

在u-boot界面设置服务器ip为虚拟机的ip地址,同时设置板子的ip地址:

1
2
setenv serverip 192.168.2.150
setenv ipaddr 192.168.2.100

确保连接正常:

加载内核并启动:

1
2
tftpboot 0x10000000 image.ub
bootm 0x10000000

如果网络不稳定,可能loading时候会打印T,累计超过10个T就自动结束loading。此时可以更换网线,但最好是在petalinux-config -c u-boot -> Networking support中调整重传时间为10000ms和重传次数为255。同时增大size of buffer、block size和window size来提升网络传输速度(实测增大参数后由300多KB/s上升至10MB/s)。

6. bootm出现inflate() returned -5,gzip uncompress error

这里是解压内核出现了问题,可能是内核太大原因,可以在petalinux-config -> Image Packaging Configuration —> Root filesystem type中,选择EXT4,这样它就不会将文件系统放到内核中,而是直接挂载SD卡的文件系统。(实测内核大小从600M下降到20M)

也可以直接使用未压缩的内核。

查看petalinux-config -> u-boot Configuration -> u-boot script configuration -> Kernel image name,有的叫uImage,有的叫Image。

在images/linux目录下,将uImage/Image、system.dtb拷贝到SD卡中或者tftp目录下。

在u-boot界面,如果拷贝在SD卡中,则运行以下指令:

1
2
3
4
mmc dev 0
fatload mmc 0:1 0x1F000000 system.dtb
fatload mmc 0:1 0x20000000 Image
booti 0x20000000 - 0x1F000000

读取到内存中的地址可以根据文件的大小决定,这边我的system.dtb大小为20多KB,从0x1F000000-0x20000000有16MB的大小,足够装下该文件。

booti命令格式为:booti addr [initrd[:size]] [fdt]

所需的三个参数分别是内核地址、文件系统地址和设备树地址。如果Root filesystem type选择为EXT4,则文件系统地址不需要指定,用”-“代替,否则它会解压并使用该位置的文件系统而不是来自SD卡的文件系统。如果Root filesystem type为INITRAMFS时,文件系统直接包含在Image里面,此时无论指不指定文件系统地址都可以。

如果需要指定该参数,先把rootfs.cpio.gz.u-boot也拷贝到SD卡里,然后加载到内存:

1
fatload mmc 0:1 0x60000000 rootfs.cpio.gz.u-boot

使用以下命令启动:

1
booti 0x20000000 0x60000000 0x1F000000

此时无论Root filesystem type是什么,都会以该文件系统启动内核。

如果放在tftp文件夹下,则运行以下指令:

1
2
3
tftpboot 0x1F000000 system.dtb
tftpboot 0x20000000 Image
booti 0x20000000 - 0x1F000000

7. 读取SD卡文件出现Error reading cluster,Failed to load ‘xxx’

如果出现以下问题:

可以尝试将文件放到SD卡的ext4分区(这里我的ext4分区还有文件系统),创建一个文件夹以放置这些文件:

然后使用ext4load读取文件:

1
2
mmc dev 0
ext4load mmc 0:2 0x20000000 /myboot/system.dtb

如果依然出现问题,可以反复运行这两条指令(两条指令之间间隔两三秒)或重启或更换SD卡,有可能成功:

如果多次出现Transfer data timeout且重启依然如此,可能是文件太大的问题:

通过以下命令将Image拆成多份:

1
split -b 128M Image Image.part

根据文件大小生成多个Image.partxx文件,将其复制到SD卡中。

然后在u-boot中依次加载各文件,需要注意地址,前面设置每份大小是128M,所以这里相隔0x8000000:

1
2
3
4
5
6
mmc dev 0
ext4load mmc 0:2 0x20000000 /myboot/Image.partaa
ext4load mmc 0:2 0x28000000 /myboot/Image.partab
ext4load mmc 0:2 0x30000000 /myboot/Image.partac
ext4load mmc 0:2 0x38000000 /myboot/Image.partad
ext4load mmc 0:2 0x40000000 /myboot/Image.partae

8. 挂载SD卡文件系统

如果使用SD卡的文件系统启动OS有问题,可以使用INITRAMFS的方式启动OS,然后在/mnt下创建一个文件夹,将SD卡挂载到该文件夹下。

挂载之后可以读写SD卡文件系统中的文件:

9. 设置自定义启动命令

为了避免每次都进入u-boot然后手动启动,这里可以设置启动命令,启动u-boot后自动执行这些命令。

设置petalinux-config -c u-boot -> Boot options -> bootcmd value,各命令之间用”&&”分隔。

10. 总结

总结

根据自身的情况选择不同的方法,直接将各种启动文件打包到BOOT.BIN中启动是最简单的方法。但如果不想配置flash分区,则可以使用不带内核的BOOT.BIN启动至u-boot,再使用SD卡或TFTP获取内核。
如果执行bootm解压内核时出现问题,则尝试使用EXT4文件系统而非INITRAMFS从而降低BOOT.BIN的大小。如果没有SD卡或SD文件系统启动有问题无法选择EXT4文件系统,则使用booti启动未压缩的内核,此时需要在启动u-boot后使用TFTP的方式获取未压缩的内核、设备树文件、文件系统(可选)。


Site Total Visits: Loading
Site Total Visitors: Loading