跳转至

os

WSL2 内部实现探究

背景

最近看到 Windows Subsystem for Linux September 2023 update 声称 WSL2 最新的预览版本支持让 Linux 和 Windows 一定程度上共享网络地址空间,就像 WSL1 那样:

  • IPv6 support
  • Connect to Windows servers from within Linux using the localhost address 127.0.0.1
  • Connect to WSL directly from your local area network (LAN)
  • Improved networking compatibility for VPNs
  • Multicast support

因此比较想知道这是怎么做到的,但目前我手上还没有预览版本的 windows,因此目前先研究 WSL2 已有的功能是如何实现的,未来再回来更新这一部分。

Linux 内核格式与启动协议

背景

之前在各种场合遇到过各种 Linux 内核的文件名或格式,例如:

  • vmlinux
  • vmlinuz
  • uImage
  • bzImage
  • uImage

即使是同样的文件名,格式可能也是不一样的,相应的启动协议也可能不一样。这篇博客尝试结合 Linux,各种 Bootloader(QEMU,EDK-II,U-Boot,OpenSBI)的代码来研究不同的 Linux 二进制格式以及启动协议。

在 M1 上运行 Windows ARM 虚拟机

目前 Windows ARM 出了预览版,可以从 Windows Insider Preview Downloads 下载,得到一个 9.5GB 的 vhdx 文件。

接着,用 qemu-img 转换为 vmdk 格式:

$ qemu-img convert Windows11_InsiderPreview_Client_ARM64_en-us_22533.vhdx -O vmdk -o adapter_type=lsilogic Windows11_InsiderPreview_Client_ARM64_en-us_22533.vmdk

转换后,在 VMWare Fusion for Apple Silicon Tech Preview 中,选择从已有的 vmdk 中创建虚拟机,启动前修改一些设置,特别是内存,默认 256MB 肯定不够,默认单核 CPU 也太少了一些。内存不足可能导致安装失败,记住要第一次启动前设置。

启动以后会无法访问网络,按照下面网页里的方法设置网络:

https://www.gerjon.com/vmware/vmware-fusion-on-apple-silicion-m1/

需要注意的是,bcdedit 选项填的 IP 地址一般是 bridge 上的地址,比如 bridge101 的地址。

然后就可以正常工作了!

VMWare 论坛里,还谈到了下面几个问题的解决方法:

为了让声音工作,可以修改 vmx 文件,设置 guestOS:

guestOS = "arm-windows11-64"

这样声音就可以正常播放了。

分辨率的问题,可以用 RDP 来解决:首先在虚拟机里打开 Remote Desktop,然后用 macOS 的 Microsoft Remote Desktop Beta 访问即可。

系统里没有 Microsoft Store,要安装的话,用命令行的 Powershell 执行下面的命令:

wsreset.exe -i

这个方法见 Parallels Desktop KB128520

UPDATE:

VMware Fusion 发布了新版本 22H2,有官方的 Windows 11 on ARM 支持了:

  • Windows 11 on Intel and Apple Silicon with 2D GFX and Networking
  • VMtools installation for Windows 11 GOS on M1
  • Improved Linux support on M1
  • 3D Graphics HW Acceleration and OpenGL 4.3 in Linux VMs* (Requires Linux 5.19+ & Mesa 22.1.3+)
  • Virtual TPM Device
  • Fast Encryption
  • Universal Binary

并且不需要上面写的网卡的 workaround 了:

vmxnet3 Networking Drivers for Windows on ARM

While Windows does not yet ship with our vmxnet3 networking driver for
Windows on ARM as it now does for Intel, the VMware Tools ISO on ARM
contains the 2 currently supported drivers for graphics and networking.

实测安装 VMware Tools 以后,就可以成功用 vmxnet3 网卡上网了,不需要之前的 bcdedit 方案。

但是目前测试 Linux 虚拟机有一些问题,一些内核版本在启动的时候 vmwgfx 驱动会报错,不能正常显示,但是系统是正常启动的,可以通过 SSH 访问。我测试的情况见下:

Linux 5.19.6(5.19.0-1-arm64): 可以正常启动和显示,但是没有 3D 加速(按照 VMware 的说法是需要 5.19 内核 + Mesa 22.1.1 以上,但是我的环境版本已经符合了这个要求,可能是 Debian 打包缺了什么东西);

