Fedora 在树莓派 4 上的 USB 问题的复杂解决方法

更新时间:

上一篇帖子中,我介绍了一种十分简单的解决在树莓派 4B 4GB/8GB 内存型号上运行 Fedora 时无法使用 USB 接口的方法。这种方法通过牺牲可用内存的方式来换取 USB 接口的正常功能。而在现在这篇帖子中,我将再介绍一种方法,虽然需要更多的操作,但是不会导致 3 GiB 内存的限制。

上篇帖子中提到,2GB 内存的型号因为没有 USB 相关的问题,无需进行额外操作。USB 接口不能使用的问题的具体症状也在该帖中有所描述

概括

如果只用一句话总结这个方法的话,那就是让 Fedora 使用 openSUSE(另一个 GNU/Linux 发行版)的引导程序和固件。这其中涉及的步骤包括:

  • 从 openSUSE 中提取文件
  • 将文件复制到安装了 Fedora 的 SD 卡上
  • 修改 openSUSE 的引导配置文件,以允许启动 Fedora

由于我将会提到比较多的细节,帖子的篇幅和内容可能会让您感觉这种方法很费劲,但实际上只有这几个大体步骤而已,并没有那么可怕。

从 openSUSE 中提取文件

下载 openSUSE 映像

要用 openSUSE 的文件之前肯定要先下载 openSUSE。因为只需要几个引导文件和固件,所以建议只下载最基础的 openSUSE Leap JeOS 映像即可。Leap 是 openSUSE 的稳定发行通道,而 JeOS 是不带桌面环境的最小安装,可以减少下载流量和磁盘占用。

截至此帖撰写时,树莓派 4 的最新的 openSUSE Leap JeOS 映像版本是 Leap 15.2。您也可以从 openSUSE Wiki 上下载最新版本。

提取映像

下载下来的文件以 .xz 结尾,意味着它是一个压缩的映像,所以在进行进一步操作前,需要先将其解压。

如果您的系统中安装了 xz 命令的话,可以使用下面的命令解压 openSUSE 的映像:

$ xz -dv openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw.xz

如有需要,请根据您下载的映像版本以及下载路径等因素,相应地修改此帖中提及的命令中的文件名。

这里用到的 -d 选项的意思是使用解压模式。-v 选项是用来让 xz 显示解压进度用的,可有可无。

等到选项执行完成后,解压出来的映像会直接替代原来的 .xz 文件,存储在同一位置,.xz 后缀也会被从文件名中删除。

挂载映像

映像解压完后,就可以将其挂载了,然后就可以将映像里的文件复制出来。openSUSE 的映像里有好几个分区;其中,第一个分区,也就是 EFI 分区,包含您将要复制的引导文件和固件,所以只需挂载第一个分区即可。

您可以任选用来挂载映像的工具,只要能够达成可以从映像中往外复制文件的最终目标就行。下面是在 GNU/Linux 环境中使用 mount 命令挂载映像的方法。

  1. 找出映像中 EFI 分区的偏移量。可以使用 fdisk 命令来间接得出偏移量。

    $ fdisk -l openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw
    Disk openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw: 2.2 GiB, 2353004544 bytes, 4595712 sectors
    Units: sectors of 1 * 512 = 512 bytes
    Sector size (logical/physical): 512 bytes / 512 bytes
    I/O size (minimum/optimal): 512 bytes / 512 bytes
    Disklabel type: dos
    Disk identifier: 0x52b80fee
    
    Device                                                                     Boot   Start     End Sectors  Size Id Type
    openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw1         2048  133119  131072   64M  c W95
    openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw2       133120 1157119 1024000  500M 82 Linu
    openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw3      1157120 4595678 3438559  1.7G 83 Linu
    

    上面是 fdisk 的输出结果。其中,Sector size,也就是扇区大小,是 512 字节;第一个分区的 Start 下的值是 2048,意味着该分区的起始扇区的编号是 2048。扇区号是从 0 开始编的,也就是说如果一个扇区编号为 2048,那么它前面也刚好有 2048 个扇区。因此,映像开头和第一个分区的起始点之间有 512 * 2048 = 1048576 个字节,故得出该分区的偏移量为 1048576。

  2. 创建一个目录。例如 /mnt/tmp,用作映像分区的挂载点。由于一般情况下 /mnt 是需要较高的权限才能写入的,因此如果您要在它下面创建挂载点的话,需要使用超级用户权限执行下面的命令(通常在命令前加 sudo 即可)。

    # mkdir /mnt/tmp
    
  3. 挂载映像,在挂载时指定之前算出的偏移量。这里需要注意的是,mount 命令一般都需要超级用户权限。

    # mount -o loop,offset=1048576 openSUSE-Leap-15.2-ARM-JeOS-raspberrypi4.aarch64-2020.07.08-Build1.35.raw /mnt/tmp/
    

