这两天翻出来了去年代收的 PolarFire SoC Icicle Kit。因为隔壁的 FPGA 大佬们看不上这块板子,我打算尝试物尽其用一下,目标只是用板子上的 RISC-V 核启动 Arch Linux RISC-V 的 rootfs 测试(把它当作一块 SD 卡槽没有问题、并且带 PCIE 的 HiFive Unleashed 来用。隔壁嵌入式群的大佬们:买椟还珠!)。如此便开始了年轻人的 FPGA 初体验(可能还是不能算)。
噩梦的开始
一开始尝试的当然是最新版的 Yocto 镜像,毕竟这是“官方”的 Linux 镜像。结果刷完后立刻遇到了启动失败:
一开始我还以为是 SD 卡坏了。在多次尝试未果后……
当时的猜测是(不一定对),可能因为板子上 FPGA 部分(抱歉,我不知道专业的称呼)不够新,所以我打算刷一下 HSS。结果这成为了噩梦的开始。
可怕的“硬件”工具链
我最初参考的文档来自 U-boot:https://u-boot.readthedocs.io/en/latest/board/microchip/mpfs_icicle.html
这份文档可能已经颇为过时,里面编译 HSS 的部分从一开始就找不到名叫“icicle-kit-es”的 BOARD.
在我加上 mpfs-
前缀,并根据后续报错依次按照我的 CROSS 工具链目标修改了 PLATFORM_RISCV_ABI=lp64d PLATFORM_RISCV_ISA=rv64gc
之后,我遇到了第一个大魔王:SoftConsole。
好在这个工具可以无需注册直接下载。
顺利安装完成后,按照要求设置 SC_INSTALL_DIR
,我终于看到了……下个错误:缺少 fpgenprog。
由于不想安装完整的 Libero SoC
(一个巨大的需要折腾 license 的开发工具集),我试图去下载这里提到的 Program Debug Tool
。从文档上找到下载链接点开后,看到了这样的悲剧:
它没了。
后面提到的 Programming and Debug
工具下载也藏在了注册墙后面,我考虑转向其他思路试试,先暂时没有继续了。
(另:关于 Libero SoC
的安装会有多坑,可以参考这位受害者的体验: https://www.cnx-software.com/2021/10/25/installing-libero-soc-in-ubuntu-and-windows-10/ )
Arch 内核的陨落
由于目前 Arch Linux RISC-V 基本没有处理 bootloader 部分的工作,我打算先试试直接使用旧版 Yocto 自带的 U-boot 来启动 Arch 的内核、rootfs。由于不熟悉 U-boot 和这些嵌入式镜像格式,我先花了点时间学习 U-boot 的启动逻辑 和操作 uImage 的常用命令等。
Yocto 的镜像里有一个很小的 /boot 分区,里面有 boot.scr.uimg 脚本和 fitImage 镜像。我遇到的第一个问题是,这个 FAT16 的 /boot 分区装不下 Arch 的 kernel,而且把 FAT16 扩容并转换为 FAT32 是 libparted 等常用工具不支持的操作。
在艰难尝试了许多次之后,我确定了这个分区后面的那个类型为 BIOS boot 但 GParted 抱怨为损坏分区的分区可能存放的是 uboot 本体(或者含它的 HSS?尚未仔细研究)。因此向后扩容 /boot 的想法可能不大靠谱。我只好退而求其次,把第一个分区删掉,直接把最后的 rootfs 所在分区标记为 legacy_boot
。
然后我复制了 Unmatched 上的 extlinux.conf
并做了相应修改(内核版本、UUID 等)。第一次尝试启动失败在缺少了两个环境变量:
后来在大佬们的帮助下,我找到了设置它的办法。其实正确的值就来自上面的 boot.scr.uimg
,设置前者为 ${ramdisk_addr_r}
,后者则只需要设置一个足够大的值。
然而这次 Arch 的内核挂在了无限循环刷屏 L2CACHE ERROR 上。
由于大佬觉得这个问题不好解决,我决定先暂时放弃内核,用 Yocto 的内核启动 Arch rootfs 测试。
用魔法打败魔法
在现在的情况下,直接用原版的 boot.scr.uimg 和 fitImage 组合至少存在这样的问题:
- 1、Arch rootfs 期待一个 rw 的 /。默认的 ro 环境会导致启动后一大堆服务失败、SSH Host Key 未生成等奇怪的问题。
- 2、默认的
root=
设置为了 SD 卡的第三个分区(/dev/mmcblk0p3
)。但经过上面的操作,SD 卡上现在已经只剩两个分区了。
为了修改 cmdline 解决这些问题,我在 U-boot shell 和 uEnv.txt 里鼓捣了各种操作都没有成功。看起来这个内核是把 cmdline 写死编译进去了。
在不重新编译内核的情况下,怎么更改里面写死的 cmdline 呢?那当然是直接修改二进制了!
首先把 fitImage 拆开,用 dumpimage 工具提取出里面的内核和 fdt 文件。从输出中可以看到,内核是 gzip 压缩过的:
用 gzip 解压这个文件,然后用 vim 打开:
诶嘿,我们的 cmdline 找到了。直接修改为想要的值(分区号直接替换,然后换掉一个应该影响不那么大的参数写上 rw),并保持字符串总长度不变(填空格补齐)。一共有两处,做同样处理即可。
修改完后,直接把未压缩的内核、fdt 复制到 rootfs 内,然后添加一个 extlinux 启动项:
label yocto
menu label Arch Linux with Yocto kernel
linux /boot/yocto.kernel.patched
fdt /boot/yocto.dtb
Bingo!成功启动。
至此,最初的目标有了一个最低限度的成果。
尾声/题外话
感谢 PLCT 实验室、TUNA、AOSC 等社区一直以来的帮助,肥猫现在可能从完全不懂嵌入式稍微进步了一点点。
没想到折腾这块难啃的板子会成为我荒废三年多的博客再次更新的契机。我的这一轮 Arch Linux RISC-V 移植项目从最初尝试至今也已经超过三年,而今年年底就是我进入 Arch 十周年了。希望自己下次写博客不要又是三年以后 😛
感觉那个地址的值怎么选至今还是个黑箱,网络上一点资料都没有