UPDATE(2022-09-27):更新了一下系统,现在 glxinfo 可以看到 SVGA 了:

Device: SVGA3D; build: RELEASE; LLVM; (0x406)
Version: 22.2.0
Accelerated: no

但是显示有一些 BUG,刷新不正常。

Linux 5.18(5.18.0-0.bpo.1-arm64): VMware Fusion has encountered an error and has shut down the virtual machine

Linux 5.16(5.16.0-0.bpo.4-arm64): SSH 也没启动,看不到内核日志

Linux 5.15.15(5.15.0-0.bpo.3-arm64):

图形界面起不来,可以通过 SSH 访问。

[   10.765945] kernel BUG at drivers/gpu/drm/vmwgfx/vmwgfx_drv.h:1627!
[   10.766206] Call trace:
[   10.766207]  vmw_event_fence_action_queue+0x328/0x330 [vmwgfx]
[   10.766210]  vmw_stdu_primary_plane_atomic_update+0xd8/0x220 [vmwgfx]
[   10.766214]  drm_atomic_helper_commit_planes+0xf8/0x21c [drm_kms_helper]
[   10.766222]  drm_atomic_helper_commit_tail+0x5c/0xb0 [drm_kms_helper]
[   10.766225]  commit_tail+0x160/0x190 [drm_kms_helper]
[   10.766227]  drm_atomic_helper_commit+0x16c/0x400 [drm_kms_helper]
[   10.766230]  drm_atomic_commit+0x58/0x6c [drm]
[   10.766242]  drm_atomic_helper_set_config+0xe0/0x120 [drm_kms_helper]
[   10.766245]  drm_mode_setcrtc+0x1ac/0x680 [drm]
[   10.766249]  drm_ioctl_kernel+0xd0/0x120 [drm]
[   10.766253]  drm_ioctl+0x250/0x460 [drm]
[   10.766257]  vmw_generic_ioctl+0xbc/0x160 [vmwgfx]
[   10.766261]  vmw_unlocked_ioctl+0x24/0x30 [vmwgfx]
[   10.766264]  __arm64_sys_ioctl+0xb4/0x100
[   10.766287]  invoke_syscall+0x50/0x120
[   10.766300]  el0_svc_common.constprop.0+0x4c/0xf4
[   10.766302]  do_el0_svc+0x30/0x9c
[   10.766303]  el0_svc+0x28/0xb0
[   10.766327]  el0t_64_sync_handler+0x1a4/0x1b0
[   10.766328]  el0t_64_sync+0x1a0/0x1a4

回收硬盘空间:

sudo vmware-toolbox-cmd disk shrink /

给 Rocket Chip 挂接串口外设

前言

最近在给 rCore 添加 Rocket Chip 支持。下面讲讲最近做了哪些工作,遇到了哪些坑,都是怎么解决的。

踩坑过程

Rocket Chip 运行代码

首先分析了一下已有的代码和工作方式,这个 Rocket Chip(ucb-bar/fpga-zynq)的设计大概是这样的:在 PS 上通过 fesvr 向 Rocket Chip 写入程序。Rocket Chip 本身暴露出一个 TSI,一个串口的调试接口,通过 Zynq Adapter 挂到了 PS 下的 AXI 总线,暴露出若干个寄存器,大概如下:

  /**
   * Address Map
   * 0x00 - serial out FIFO data
   * 0x04 - serial out FIFO data available (words)
   * 0x08 - serial in  FIFO data
   * 0x0C - serial in  FIFO space available (words)
   * 0x10 - system reset
   * 0x20 - req FIFO data
   * 0x24 - req FIFO data available (words)
   * 0x28 - data FIFO data
   * 0x2C - data FIFO data available (words)
   * 0x30 - resp FIFO data
   * 0x34 - resp FIFO space available (words)
   * 0x38 - nsectors
   * 0x3C - max request length
   */

前面的是调试接口,后面的是 block device 和 network,我们暂时还没有用到这些 UCB BAR 做的私货。在 Vivado 中,地址 Offset 是 0x43C00000,所以代码中就这样访问对应的物理地址:

#define ZYNQ_BASE_PADDR 0x43C00000L

fd = open("/dev/mem", O_RDWR|O_SYNC);
assert(fd != -1);
dev = (uint8_t *) mmap(
  0, sysconf(_SC_PAGESIZE),
  PROT_READ|PROT_WRITE, MAP_SHARED, fd, ZYNQ_BASE_PADDR);
