本文是基于 WSL2+Docker 从零复现 Minos Hypervisor 的过程记录。
1. 总体流程 1 2 3 4 5 6 7 8 9 10 11 WSL2 (Ubuntu 26.04, x86_64) └─ Docker 容器 (ubuntu:26.04) ├─ git clone 原始 minos 源码(未打补丁) ├─ 打补丁 1(Makefile / GCC15 兼容) ├─ 编译 minos → minos.bin ├─ 编译 u-boot → u-boot.bin ├─ 编译 Linux 4.19.238 → Image(集成 minos 驱动) └─ 打包 ramdisk(官方 qemu-virt.dtb + Image) └─ 宿主机 ├─ 改造官方 virtio-sd.img(写入 boot 分区) └─ QEMU 启动 → guest shell
产物目录 :容器 /home/minos/work = 宿主机 ~/minos-work(挂载共享)
2. 安装 Docker 2.1 安装 Docker Engine 1 curl -fsSL https://get.docker.com | sh
注意 :WSL 环境下脚本会打印提示:
1 2 3 WSL DETECTED: We recommend using Docker Desktop for Windows. You may press Ctrl+C now to abort this script. + sleep 20
这是正常提示,不是错误 。不要按 Ctrl+C,脚本 sleep 20 秒后仍会继续安装 Docker Engine。
中间可能出现的无害输出 :
1 sudo: preserving the entire environment is not supported, '-E' is ignored
这只是 sudo 忽略 -E 参数的 warning,不影响安装。
2.2 验证安装
2.3 加入 docker 组 1 sudo usermod -aG docker $USER
必须让组生效 :关掉当前终端,重新开一个新终端(最可靠),或 newgrp docker。 验证:groups 输出里应看到 docker。
3. 配置镜像加速器 3.1 背景 第一次 docker build / docker pull 报错:
1 2 failed to do request: Head "https://registry-1.docker.io/v2/library/ubuntu/manifests/26.04": dial tcp 173.252.108.3:443: i/o timeout
原因 :Docker Hub(registry-1.docker.io)在本地网络不可达。
3.2 排查各镜像源可达性 1 2 3 4 timeout 10 curl -sI https://registry-1.docker.io/v2/ | head -1 timeout 10 curl -sI https://docker.mirrors.ustc.edu.cn/v2/ | head -1 timeout 10 curl -sI https://registry.cn-hangzhou.aliyuncs.com | head -1 timeout 10 curl -sI https://docker.m.daocloud.io/v2/ | head -1
结果 :
源
结果
判断
Docker Hub
超时
❌
中科大
超时
❌
阿里云
200
⚠️ 可达但它是 ACR 端点,不一定代理 docker.io
DaoCloud
HTTP/2 401
✅ 可达 (401 是 registry 未带 token 访问 /v2/ 的正常响应)
3.3 配置 daemon.json 1 sudo vim /etc/docker/daemon.json
写入:
1 2 3 4 5 { "registry-mirrors" : [ "https://docker.m.daocloud.io" ] }
保存退出:vim 里 i 编辑 → 粘贴 → Esc → :wq 回车。
3.4 重启 + 验证 1 2 3 sudo systemctl restart dockerdocker pull hello-world
4. 创建 Dockerfile 并 build 容器 4.1 项目结构 1 2 3 4 5 6 7 ~/workspace/docker-minos/ ├── Dockerfile ├── build.sh # 分步构建辅助脚本 ├── qemu-virt-minimal.dts # 精简 host dtb(备用,官方 dtb 不可用时) ├── boot.cmd # U-Boot 启动脚本源(备用) ├── patches/ # 补丁文件 └── minos/ # (早期 COPY 用的源码,后改为容器内 clone)
4.2 Dockerfile 最终内容 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 FROM ubuntu:26.04 ENV DEBIAN_FRONTEND=noninteractiveRUN apt-get update && apt-get install -y --no-install-recommends \ gcc-aarch64-linux-gnu \ device-tree-compiler \ bison flex libssl-dev swig python3-dev \ python3-setuptools python3-pyelftools \ git wget curl ca-certificates xz-utils file patch vim sudo \ && rm -rf /var/lib/apt/lists/* RUN userdel -r ubuntu \ && groupadd -g 1000 minos \ && useradd -m -s /bin/bash -u 1000 -g 1000 minos COPY --chown =minos:minos build.sh /home/minos/work/build.sh COPY --chown =minos:minos qemu-virt-minimal.dts /home/minos/work/qemu-virt-minimal.dts COPY --chown =minos:minos boot.cmd /home/minos/work/boot.cmd RUN chmod +x /home/minos/work/build.sh VOLUME ["/home/minos/output" ] USER minosWORKDIR /home/minos/work
4.3 Dockerfile 的踩坑修复史 坑 1:UID 1000 is not unique
1 useradd: UID 1000 is not unique
ubuntu:26.04 基础镜像自带 ubuntu 用户(uid=1000)。需先删它:
1 RUN userdel -r ubuntu && useradd -m -s /bin/bash -u 1000 -g 1000 minos
但 userdel -r ubuntu 会连主组一起删 → 下一步报 group '1000' does not exist。
坑 2:group '1000' does not exist 需先重建 gid=1000 的组,再建用户:
1 2 3 RUN userdel -r ubuntu \ && groupadd -g 1000 minos \ && useradd -m -s /bin/bash -u 1000 -g 1000 minos
坑 3:git clone SSL 证书错误
1 fatal: unable to access 'https://github.com/...': Problem with the SSL CA cert
容器缺 ca-certificates 包 → Dockerfile 补装 ca-certificates(连同 curl)。
4.4 build 容器 1 2 cd ~/workspace/docker-minosdocker build --network host -t minos-build .
--network host 加速 apt/下载。首次会拉 ubuntu:26.04(走 DaoCloud 加速器)。
4.5 验证容器身份 1 2 3 4 5 docker run --rm \ -v ~/minos-output:/home/minos/output \ -v ~/workspace/docker-minos:/home/minos/host \ minos-build bash -c 'whoami; pwd; id'
5. 进入容器,从零 clone 源码 5.1 创建并进入容器 1 2 3 4 5 6 mkdir -p ~/minos-work ~/minos-outputdocker run -it --name minos-dev \ -v ~/minos-work:/home/minos/work \ -v ~/minos-output:/home/minos/output \ -v ~/workspace/docker-minos:/home/minos/host \ minos-build
A+B 结合 :--name minos-dev(命名容器)+ -v ~/minos-work:/home/minos/work(源码挂载宿主机,永久保留)。
之后重新进入 :
1 2 docker start -i minos-dev docker exec -it minos-dev bash
5.2 容器内从零 clone 原始 minos 1 2 cd /home/minos/workgit clone https://github.com/minosproject/minos.git
5.3 验证拿到的是干净源码 1 2 3 4 cd /home/minos/work/minosgrep -c 'fno-PIE' Makefile grep -n 'default:' arch /aarch64/virt/stage2.c
6. 补装构建工具 6.1 发现缺 make/gcc clone 后执行 make 报 make: command not found。检查确认容器缺 make/gcc/g++。
6.2 以 root 进入容器安装 1 2 3 4 docker exec -it -u root minos-dev bash apt-get update apt-get install -y make gcc g++ exit
minos 用户无 sudo 权限(Dockerfile 没配置),所以用 -u root 进容器安装。装完 exit 回 minos 用户 再构建,保证源码文件属主正确。
6.3 验证
7. 复现编译错误 7.1 复现编译错误 1 2 3 cd /home/minos/work/minosmake qemu_arm64_defconfig make -j$(nproc ) CROSS_COMPILE=aarch64-linux-gnu-
复现的报错 :
1 2 cc1: sorry, unimplemented: code model 'large' with '-fPIC' fatal error: config/config.h: No such file or directory
7.2 根因分析
错误
根因
code model 'large' with '-fPIC'
Ubuntu 26.04 GCC 15 默认启用 PIE(--enable-default-pie),而 minos 的 -mcmodel=large 与 PIE 冲突
config/config.h 缺失
连锁反应:asm-offset.s 因上一个错误编译失败,依赖它的头文件没生成
验证根因 (可选加深理解):
1 2 3 4 5 6 7 cd /tmpecho 'int x;' > t.caarch64-linux-gnu-gcc -mcmodel=large -c t.c -o t.o aarch64-linux-gnu-gcc -mcmodel=large -fno-PIE -c t.c -o t.o echo 'typedef int bool;' > t2.cgcc -std=c23 -c t2.c -o t2.o gcc -std=gnu89 -c t2.c -o t2.o
7.3 补丁 1:Makefile / GCC15 兼容 补丁内容 (patches/01-makefile-gcc15.patch):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @@ -145,7 +145,8 @@ MBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ -fno-strict-aliasing -fno-common -fshort-wchar \ -Werror-implicit-function-declaration \ -Wno-format-security -O$(O_LEVEL) -DBUILD_HYPERVISOR \ - -std=gnu89 --static -nostdlib -fno-builtin -g $(MINOSINCLUDE) + -std=gnu89 --static -nostdlib -fno-builtin -g \ + -fno-PIE -fno-pic $(MINOSINCLUDE) @@ -293,7 +294,7 @@ endif $(offset_s): $(offset_c) $(Q) echo " CC $(offset_s)" - $(Q) gcc $(MINOSINCLUDE) -S $< -o $@ + $(Q) gcc $(MINOSINCLUDE) -std=gnu89 -fno-PIE -S $< -o $@
为什么这两处 :
-fno-PIE -fno-pic:解决 -mcmodel=large 与 PIE 冲突(所有 aarch64 编译)
asm-offset 规则加 -std=gnu89:该规则用宿主 gcc 编译,没走 MBUILD_CFLAGS,需单独指定(避免 c23 的 bool 关键字问题)
7.4 应用补丁 1 2 3 cd /home/minos/work/minospatch -p1 < /home/minos/host/patches/01-makefile-gcc15.patch
验证:
1 grep -n 'fno-PIE' Makefile
7.5 并行编译 bug 直接 make -j$(nproc) 会报:
1 make[1]: *** No rule to make target 'apps/esh/built-in.o', needed by 'apps/built-in.o'. Stop.
根因 :Minos 的构建脚本(scripts/Minos.build.mk)用递归 make 生成子目录 built-in.o,并行时父目录依赖检查和子目录生成规则竞态。
解决 :用 -j1 单线程构建。
7.6 编译成功 1 2 make -j1 CROSS_COMPILE=aarch64-linux-gnu- ls -la minos.bin
7.7 编译 mkrmd 1 2 make mkrmd ls -la tools/mkrmd/mkrmd
mkrmd 用宿主 gcc 编译,验证了补丁 1 的 asm-offset 规则(-std=gnu89)生效。
8. 构建 U-Boot 1 2 3 4 5 cd /home/minos/workgit clone --depth 1 https://github.com/minosproject/u-boot.git cd u-bootmake qemu_arm64_defconfig make -j1 CROSS_COMPILE=aarch64-linux-gnu-
8.1 踩坑:bc 缺失 末尾报错:
1 2 /bin/sh: 1: bc: not found CFGCHK u-boot.cfg
原因 :u-boot 的 CFGCHK 步骤需要 bc(命令行计算器)。不影响 u-boot.bin 生成,但 make 返回非零。
解决 :
1 2 3 4 5 docker exec -it -u root minos-dev bash apt-get install -y bc exit cd /home/minos/work/u-bootmake -j1 CROSS_COMPILE=aarch64-linux-gnu-
产物 :u-boot.bin(591400 字节)、u-boot/tools/mkimage(226400 字节)。
9. 构建 Linux 内核 1 2 3 4 5 6 7 8 9 10 cd /home/minos/workwget -c https://cdn.kernel.org/pub/linux/kernel/v4.x/linux-4.19.238.tar.xz tar xf linux-4.19.238.tar.xz cd linux-4.19.238cp -r /home/minos/work/minos/generic/minos-linux-driver drivers/minosecho 'obj-y += minos/' >> drivers/Makefilemake ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- -j$(nproc ) Image
要点 :
下载用 cdn.kernel.org(文档的 mirrors.edge.kernel.org 慢/超时)
集成 minos 驱动:obj-y 强制内置(不是模块),guest 启动后驱动自动加载
产物:arch/arm64/boot/Image(19173888 字节,约 19MB)
为什么需要自编译内核 (rootfs 用官方但内核必须自己编): 官方镜像 boot 分区虽有个 Image,但那是 4.2.0 通用内核(无 minos 驱动) 。我们编译的 4.19.238 内置 minos-linux-driver (guest↔hypervisor 通信的桥梁:console/vmbox/hypercall),是虚拟化栈核心。
10. 打包 ramdisk 10.1 获取官方 host dtb 官方文档 005 提供网盘下载:qemu-virt.dtb(6899 字节,与文档日志一致)。 下载后放到 ~/minos-work/downloads/(容器内可见为 /home/minos/work/downloads/)。
10.2 打包 1 2 3 4 5 cd /home/minos/work/home/minos/work/minos/tools/mkrmd/mkrmd \ -f /home/minos/work/ramdisk.bin \ /home/minos/work/linux-4.19.238/arch/arm64/boot/Image \ /home/minos/work/downloads/qemu-virt.dtb
预期输出 :
1 2 3 4 Image f_offset 0x0 0x19173888 qemu-virt.dtb f_offset 0x19177472 0x6899 generate ramdisk done ramdisk size 0x124d000
产物 :ramdisk.bin(19189760 字节)。
11. 构建可启动镜像 11.1 准备工作 官方镜像 virtio-sd.img(512MB)含:
分区 1(boot,76MB FAT16):放启动文件
分区 2(rootfs,436MB ext4):Linux 用户态系统
需要把 minos 的 3 个启动文件写入 boot 分区(分区 1),rootfs 分区(分区 2)保留官方内容。
11.2 挂载方式说明 文档 005 用 mount -o loop,offset=32256(offset=63扇区×512=32256 手动指定),本记录用 losetup -P(自动解析分区表,更通用):
11.3 命令(宿主机执行) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 mkdir -p ~/minos-work/mnt/bootls -la ~/minos-work/virtio-sd-run.img 2>/dev/null || cp ~/minos-work/downloads/virtio-sd.img ~/minos-work/virtio-sd-run.imgsudo losetup -fP ~/minos-work/virtio-sd-run.imgsudo losetup -l | grep virtio-sd-runDEV=$(sudo losetup -l | grep virtio-sd-run | awk '{print $1}' | head -1) sudo mount ${DEV} p1 ~/minos-work/mnt/bootsudo cp ~/minos-work/minos/minos.bin ~/minos-work/mnt/boot/kernel.binsudo cp ~/minos-work/minos/dtbs/qemu-arm64.dtb ~/minos-work/mnt/boot/sudo cp ~/minos-work/ramdisk.bin ~/minos-work/mnt/boot/ls -la ~/minos-work/mnt/boot/sudo umount ~/minos-work/mnt/bootsudo losetup -d $DEV
写入的文件 :
文件
内容
谁加载
kernel.bin
minos.bin(hypervisor)
U-Boot
qemu-arm64.dtb
hypervisor 设备树
U-Boot
ramdisk.bin
guest 内核+dtb 打包
minos(guest 启动时)
12. QEMU 启动 12.1 启动命令 1 2 3 4 5 qemu-system-aarch64 -nographic -bios /home/finfen01/minos-work/u-boot/u-boot.bin \ -M virtualization=on,gic-version=3 \ -cpu cortex-a53 -machine type =virt -smp 4 -m 2G \ -drive if =none,file=/home/finfen01/minos-work/virtio-sd-run.img,format=raw,id =hd0 \ -device virtio-blk-device,drive=hd0
踩坑 :用 ~/minos-work/... 时 QEMU 可能报 Could not open ...: No such file or directory (波浪号未被展开)。改用绝对路径 解决。
12.2 预期成功输出 1 2 3 4 5 6 7 8 9 10 11 12 13 U-Boot 2019.07-rc4 ... Starting kernel ... [ 0.000000] Starting Minos AARCH64 [ 0.000000] Minos v0.4.00 [ 0.000000] current EL is 2 ← hypervisor 在 EL2 [ 0.000000] vgicv3: nr_lrs 4 nr_prs 5 ... [ 0.000000] Booting Linux on physical CPU ... [ 0.000000] Linux version 4.19.238 ... ← 我们编译的内核 [ 0.000000] Memory: 963728K/1048576K available [ 0.123662] CPU: All CPU(s) started at EL1 [ 0.651527] VFS: Mounted root (ext4 filesystem) on device 254:2. root@genericarmv8:~# ← 进入 shell!
13. 最终验证 13.1 确认内核版本 1 2 root@genericarmv8:~# uname -a Linux genericarmv8 4.19.238
13.2 确认 minos 驱动加载 1 2 3 4 root@genericarmv8:~# dmesg | grep -i minos [ 0.000000] Linux version 4.19.238 (minos@c38964958dc3) (gcc version 15.2.0...) [ 0.550523] Minos Hyperviosr Driver Init ... [ 0.551254] Minos Hyperviosr Driver Init Done
Minos Hyperviosr Driver Init Done 是最终确认 :guest 内核里的 minos 驱动成功与 EL2 的 hypervisor 建立通信(HVC hypercall / vmbox),完整 Type-1 虚拟化栈工作正常。
注意 :官方 rootfs 是精简 BusyBox,head -5 不支持,用 head -n 5 或直接 head。
14. 记录中踩到的坑汇总
#
现象
根因
解决
1
Docker Hub 拉镜像超时
registry-1.docker.io 网络不可达
配置 DaoCloud 镜像加速器
2
Dockerfile UID 1000 is not unique
ubuntu:26.04 自带 ubuntu 用户
userdel -r ubuntu
3
group '1000' does not exist
userdel 连主组一起删
先 groupadd -g 1000 minos
4
git clone SSL 证书错误
容器缺 ca-certificates
Dockerfile 补装 ca-certificates
5
make: command not found
Dockerfile 漏装 make/gcc
容器内 apt install make gcc g++
6
code model 'large' with '-fPIC'
GCC 15 默认 PIE
补丁 1:-fno-PIE -fno-pic
7
No rule to make target .../built-in.o
Minos 构建脚本并行竞态
make -j1
8
u-boot bc: not found
CFGCHK 需要 bc
apt install bc
9
QEMU Could not open '~/...'
波浪号未展开
用绝对路径
15. 关键产物位置
产物
容器路径
宿主机路径
minos.bin
/home/minos/work/minos/minos.bin
~/minos-work/minos/minos.bin
qemu-arm64.dtb
/home/minos/work/minos/dtbs/qemu-arm64.dtb
~/minos-work/minos/dtbs/qemu-arm64.dtb
mkrmd
/home/minos/work/minos/tools/mkrmd/mkrmd
~/minos-work/minos/tools/mkrmd/mkrmd
u-boot.bin
/home/minos/work/u-boot/u-boot.bin
~/minos-work/u-boot/u-boot.bin
Image
/home/minos/work/linux-4.19.238/arch/arm64/boot/Image
~/minos-work/linux-4.19.238/arch/arm64/boot/Image
ramdisk.bin
/home/minos/work/ramdisk.bin
~/minos-work/ramdisk.bin
官方 dtb
/home/minos/work/downloads/qemu-virt.dtb
~/minos-work/downloads/qemu-virt.dtb
官方镜像
/home/minos/work/downloads/virtio-sd.img
~/minos-work/downloads/virtio-sd.img
可启动镜像
-
~/minos-work/virtio-sd-run.img
容器 :minos-dev(挂载 ~/minos-work,源码永久保留)