此时就可以在挂载点下访问 EFI 分区的文件了,也可以将它们复制出来,挂载分区的最终目标也就达成了。

$ cd /mnt/tmp
$ ls
bcm2708-rpi-b.dtb       bcm2710-rpi-3-b-plus.dtb  LICENCE.broadcom
bcm2708-rpi-b-plus.dtb  bcm2710-rpi-cm3.dtb       overlays
bcm2708-rpi-cm.dtb      bcm2711-rpi-4-b.dtb       start4.elf
bcm2708-rpi-zero.dtb    bootcode.bin              start.elf
bcm2708-rpi-zero-w.dtb  config.txt                startup.nsh
bcm2709-rpi-2-b.dtb     EFI                       u-boot.bin
bcm2710-rpi-2-b.dtb     fixup4.dat                ubootconfig.txt
bcm2710-rpi-3-b.dtb     fixup.dat

将文件复制到 Fedora SD 卡上

复制文件就很简单了,这里对文件复制的流程也没有特殊要求,只需将 openSUSE EFI 分区中的所有文件和目录都复制到您安装了 Fedora 的 SD 卡上的 EFI 分区即可。如果想使用命令来复制的话,在 SD 卡上的 EFI 分区中运行下列命令:

$ cp -rv /mnt/tmp/* .

此命令中的 -r 选项指定 cp 将子目录也一同复制过来;和之前一样,-v 选项是用来查看进度的可选选项。

截至 Fedora 32 和 Linux 5.8,openSUSE 的 EFI 分区中有一个文件在 Fedora 上是用不了的,那就是 U-Boot 映像 u-boot.bin。如果用了 openSUSE 的 U-Boot 映像的话,Fedora 是无法启动的。作为替代,您可以使用 Fedora 的 rpi4-u-boot.bin:先删除 openSUSE 的 u-boot.bin,然后将 rpi4-u-boot.bin 重命名为 u-boot.bin 即可。

如果想使用命令行的话,删除和重命名这两个操作可以只用一个命令来同时完成:

$ mv {rpi4-,}u-boot.bin

Fedora 33 用户应执行的额外步骤

如果将 Fedora 33 自带的 U-Boot 映像和 openSUSE 的启动文件一起使用,并且在启动树莓派时没有接显示器的话,启动过程就会卡住,必须连上显示器才能继续启动。解决方法很简单,就是在 SD 卡的 EFI 分区内创建一个名为 extraconfig.txt 的文件,然后在文件中填入下面的内容:

hdmi_force_hotplug=1

可以在 SD 卡的 EFI 分区下运行下面的命令来创建此文件:

$ echo 'hdmi_force_hotplug=1' > extraconfig.txt

修改引导配置文件

如果不修改引导配置的话,从 openSUSE 移植到 Fedora 的配置文件会尝试从无效的路径读取文件,导致系统不能启动,因此您需要修改引导配置文件,填入 Fedora 引导文件的路径。

在您的 SD 卡的 EFI 分区下的 EFI/BOOT/grub.cfg 文件中,删除所有已有内容,然后粘贴下列文本。

set prefix=($root)/EFI/fedora
normal

保存文件,安全弹出 SD 卡,插入到树莓派中,然后开机。系统启动后,USB 接口就应该可以使用了。

清理

倘若配置没有问题的话,就可以清理您刚才临时创建的文件了。如果您之前是通过 mount 挂载的 openSUSE 映像,可以使用下面的命令来卸载,然后移除挂载点:

# umount /mnt/tmp
# rmdir /mnt/tmp

已知问题

  • 在 8GB 内存型号上运行 Fedora 32 时,无论您是否已经应用了上述解决方案,系统都只能使用 4 GiB 的内存。此问题是由 Fedora 32 老版本的 U-Boot 映像导致的。Fedora 33 更新了 U-Boot 映像,此问题也随之而解。

参考资料

这帖子基本只是将这篇网页上介绍的解决 USB 接口问题的方法详细地解释了一遍。这个方法背后的大体思路是在该网页中讲解的,但是并没有介绍具体的步骤,于是我填补了这一空白。很惭愧,就做了一点微小的工作。