assert(dev != MAP_FAILED);

这块地址在 Device Tree 里也有对应的项,于是 PS 在访问的时候就会找到总线上的 Rocket Chip 的 Slave,也就对应到了上面的那个寄存器的 Map。接着就是由 fesvr 向 Rocket Chip 里写程序,然后跑起来了。

OpenSBI 输出

接着就需要先把输入输出做起来,需要移植一个 bootloader。相比之下,OpenSBI 明显比 bbl 更适合于这个用途,于是拿着 OpenSBI 就拿来改了。考虑到 fesvr 采用的是 htif 进行输入输出,于是从 bbl 里抄了相关代码过来,得到了正确的输出:

rCore,启动!

接下来,就想着怎么把 rCore 丢进去跑。把 payload 替换掉,丢进去,gg 了。一直出现一个玄学的问题,只要我修改页表,就出现 instruction access fault。也一直没有找到真实的原因,最后把 PMP 保护关了就好了。。怀疑是 Rocket Chip 实现有误。

又做了一些小的修改和适配,用户态也可以正常跑起来了。但是,现在串口只能轮询读取,而 htif 是通过读写内存进行的,也没有类似 MSI 的机制(现在想了想,其实可以,给 PS 挂一个 AXI Interrupt Controller,采用软件产生中断模式,然后接到 Rocket Chip 上,其实也是可以的),另外 Rocket Chip 原来的 Config 还没有向外暴露中断,我想挂一个串口也得让 Rocket Chip 访问得到。于是就开始了阅读 Chisel 代码然后魔改的过程了。

魔改 Rocket Chip

其实算不上魔改,克服了对 Rocket Chip 的恐惧,仔细阅读代码以后,发现还是比较容易理解的。譬如,我要添加一个外部总线,只需要添加一句:

  case ExtBus => up(ExtBus, site).copy(idBits = 6)

那么对应地,就多了一片地址映射:

60000000 - 80000000  RWX  mmio-port-axi4@60000000

意味着,只要我在 Rocket Chip 里访问这片地址,那么就会访问这个 AXI 总线上的外设了。但是事情没有这么简单,在踩了很久的坑以后才最终解决。。

AXI 总线地址的计算方式

首先谈谈 AXI 总线上地址是怎么计算的。AXI 总线是一个星形结构,一个 Master 多个 Slave,在这里出现的例子是:

  1. PS 是 Master,Rocket Chip 是 Slave — 刚才谈到过的那片 register space
  2. Rocket Chip 是 Master,PS 是 Slave — 让 Rocket Chip 访问 DDR 控制器
  3. Rocket Chip 是 Master,外设 是 Slave — 这就是现在要做的事情

之前省略没说的是上面的第二点,就是让 Rocket Chip 也可以拿到内存用。那问题来了,怎么让 Rocket Chip 和 ARM 上的 Linux 不要打架?把地址空间分成两块就好了:

wire [31:0] mem_araddr;
wire [31:0] mem_awaddr;

