——甚至任何发行版的镜像

准备工作:

  1. 耐心
  2. 一杯咖啡
  3. 一块板子和一条串口调试线,至少16G的任何品牌的 sdcard
  4. 能熟练操作的一个 Linux 发行版(推荐 Archlinux 或者 Ubuntu)
  5. 大致了解如何利用 qemu 和 binfmt 创建 RISC-V 模拟运行环境(推荐阅读
  6. 大致了解如何创建块设备(推荐参考的一篇文章:losetup创建块设备,或者利用 zfs 创建块设备,我更习惯后者,后面的内容会以 zfs 文件系统为例,但实际操作中,仅仅是创建块设备不同,挂载无异)
  7. 大致了解如何创建一个 RISC-V 交叉编译环境(推荐阅读
  8. 大致了解如何使用简单的 systemd-nspawn 容器(推荐阅读)或者 chroot(推荐阅读
  9. 大致了解 StarFive VisionFive V1 的启动流程(推荐阅读,不想阅读的朋友等等我的视频)
  10. 觉得以上准备好烦,就是想白嫖的朋友只有等我的视频连载吧

第一部分:编译、打包内核,创建 deb 源:

创建一个StarFive VisionFive V1 的 RISC-V 内核尤为重要,截止本文完稿,主线内核 5.16 还没有对 StarFive VisionFive V1 的 dts 和 deconfig 提供支持,预计 5.17 能进入主线了, 所以目前我们需要使用 5.17 的发布候选版本,就是 RC 版本进行编译和构建。完整流程如下:

#Debian 或者 Ubuntu

#Debian 安装依赖:
apt install libncurses-dev libssl-dev bc flex bison gcc-riscv64-linux-gnu build-essential ccache cpio fakeroot flex git kmod libelf-dev libncurses5-dev libssl-dev lz4 qtbase5-dev rsync schedtool wget zstd pahole dwarves -y

#Ubuntu 安装依赖:
apt install libncurses-dev libssl-dev bc flex bison gcc-riscv64-linux-gnu build-essential ccache cpio fakeroot flex git kmod libelf-dev libncurses5-dev libssl-dev lz4 qtbase5-dev rsync schedtool wget zstd dwarves -y

#下载源码:
#可以从这个地址下载内核,但是不要从 releases 下载。大家最好下载最新的 commits,在这里#我提供一个下载地址:https://github.com/starfive-tech/linux

mkdir -p linux-build
#创建编译目录

cd linux-build
#进入目录

wget https://github.com/starfive-tech/linux/archive/54fad564dc7a117704e99248c3984f907e1867d5.tar.gz
#下载特定 commits 的内核源码,大家根据你当天最新 commits 下载。

tar -xpvf 54fad564dc7a117704e99248c3984f907e1867d5.tar.gz
#解压源码

mv linux-54fad564dc7a117704e99248c3984f907e1867d5 linux-5.17.0-rc5
#给解压出来的源码目录改一个简单的名字

cd linux-5.17.0-rc5
#进入该目录

cp arch/riscv/configs/starfive_jh7100_fedora_defconfig .config
#复制内核配置文件到内核源码根目录下,并取名为 .config

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- menuconfig
#利用交叉编译工具链具体再配置内核

make ARCH=riscv CROSS_COMPILE=riscv64-linux-gnu- -jX bindeb-pkg LOCALVERSION=-starfive-xxx
#-jX 有多少线程都可以利用上,最后那里是去个你喜欢的名字
#等待编译完成。完成后会在上一层目录生成4个deb文件,类似下图:

这4个 deb 文件中,其实我们只需要3个就足够了,一个是 linux-headers ,一个是 linux-image 。我们现在知道这三个文件放在你的家目录的 linux-build 目录下。下面我们看看如何用 Arch 构建:

Archlinux 或者其他发行版,可以用类似的方法
下面谈到一些小的技巧,关于文件系统的:

1. 假设你使用 btrfs 文件系统,在 /mnt/ 目录下可以创建一个子卷,在子卷下编译,后续还能打个快照,做做备份;

2. 假设你使用 zfs 文件系统,建议使用 zvol 块设备,格式化成 ext4 文件系统,挂载到 /mnt/xxx/ 目录下,构建和打包。原因也同样是方便备份和做克隆,抑或是快速部署。

备份的理由是因为我前前后后用过三个版本的 Debian Sid/unstable 的 gcc 交叉编译工具链构建,第一次成功,过了一周编译失败了,因为 gcc 更新后引入了一个 bug ,需要打补丁,这个时候如果我有上一个版本的备份就直接 rollback 去构建和打包,就不影响后面的操作了。所以,养成备份和克隆的习惯很重要。下面我们假设你在 Archlinux 或者其他的发行版上已经在 /mnt/xxx/ 目录下有子卷或者块设备了,直接开始~

#以下操作默认在 root 权限进行

pacman -S yay #安装我喜欢的 yay
pacman -S paru #安装你们喜欢的 paru

#以上操作二选一

yay -S debootstrap debian-archive-keyring ubuntu-keyring
#安装 debian 系一些重要工具,debootstrap 可以将各种架构的 base system 安装到指定目录,后面的 keyring 目的是提供密钥,用于验证 deb 包是否被篡改。

debootstrap unstable /mnt/xxx https://mirror.sjtu.edu.cn/debian/
#从上海交大 debian 镜像源下载最新的 debian sid base system 并且安装到 /mnt/xxx 目录
debootstrap impish /mnt/xxx https://mirror.sjtu.edu.cn/ubuntu/
#从上海交大 ubuntu 镜像源下载最新的 ubuntu 21.10 base system 并且安装到 /mnt/xxx 目录

systemd-nspawn -D /mnt/xxx/ -M kernel --bind-ro=/etc/resolv.conf
#利用 systemd-nspawn 创建 名为 kernel 的 debian/ubuntu x86_64 base system 容器

#后续的操作可以参考上面 Debian 和 Ubuntu 的操作。完成之后,你需要记住打包好的 deb 包所在的位置,你可能需要使用 root 权限去将这些 deb 复制到你方便操作的目录下等待下一步操作。

完成内核编译打包,不要高兴太早。

注意在内核源码目录下把 StarFive VisionFive V1 的 dtb 文件复制出来到你记得的目录。这个 dtb 所在的目录是 <内核源码>/arch/riscv/boot/dts/starfive/ 下。大家一定记住。

下面继续,针对安装内核 deb 有两种操作方法,我更推荐第二种。第一种简单,但是不清真,就是后续将编译打包好的 riscv 内核复制到将来的系统中,直接安装,命令是:dpkg -i xxx.deb ;第二种方法,我更愿意叫它是 Debian/Ubuntu 安装软件的“原教旨主义”,就是通过架设我们的私有的 RISC-V deb 源,这样的好处是,可以让你身边有需求的朋友,完全按照 Debian/Ubuntu 系的传统,安装你做好的内核,并且能够维护这个内核版本,以方便他们后续更新使用。我们来谈架设 Deb 源。

选择合适的服务器:

如果是公司内部,可以选择在 NAS 上创建一个 Ubuntu 的虚拟机,然后将网络映射到你们公司局域网中,让所有人都能正常访问;

如果是像我这种,我选择XX云,建立一个 Ubuntu 的 VPS 作为 deb 源服务器。好的,现在假设 VPS 或者你的虚拟机已经创建好了。开始在 VPS 上操作吧。

apt install reprepro --yes
#安装 reprepro ,deb 发布器

ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 
hwclock --systohc
apt install ntpdate
ntpdate -s time.nist.gov
#以上操作的目的是将 VPS 或者虚拟机的时间同步到标准北京时间,防止时间不匹配,无法安装和更新软件

gpg --gen-key
#生成你的密钥,后续 deb 包都会用这个私钥签名,其他机器需要下载你的公钥,用于验证

上图就是生成的密钥,用 gpg --list-keys 可以显示出来。注意那一长串字符:706CE3DD… ,记下最后8位:33372332它们有重要作用,别问我怎么知道的,哈哈哈哈~

apt install apache2 -y
#安装一个你会操作的 web 服务器,我比较习惯 apache

下面去 web 服务器目录下创建目录:

mkdir -p /var/www/html/ubuntu-impish
cd /var/www/html/ubuntu-impish
mkdir -p conf db dists pool
touch conf/distributions
#distributions 描述性文件
touch conf/options
#options 描述仓库的一些选项

#注意 ubuntu-impish 这个是名字,大家喜欢什么名字可以随便一点,根据你们的需要自由处理。

下面来配置 distributions :

Origin: ubuntu
Suite: impish
Label: ubuntu
Codename: impish
Architectures: riscv64
Components: main
Description: Apt repository for StarFive VisionFive V1
SignWith: 33372332

上面的内容我来解释一下:

  • Origin 如果你是 Debian,就写 Debian,如果是 Ubuntu ,就写 Ubuntu
  • Suite 写成你的发行版的代号
  • Label 类似 Origin
  • Codename 就是发行版代号
  • Components 这个是组件,因为我们只是满足小范围的朋友使用,main 就够了,如果是严格的维护,最好详细分类
  • 描述部分大家自由发挥
  • SignWith 这里是签名,还记得你的那8位密钥吗?😁😁😁

下面导出我们的公钥到源目录:

gpg --export --armor 33372332 > /var/www/html/ubuntu-impish/gpg-public.key
#再次强调那个8位密钥

上图就是创建后的大致样子。

下面就可以来发布或者撤销你创建好的内核 deb 包了:

reprepro -b /var/www/html/ubuntu-impish -C main includedeb impish /<你之前编译并打包好的 deb目录>/*.deb
#这是发布你的 deb 包,这时候会弹出一个 TUI ,你在里面输入密码(gpg 创建密钥对时输入的密码)

reprepro -b /var/www/html/ubuntu-impish -C main remove impish <deb 的包名>
#从仓库移除或者撤销 deb 包

如果一切顺利,你的私有 deb 仓库就创建好了。好好维护吧~

第一部分小节:

  • 内核编译打包推荐交叉编译速度快
  • 记得 dtb 要复制出来,方便最后处理;
  • 构建出来的 deb 包强烈推荐使用传统的架设源服务器管理

第二部分:创建块设备,分区,创建 RISC-V 的 Debian base system

现在无论任何一个发行版,安装 zfs 的树外内核模块都非常方便了,下面以我自己的习惯来创建块设备。如果各位不会使用 zfs 文件系统,也没关系,利用 losetup 创建 .img 文件,作为块设备也是一样的。虽然 zfs 更加“科学”,笑死笑死~

#一下内容均在 root 权限下操作:

zfs create -V 10G root/Container/starfive-lxde
#在 root/Container/ 池下,创建一个名字叫做 starfive-lxde 块设备,大小是10G(10G 对于 Debian/Ubuntu 都够了,但是对于 Gentoo 是不够的,Gentoo 需要120G) 

cfdisk -z /dev/zvol/root/Container/starfive-lxde
#对该块设备进行分区,分区的样子类似下图:

格式化上面的三个分区:

  • 注意第一个分区是空分区;
  • 第二个分区,格式化成 vfat ,不用取 label 名字;
  • 第三个分区,格式化成 ext4,label 取名字叫做:_/boot
  • 第四个分区,格式化成 ext4,label 取名字叫做:_/

在 /mnt 目录下创建一个目录,我这里就叫做:Starfive,即 /mnt/Starfive

开始一些列操作来挂载块设备到目录到 /mnt/Starfive ;

mount -t ext4 /dev/zvol/root/Container/starfive-lxde-part4 /mnt/Starfive
mkdir -p /mnt/Starfive/boot
mount -t ext4 /dev/zvol/root/Container/starfive-lxde-part3 /mnt/Starfive/boot
mkdir -p /mnt/Starfive/boot/efi
mount -t vfat /dev/zvol/root/Container/starfive-lxde-part2 /mnt/Starfive/boot/efi

挂载完成后,可一运行 lsblk 查看下,结构类似下图:

利用 debootstrap 安装 RISC-V 的 Debian base system 到 /mnt/Starfive 下:

debootstrap --arch=riscv64 --keyring /usr/share/keyrings/debian-ports-archive-keyring.gpg --include=debian-ports-archive-keyring unstable /mnt/Starfive https://deb.debian.org/debian-ports/

解释一下:

  • –arch=riscv64 这里强调了架构,是 riscv64 的;
  • –keyring 这里需要大家去单独下载一个 deb 包,我已经不记得 debian 和 ubuntu 的源里是否包含,不包含可以下载这个包,下载后解压 deb 提取 debian-ports-archive-keyring.gpg 这个文件放到我上面这个目录下;
  • –include 在 base system 保重,添加特定的包,debian-ports-archive-keyring 包是密钥包,添加一下避免后续万一缺少密钥什么麻烦
  • 目前 RISC-V 架构并不在稳定版本 Debian 的支持中,比方说现在的 Debian 稳定版是 Debian 11,它是不支持 RISC-V 的,所以我们只能用不稳定版本 Sid/Unstable,如果你在某些网站看到 RISC-V 是稳定分支,那是宣传,并不是真实情况。
  • /mnt/Starfive 是目录,现在已经挂载好块设备了
  • https://deb.debian.org/debian-ports/ 是下载 deb 包的地址(这是官方源,建议不要用镜像,偶尔因为同步问题,会出现文件校验不匹配)

根据各位的网速,完成 base system 的部署。

第二部分小节:

  • 用你们习惯的方法创建块设备;
  • 习惯去备份,避免重复劳动,节约时间;
  • 掌握 debootstrap 的命令,可以看看 help 的输出,多尝试总不会有错。

第三部分:完善基础系统,准备 /boot 目录必要文件,为开发板最后启动做准备

Debian/Ubuntu 创建 RISC-V 模拟环境

#以下内容均在 root 权限下完成

apt install qemu-user-static binfmt-support -y
#安装 qemu binfmt 创建模拟环境

Archlinux 或者其它发行版创建 RISC-V 模拟环境

大家参考这段 Archlinux wiki 就可以了,我就不班门弄斧了。

随后我们就可以直接用 systemd-nspawn 进入容器开始后续的操作。

#一下内容均在 root 权限下完成

systemd-nspawn -D /mnt/Starfive -M starfive --bind-ro=/etc/resolv.conf
#启动名字为 starfive ,根目录在 /mnt/Starfive 的 Debian RISC-V 容器。

apt update; apt dist-upgrade -y
#更新系统

apt install curl gnupg2 gnupg vim nano initramfs-tools -y
#安装必要的工具,编辑器,为后续生成 initramfs 镜像做准备。

curl -s http://<内核私有源的地址>/xxx/gpg-public.key | apt-key add -
#添加内核私有源的公钥到 apt-key 中,我记得 ubuntu 和 debian 这里略有不同,大家根据不同发行版再搜索下方法。

deb http://<内核私有源的地址>/xxx unstable main
#添加私有源的地址到 /etc/apt/sources.list 中

apt update; apt install <你私有源中内核的名字,切记 linux-headers linux-image 都安装>
#刷源,安装私有源内核

这个时候你的 /boot 目录下应该是这样的:

大家可以从这里下载最早创建的 Fedora 镜像中的启动必要的文件,你可能会问,为什么 Debian/Ubuntu 下不能根据自己的发行版创建?其实原因是开发板的 uboot 读取的配置文件和目前 .efi 文件所决定的,我们按部就班就可以了。

下面我们就需要将 Fedora 原始镜像中文件复制到 Debian/Ubuntu 的 /boot 目录下,做适当修改就可以了。

将 boot 文件夹(从上面下载的压缩包解压出来以后,你会看到)复制到Debian/Ubuntu boot目录下。

那么目前 Debian/Ubuntu 的 /boot 目录下就还有一个 boot 文件夹,里面有一个叫做 uEnv.txt 的文件,大家可以用常用的编辑器打开,将 Fedora 修改成 Debian 。类似下面两张图所示:

完成后我们来复制 EFI 文件夹(压缩包里可以见到),将这个 EFI 文件夹完整复制到 Debian/Ubuntu 的 /boot/efi/ 目录下,你可将 EFI 文件夹里的 fedora 删掉,当然保留也可以,作为一个备份。

将编译内核那个部分生成的 dtb 复制到你的 Debian/Ubuntu 的 /boot/ 目录下。

将压缩包中的 extlinux 目录还有 grub.cfg 也复制到 Debian/Ubuntu 的 /boot 目录下,用编辑器对 extlinux 里面的配置文件和 grub.cfg 进行修改,修改的内容包括 kernel 对应的 vmlinuz 文件名,fdt 对应的 dtb 文件,initd 对应的 initramfs 镜像,UUID值,你可以重新打开一个终端 sudo lsblk 查看根目录的 UUID,复制后、粘贴过去。最后样子大概是这样的:

最后别忘了 ls -l 看看 /boot 目录,再 tree 检查一下(没有 tree 就 apt 安装一下)。

感觉大功告成了,别忘了最后的收尾:

passwd root
#为 root 创建一个密码

sync
#同步文件系统,写入缓存

exit
#退出容器

umount /dev/zvol/root/Container/starfive-lxde-*
#卸载挂载的块设备

dd if=/dev/zvol/root/Container/starfive-lxde of=/dev/<你的sdcard> status=progress bs=1M
#将做好的块设备烧到你的 sdcard 上,这里注意确定你的块设备,别写错了

第三部分小结:

  • 根据你做的镜像发行版不同,debian 和 ubuntu 导入你内核私有源的公钥会略有不同,根据遇到的情况查阅 Google
  • 按部就班,多检查细节

写在最后:

有任何问题可以留言,发邮件给我,hougelangley1987@gmail.com ,加我微信:15887005593 也可以,但是我回复会根据上班情况有所改变。

如果各位朋友还是没有弄明白,可以期待近期放出的视频教程,我会把3个部分拆解成9个部分,给大家详细介绍,关注我的 B 站,油管,或者 StarFive 的官方 B 站,油管账号都可以的。

One thought on “为 StarFive VisionFive V1 创建 Debian 系统镜像

  1. houge,您好!感谢您的分享,我最近根据您的这篇文章试着为visionfive v1开发板构建ubuntu系统镜像,但是没有对应开发板固件的启动文件,导致板子无法启动构建的镜像,请问您在文章里提供的最早创建的镜像启动文件要如何下载呢?

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注