Skip to content

RV64 板子更换 rootfs 指南

XieJiSS edited this page Feb 8, 2023 · 10 revisions
  1. 请确保你或你的同伴可以在物理上(通过串口)访问到板子。否则,你的板子将在进入第八步时失联。

  2. 首先,以 root 身份回到根目录:

    sudo su
    cd /
  3. 下载 rootfs tarball(确保安装了 wget):

    mkdir new && cd new
    wget https://archriscv.felixc.at/images/archriscv-20220727.tar.zst
    tar -xf archriscv-20220727.tar.zst
    cd ..

    You can also generate your own rootfs tarball using https://github.com/CoelacanthusHex/archriscv-scriptlet/blob/master/mkrootfs

  4. 在根目录创建 old 文件夹:

    mkdir old
  5. 看一下 fstab:

    cat /etc/fstab

    最好拍照或截图备查。

  6. 获取当前的 Linux 内核版本:

    首先,初始化用于从 vmlinuz 提取内核版本的脚本。vmlinuz 一般位于 /boot 目录下,需要 root 权限才能访问。

    kver_generic() {
        # For unknown architectures, we can try to grep the uncompressed or gzipped
        # image for the boot banner.
        # This should work at least for ARM when run on /boot/Image, or RISC-V on
        # gzipped /boot/vmlinuz-linuz. On other architectures it may be worth trying
        # rather than bailing, and inform the user if none was found.
    
        # Loosely grep for `linux_banner`:
        # https://elixir.bootlin.com/linux/v5.7.2/source/init/version.c#L46
        local kver= reader=cat
    
        [[ $(file -b --mime-type "$1") == 'application/gzip' ]] && reader=zcat
    
        read _ _ kver _ < <($reader "$1" | grep -m1 -aoE 'Linux version .(\.[-[:alnum:]]+)+')
    
        printf '%s' "$kver"
    }

    执行 kver_generic /boot/vmlinuz,记住 Linux 内核版本。可以将其赋值给一个临时的 shell 变量,也可以继续拍照记录:

    linux_kver=$(kver_generic /boot/vmlinuz)

    注意,如果你当前的系统没有开启内核压缩,那么可能需要将 vmlinuz 修改为 vmlinux。

  7. 看一下 ip addr 和 router 的地址:

    # 这里 eth0 可能需要按实际情况修改,ip addr show 可以查看全部 device
    # 一般 ip addr show 的第二个 device 就是我们需要的 device(第一个是 lo 本地回环)
    ip addr show dev eth0

    记录 inet 行的 IP 和 IP 后面的掩码后缀,这是你本机当前的 IP 地址。之后会用到,建议拍照或截图留存。

    理论上这步可以删去,随后直接用 dhcp 即可。然而,DHCP 在 PLCT 南京机房网络环境下并不稳定,可能会坏掉。对于 PLCT 内网的机器,建议还是配成静态 IP。

    ip route show dev eth0

    记录 default via 后面的 IP 地址,这个就是你的板子所在局域网的 router 的地址。建议拍照或截图留存。

    如果目标板子不在 PLCT 南京内网,并且你并不理解上述命令的用途:建议在此停下,先和 mentor 讨论清楚网络拓扑再继续。

  8. 开始更换 rootfs:

    1. 几个关键路径:

      /new/lib/    # will be set as the value of LD_LIBRARY_PATH
      /new/lib/ld-linux-riscv64-lp64d.so.1

      在新的 rootfs 并非 Arch Linux 时,可能需要将 /lib 替换为 /usr/lib。原因详见:The /lib directory becomes a symlink - Arch Linux News

    2. 移动文件夹

      mv etc home media mnt opt root srv var old/  # here, we should not delete /boot
      mv new/etc new/home new/mnt new/opt new/root new/srv new/var ./
    3. 继续移动文件夹

      LD_LIBRARY_PATH=/new/lib/ /new/lib/ld-linux-riscv64-lp64d.so.1 /new/bin/mv bin sbin usr lib old/
      LD_LIBRARY_PATH=/new/lib/ /new/lib/ld-linux-riscv64-lp64d.so.1 /new/bin/mv new/bin new/sbin new/usr new/lib ./
      
      mv old/lib/firmware ./lib/

      /lib/firmware 是 Ubuntu on Unmatched 的 firmware 路径,可能需要按实际情况修改。

    4. 把 kernel modules 移动回来

      mv old/usr/lib/modules/$linux_kver ./lib/modules/

      这里的 $linux_kver 是前面「获取当前的 Linux 内核版本」步骤中设置的。

      dtbs、vmlinuz 等均位于 /boot 下。rootfs 的 tar 文件里面并不会包含 dtbs 和 vmlinuz 等文件,但我们可以直接用旧的 /boot 里面提供的文件,这也就是为什么我们之前没有移动 /boot。

    5. 修改 fstab

      echo "LABEL=cloudimg-rootfs  /      ext4     discard,errors=remount-ro       0 1" >> /etc/fstab
      # for systemd-timesyncd:
      echo "LABEL=timesyncd-clock  /var/lib/systemd/timesync/     tmpfs  size=8K,rw,nodev,nosuid,noexec,noatime 0 1" >> /etc/fstab

      注意这里可能需要根据之前看的 fstab 内容来酌情修改第一行,例如,原本是 vfat 的硬盘,你肯定不会希望它被设置成按照 ext4 格式读取。

      第二行的 tmpfs 是因为我们稍后要启用 systemd-timesyncd,但是不希望它太过影响硬盘寿命。如果你不在乎,可以丢掉这行。

    6. 重启机器。

  9. 重启后已经是 Arch Linux 了。检查 fstab 是否配置正确,随后开始配网络:

    echo test > test.txt  # 测试 / 是否被 mount 为 rw
    # mount -o remount,rw /  # 如果上一行报错,则执行这一行,然后停下并联系你的 mentor
    rm test.txt
    
    ip addr add 之前记录下的内网IPv4地址/24 dev eth0
    ip link set eth0 up
    ip route add default via 之前记录下的router地址 dev eth0
    
    # 114.114.114.114 是国内常用的 dns 递归服务器
    # For foreign devs: 1.1.1.1 can be used instead
    echo 'nameserver 114.114.114.114' > /etc/resolv.conf
    
    systemctl start systemd-timesyncd
    
    pacman -Syu --noconfirm
    pacman -Syy vim openssh dhcpcd
    systemctl start sshd.service
    systemctl enable sshd.service
    touch .ssh/authorized_keys  # 受信任的 ssh 公钥,可以使用 vim 编辑
    
    vim /etc/dhcpcd.conf  # 配置样例如下。这里受限于南京内网拓扑,提供的是静态 IP 的配置方案
    # /etc/dhcpcd.conf
    
    interface eth0
    static ip_address=之前记录下的内网IPv4地址/24	
    static routers=之前记录下的router地址
    static domain_name_servers=114.114.114.114

    Again, for foreign devs, consider using 1.1.1.1 instead of 114.114.114.114

  10. 更新内核和 rootfs 自带的其它软件包,随后再次重启。

    pacman -Syu --noconfirm
    # reboot -f,对于 Unmatched 板子可能还需要按 reset 按钮

    跑完 Syu 如果不重启,可能会遇到很多「升级升了一半」导致的问题,例如找不到 kernel module、找不到各种符号等等。