// Memory given to Rocket is the upper 256 MB of the 512 MB DRAM
assign S_AXI_araddr = {4'd1, mem_araddr[27:0]};
assign S_AXI_awaddr = {4'd1, mem_awaddr[27:0]};

这样做,就透明地把 Rocket Chip 看到的内存空间都映射到了实际内存的 [256MB, 512MB) 这片空间上了。

注:我实验用的板子实际上有 1GB 的 DRAM,但实际上已经足够用了,所以就没有改原来 zedboard 的配置。

我在前面也提到,在 PS 上访问 0x43C00000 就是对应了 Zynq Adapter 的 0x0 地址。这里也是,在 Rocket Chip 上访问 0x0 的地址,我强行改成了 0x10000000,然后 Offset 是 0,所以最后到内存就是 0x10000000 的地址了。

所以 AXI 总线上 Slave Register 的地址 = Master 地址 - 匹配到的 Slave 的 Offset 地址。但是,如果只有单个 Slave 的时候,AXI Interconnect 可能不检查地址范围,而是直接截断,但在有多个 Slave 的时候,会先检查地址范围,如果找不到就返回错误。这个问题让我困惑了许久,直到我挂上了 System ILA 看。。

AXI Uartlite

既然有了外设总线,第一个想到的外设就是 UART 咯,于是加了一个 AXI Uartlite,用 AXI Interconnect 连到外设总线上。写了程序简单测试了一下,确实读取到了数据,然后也很快就可以成功地从串口读数据,写数据。于是我又加了一个串口,拉到 AXI Interconnect 第二个接口上,结果就不工作了。

细心的读者可能已经从我上面讲到的一些内容上猜到了问题所在。。但这一点直到后面我才明白发生了什么,后面会再讲到这里的问题。

AXI Interrupt Controller

接着,回到我们最初的目标,既然可以输入输出了,还要真的串口干啥?添加中断或者拉一路 JTAG 出来,脱离 PS 来进行调试。所以接下来需要从 Rocket Chip 中暴露外部中断。在原来的代码中,是直接关掉了的:

target.tieOffInterrupts()

它的功能很简单,直接把中断置 0。但我要的是拉到外面,经过了一番挣扎:

val io = IO(new Bundle {
    val ps_axi_slave = Flipped(adapter.axi.cloneType)
    val mem_axi = target.mem_axi4.head.cloneType
    val mmio_axi = target.mmio_axi4.head.cloneType
    val interrupts = Input(UInt(2.W))
})

io.mem_axi <> target.mem_axi4.head
io.mmio_axi <> target.mmio_axi4.head
target.interrupts := io.interrupts

终于找到了正确的方法,拉出来两路中断信号。于是很开心地直接接到了 Uartlite 上,但是事情肯定不会这么简单:

Uartlite 是正边沿触发的中断,但是 Rocket Chip 期望的是高电平触发的中断。所以我们需要一个中断控制器来实现这个,加了一个 AXI Interrupt Controller。但是问题来了,我们还没解决那个只要加俩 Slave 就都访问不到的问题呢!于是到处挂 System ILA 调试,发现了问题所在:

我们之前提到,0x60000000 - 0x80000000 地址段是对应到了外部 AXI 总线的,这没错,但是,如果在 Rocket Chip 上读 0x60000000 的地址,到总线上还是 0x60000000 的地址而不是 0x0,而之前只有一个 Slave 的时候,没有真的去检查这个地址范围,所以找到了正确的寄存器,现在不行了,于是出错了。

解决方法也很简单,乖乖地把 Offset 调成 0x60000000 和 0x61200000,然后再映射到 rCore 的内核态里。一番挣扎,又参照了 Linux 的 Uartlite 驱动(发现了遗忘设置的 MER 寄存器,不认真阅读文档的后果),终于在 ILA 上看到 uartlite 的输出上有一个脉冲,紧接着看到中断控制器输出了一个 irq,然后 Rocket Chip 收到了 external interrupt。Cheers!

中断处理

事情虽然差不多解决了,但是还没有结束。收到了一个 interrupt 以后,打印了一下寄存器状态,马上又来下一个 interrupt 了。现在不仅要在 Rocket Chip 的 PLIC 上把中断给确认了(吐槽一下,Rocket 的 PLIC 文档也比较欠缺,我是照着 U54 核的地址找到,但是 U54 呢是一个 4+1 的组合,hart0 没有 M 态,所以我为了打开 hart0 的 S 态中断,要找 hart1 的 M 态地址,详见 SiFive 文档),在 AXI Interrupt Controller 上也得把中断给确认了。但还是不行,每次 interrupt controller 输出的 irq 拉低不久,uartlite 又出现了新的一次中断。

这次的问题很有戏剧性:处理中断的时候输出调试信息,调试信息把 tx fifo 写满了,uartlite 也会产生一个中断。。于是没完了。解决方法很简单,牺牲一些性能,每次输出的时候都等到 tx fifo 空了才写,然后在处理串口中断的时候不要输出调试信息。

这下没有新的问题了,串口中断终于是工作了。

总结和致谢

这么一番搞下来,对 Vivado 和 AXI 的相关知识都比较熟悉了吧,也踩了很多的坑。需要特别感谢 @cq_z4yx 提供的技术支持。

相关文档和链接:

  1. PG099 AXI Interrupt Controller
  2. PG142 AXI Uartlite
  3. OpenSBI 适配
  4. rCore 适配

在 macOS 的 VirtualBox 上从 USB 启动

做了一个 Windows 10 安装 U 盘,想测试一下能不能启动,于是想用 VirtualBox 起一个虚拟机。但是发现,一般情况下要从 ISO 或者把 U 盘克隆成一个 vdi/vmdk etc 再启动。不过找到了 Cem Arslan 的 VirtualBox - Booting From USB (MAC) 实验了一下,确实可以用,以 /dev/disk2 为例方法如下:

$ diskutil unmountDisk /dev/disk2
$ sudo chown $(whoami) /dev/disk2
$ VBoxManage internalcommands createrawvmdk -filename PATH_TO_VMDK -rawdisk /dev/disk2
$ # Now boot from VirtualBox

对于其它平台,可以参考 Tu Nguyen 的 How to boot from USB in VirtualBox

研究了一下生成的 vmdk 文件,大概是这样的:

# Disk DescriptorFile
version=1
CID=12345678
parentCID=ffffffff
createType="fullDevice"

# Extent description
RW 12345678 FLAT "/dev/disk2" 0

# The disk Data Base 
#DDB

ddb.virtualHWVersion = "4"
ddb.adapterType="ide"
ddb.geometry.cylinders="1234"
ddb.geometry.heads="1234"
ddb.geometry.sectors="1234"
ddb.uuid.image="12341234-1234-1234-1234-123412341234"
ddb.uuid.parent="00000000-0000-0000-0000-000000000000"
ddb.uuid.modification="00000000-0000-0000-0000-000000000000"
ddb.uuid.parentmodification="00000000-0000-0000-0000-000000000000"
ddb.geometry.biosCylinders="1234"
ddb.geometry.biosHeads="1234"
ddb.geometry.biosSectors="1234"

更改 macOS 屏幕亮度的按键

由于我打开了「Invert Fn」功能,所以需要调亮度的时候,是采用 Fn+F1/F2 的方法。但是,我的机械键盘则是,不按 Fn 时为 1-9,按着 Fn 时为对应的 F1-F9,但是就无法调整亮度和声音了。

然后捣腾了一下,发现可以用 ScLk 和 Pa/Br(名称在各个键盘上不大一样)调整亮度。不过,还没发现如何更改音量。。。

构建简易的 initramfs

一直对 Linux 的启动很感兴趣,但对 initrd 和 initramfs 等概念不大了解,于是上网找了资料,自己成功地看到了现象。

参考资料:

具体步骤:

$ cat hello.c
#include <stdio.h>
#include <unistd.h>

int main() {
    for (;;) {
        printf("Hello, world!\n");
    }
}
$ gcc -static hello.c -o init
$ echo init | cpio -o -H newc | gzip > initrd
$ qemu-system-x86_64 -kernel /boot/vmlinuz-linux -initrd initrd -nographic -append 'console=ttyS0'
# Use C-a c q u i t <Enter> to exit

可以看到过一会(三四秒?),可以看到满屏的 Hello world 在输出。

向 Nexus 6P 中刷入 LineageOS 实践

Nexus 6P 自带的系统没有允许 Root,所以需要自己解锁 bootloader 并且刷上别的系统。我选择了 LineageOS。Nexus 6P 的代号为 angler,首先可以找到官方的安装教程

我们需要下载的东西:

$ wget https://mirrorbits.lineageos.org/full/angler/20180521/lineage-15.1-20180521-nightly-angler-signed.zip
$ wget https://mirrorbits.lineageos.org/full/angler/20180521/lineage-15.1-20180521-nightly-angler-signed.zip?sha256 -O lineage-15.1-20180521-nightly-angler-signed.zip.sha256
$ wget https://mirrorbits.lineageos.org/su/addonsu-15.1-arm64-signed.zip
$ wget https://mirrorbits.lineageos.org/su/addonsu-15.1-arm64-signed.zip?sha256 -O addonsu-15.1-arm64-signed.zip
$ wget https://github.com/opengapps/arm64/releases/download/20180527/open_gapps-arm64-8.1-full-20180527.zip
$ wget https://github.com/opengapps/arm64/releases/download/20180527/open_gapps-arm64-8.1-full-20180527.zip.md5
$ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img
$ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img.asc
$ wget https://dl.twrp.me/angler/twrp-3.2.1-0-angler.img.md5
$ gpg --verify *.asc
$ md5sum -c *.md5
$ sha256sum -c *.sha256

其中 Open GApps 可以自己考虑选择 full 还是其它的选择。

接下来,按照教程,先解锁 bootloader。连接手机,进入 USB Debugging Mode,重启进入 bootloader 并且解锁:

$ adb reboot bootloader
$ fastboot flashing unlock
# Confirm unlocking, and then the data should be wiped

接下来刷入 TWRP。还是进入 bootloader,然后刷入。

$ fastboot flash recovery twrp-3.2.1-0-angler.img
# Select recovery, and enter it

进入 TWRP 后,把我们刚刚下载的 zip 文件都 push 到手机上,并用 TWRP 安装:

# Select Wipe -> Advanced Wipe, Select Cache, System and Data and wipe then
# Install lineageos, opengapps, addonsu and follow on-screen instructions
# Reboot into system

经过一段时间的等待,LineageOS 就安装成功了。但是遇到了一些问题:

  1. 开机时提示 vendor image 版本与打包 LineagesOS 时采用的版本不同。 于是我下载了官方的 factory image,找到其中的 vendor.img,用 TWRP 刷到了 vendor 分区中。并且执行了 flash-bash.sh 更新 bootloader 和 radio。重启的时候这个错误就解决了。2018-06-12 更新 注意:不要下载 Driver Binaries 里面的 vendor, 刷上去系统还是提示版本 mismatch,建议还是下载完整的 factory 镜像。
  2. 检测不到 SIM 卡。 回到 bootloader 看 Barcode, 是有 IMEI 等信息的,说明分区没有被写坏。在网上搜索一段时间以后,发现禁用登录密码重启一次后即可使用,之后把密码加回来即可。

在 WSL 上开启一个 getty 到串口的方法

为了测试一个硬件的 terminal,想在 Windows 上向串口开一个 tty,跑各种软件来测试。这件事情在 Linux 上和 macOS 上都有实践,但一直不知道 Windows 上怎么搞。经过了一番搜索,找到了 https://blogs.msdn.microsoft.com/wsl/2017/04/14/serial-support-on-the-windows-subsystem-for-linux/ 和 https://unix.stackexchange.com/a/123559 的方案。

以 COM5 为例:

$ sudo chmod 666 /dev/ttyS5
$ sudo agetty -s 115200 ttyS5 linux

这样就可以看到一个登录的界面了。

在 macOS 上 (https://superuser.com/questions/1059744/serial-console-login-on-osx):

$ screen /dev/tty.SLAB_USBtoUART 115200
# type C-b : exec ::: /usr/libexec/getty std.115200

体验 Fedora on RISCV

看到 RISCV 很久了,但一直没能体验。最近工具链不断更新,QEMU 在 2.12.0 也正式加入了 riscv 的模拟。但是自己编译一个内核又太麻烦,就找到了 Fedora 做的 RISCV port,下载下来试用了一下。之前试过一次,但是遇到了一些问题,刚才总算是成功地搞出来了。

官方文档地址:https://fedorapeople.org/groups/risc-v/disk-images/readme.txt 首先下载 https://fedorapeople.org/groups/risc-v/disk-images/ 下的 bbl vmlinux 和 stage4-disk.img.xz 三个文件,然后解压 stage4-disk.img.xz,大约有 5G 的样子。之前作者在脚本里作死开得特别大,导致我以前光是解压这一步就成功不了。现在终于解决了。

然后启动 qemu 命令打开虚拟机:

qemu-system-riscv64 \
  -nographic \
  -machine virt \
  -m 2G \
  -kernel bbl \
  -object rng-random,filename=/dev/urandom,id=rng0 \
  -device virtio-rng-device,rng=rng0 \
  -append "console=ttyS0 ro root=/dev/vda" \
  -device virtio-blk-device,drive=hd0 \
  -drive file=stage4-disk.img,format=raw,id=hd0 \
  -device virtio-net-device,netdev=usernet \
  -netdev user,id=usernet,hostfwd=tcp::10000-:22

这段命令摘自 readme.txt,区别只在于把 -smp 4 去掉了。不知道为什么不能正常工作,可能和作者提到的 FPU patch 有关。然后系统就可以正常起来了(firewalld 和 systemd-logind 不止为啥起不来,但是不用管)。

可以验证一下我们的系统:

$ uname -a
Linux stage4.fedoraproject.org 4.15.0-00046-g48fb45691946 #27 SMP Mon May 14 08:25:14 UTC 2018 riscv64 riscv64 riscv64 GNU/Linux