3. 第一个虚拟机:创建最小化 Guest OS(io-pkt + slogger2)
说实话,很多初学者一上来就想跑个完整的 Linux 或 Android 作为 Guest OS。我个人觉得,这步子迈得有点大。在 QNX Hypervisor 的世界里,先跑通一个最小化的 Guest OS,才是理解 vCPU、内存、中断分配最直接的方式。
这一章,我们就动手创建一个只包含 io-pkt(网络协议栈)和 slogger2(日志系统)的最小化 Guest。它没有文件系统,没有图形界面,但五脏俱全。你想想看,当你能让这个“小东西”在虚拟机里跑起来,并且能从 Host 端看到它的日志,那种感觉,比直接跑个大系统要踏实得多。
3.1 为什么是 io-pkt + slogger2?
我在项目中遇到过不少新手,上来就配 4 个 vCPU、2GB 内存给 Guest,结果系统跑不起来,根本不知道是资源不够还是配置错了。所以,我建议从最精简的模型开始。
io-pkt 和 slogger2 是 QNX 系统里两个非常基础的服务:
- io-pkt:负责网络通信。有了它,Guest 才能“开口说话”。
- slogger2:负责日志输出。有了它,我们才能“看到” Guest 内部发生了什么。
这两个服务加起来,镜像体积可以控制在 1MB 以内。这意味着什么?意味着你的虚拟机启动时间可能比你的 IDE 启动还快。这对于调试和验证概念来说,简直是神器。
3.2 理解 vCPU、内存、中断的分配
在创建虚拟机之前,我们先要搞清楚三个核心概念:vCPU、内存和中断。说白了,Hypervisor 就是个“资源大管家”,它要把物理 CPU、物理内存、物理中断,合理地“分”给各个 Guest。
下面这张图,是我自己画的一个资源分配逻辑图,你可以先看个大概:
这张图想表达的核心思想是:Hypervisor 把物理资源“切”成虚拟资源,然后喂给 Guest OS。Guest OS 看到的 vCPU、内存地址、中断号,都是 Hypervisor 给它造的“假象”。
3.3 动手:创建最小化 Guest 的配置文件
好了,理论说完了,我们直接上手。在 QNX Hypervisor 里,虚拟机的配置是通过一个 .qvm 文件来描述的。这个文件就像一张“购物清单”,告诉 Hypervisor 你需要多少资源。
下面是我为这个最小化 Guest 写的配置文件,你可以直接拿去用:
# minimal_guest.qvm
name = "minimal_guest"
cpu = 1
memory = 64M
# 指定 Guest 的内核镜像
image = {
file = "minimal_guest.ifs"
load = 0x80000000
entry = 0x80000000
}
# 分配一个虚拟网卡
vdev = {
type = "virtio-net"
mac = "00:00:00:00:00:01"
backend = "tap0"
}
# 分配一个串口,用于输出 slogger2 日志
vdev = {
type = "uart"
irq = 33
backend = "file:guest_log.txt"
}
我们来逐行拆解一下这个配置文件:
| 配置项 | 值 | 我的理解 |
|---|---|---|
cpu = 1 |
1 个 vCPU | 对于最小化系统,1 个 vCPU 完全够用。多核反而会增加调试复杂度。 |
memory = 64M |
64 MB 内存 | io-pkt + slogger2 跑起来,32MB 都绰绰有余。给 64MB 是为了留点余量。 |
vdev virtio-net |
虚拟网卡 | io-pkt 需要它来收发网络包。backend 指向 Host 的 tap 设备。 |
vdev uart |
虚拟串口 | slogger2 的输出会重定向到这个串口。我们把它保存到文件 guest_log.txt 里。 |
3.4 中断分配:一个容易被忽略的细节
配置里有一行 irq = 33,这个就是中断分配。在 QNX Hypervisor 里,每个虚拟设备都需要一个虚拟中断号。这个中断号是 Guest OS 看到的,Hypervisor 会把它映射到物理中断上。
我个人的习惯是,给虚拟设备分配中断号时,尽量避开常用的物理中断号(比如 0-31 通常是系统保留的)。从 32 开始分配,会清晰很多。
这里有个关键点:Guest OS 里的驱动,必须使用这个虚拟中断号来注册中断处理函数。如果 Guest 的驱动写死了中断号 14(比如物理串口的中断),而 Hypervisor 分配的是 33,那 Guest 永远也收不到中断。
核心原则: Guest OS 看到的中断号,是 Hypervisor 虚拟出来的。它和物理中断号没有直接关系。你可以在 .qvm 文件里任意指定,只要 Guest 的驱动能对上就行。
3.5 启动与验证
配置写好了,镜像也准备好了(如何制作最小化 .ifs 镜像,我们会在下一章详细讲)。启动命令很简单:
qvm -c minimal_guest.qvm
启动后,你会看到 Host 的终端上没有任何输出。别慌,因为 Guest 的输出被重定向到文件了。打开 guest_log.txt,你应该能看到类似这样的内容:
slogger2: Starting...
io-pkt: Starting...
io-pkt: MAC address 00:00:00:00:00:01
io-pkt: Link up on tap0
slogger2: System ready.
看到这四行日志,恭喜你,你的第一个虚拟机跑起来了!
这意味着:
- vCPU 分配成功:Guest 的代码在虚拟 CPU 上正常执行了。
- 内存分配成功:Guest 的内核和进程被正确加载到了 64MB 的虚拟内存空间里。
- 中断分配成功:串口中断(vIRQ 33)被正确传递给了 Guest,slogger2 才能把日志写出来。
嗯,就是这么简单。但你别小看这一步。你想想看,你已经亲手搭建了一个完整的虚拟化环境,并且验证了最核心的资源分配机制。这比看一百页理论文档都管用。