Windows 11下用GCC的C++代码实现的虚拟机需要终端输入/输出(如串口或虚拟控制台)和网络连接,但不需要完整的硬件设备(如磁盘、显卡、USB 等)。在终端输入/输出方面,参考qemu的源代码,但不调用qemu程序,可以使用 Linux 虚拟控制台(TTY) 或 串口(Serial Console) 进行交互。模拟QEMU提供 的virtio-console
或 isa-serial
设备允许宿主机通过 stdio
或管道与虚拟机交互,这样,虚拟机的 ttyS0
(串口)会直接连接到宿主机的 stdio
(终端)。网络连接使用 virtio-net 或 用户态网络(SLIRP) 提供网络访问,这样,虚拟机可以通过 NAT 方式访问外部网络(类似宿主机的网络代理)。
以下是一个在Windows 11下使用GCC的C++实现轻量级虚拟机的方案,重点实现终端I/O和网络功能,无需完整硬件模拟:
核心设计思路
- 使用Windows Hypervisor Platform (WHP) - 微软官方虚拟化API
- 简化设备模型 - 仅实现必要设备:
virtio-console
用于终端I/Ovirtio-net
+ SLIRP 用于网络
- 主机交互:
- 终端I/O通过标准输入输出重定向
- 网络通过用户态NAT实现
代码框架
#include <windows.h>
#include <winhvplatform.h>
#include <cstdio>
#include <thread>
// 虚拟设备基类
class VirtDevice {
public:
virtual void handle_io(uint16_t port, uint8_t* data, uint32_t size, bool is_write) = 0;
virtual ~VirtDevice() {}
};
// VirtIO 控制台设备 (简化版)
class VirtioConsole : public VirtDevice {
public:
void handle_io(uint16_t port, uint8_t* data, uint32_t size, bool is_write) override {
if (is_write) {
// 虚拟机输出 -> 宿主终端
fwrite(data, 1, size, stdout);
fflush(stdout);
} else {
// 宿主输入 -> 虚拟机 (需异步处理)
// 实际实现需用环形缓冲区和中断机制
}
}
};
// SLIRP网络后端 (伪代码)
class SlirpBackend {
public:
void start_nat() {
// 实现NAT网络转换
// 使用WinSock API处理数据包转发
}
};
// VirtIO 网卡设备
class VirtioNet : public VirtDevice {
SlirpBackend slirp;
public:
VirtioNet() { slirp.start_nat(); }
void handle_io(uint16_t port, uint8_t* data, uint32_t size, bool is_write) override {
// 网络包处理逻辑
if (is_write) {
slirp.send_packet(data, size); // 发送到外部网络
} else {
slirp.recv_packet(data, size); // 接收外部数据
}
}
};
// 虚拟机管理器
class MiniVM {
WHV_PARTITION_HANDLE partition;
std::vector<VirtDevice*> devices;
public:
bool initialize() {
// 1. 初始化Hyper-V分区
WHV_PARTITION_HANDLE partition;
CHECK(WHvCreatePartition(&partition));
// 2. 设置基础CPU特性
WHV_PARTITION_PROPERTY prop{};
prop.ProcessorCount = 1;
WHvSetPartitionProperty(partition, WHvPartitionPropertyCodeProcessorCount, &prop);
// 3. 分配内存 (示例: 512MB)
const SIZE_T ramSize = 512 * 1024 * 1024;
WHvMapGpaRange(partition, physical_mem, 0, ramSize, WHvMapGpaRangeFlagReadWrite);
// 4. 注册设备
devices.push_back(new VirtioConsole());
devices.push_back(new VirtioNet());
return true;
}
void run() {
// CPU执行循环
while (true) {
auto exit_context = WHvRunVirtualProcessor(partition, 0);
// 处理VM退出事件
switch (exit_context->ExitReason) {
case WHvRunVpExitReasonX64IoPortAccess: {
auto io = &exit_context->IoPortAccess;
for (auto dev : devices) {
dev->handle_io(io->PortNumber, io->Data, io->AccessSize, io->Direction);
}
break;
}
// 其他退出处理...
}
}
}
void load_kernel(const char* kernel_path) {
// 加载Linux内核到内存
// 设置启动参数 (指定console=ttyS0)
}
};
int main() {
MiniVM vm;
if (vm.initialize()) {
vm.load_kernel("vmlinux.bin");
vm.run();
}
return 0;
}
关键实现细节
1. 终端输入输出
- 设备模拟:
- 实现
virtio-console
设备的简化版 - 使用I/O端口或MMIO与虚拟机通信
- 实现
- 主机集成:
- 输出:直接写入
stdout
- 输入:使用独立线程读取
stdin
并注入输入缓冲区 - 启用行缓冲:
setvbuf(stdout, NULL, _IOLBF, 0);
- 输出:直接写入
2. 网络实现
- SLIRP架构:
- 关键功能:
- DHCP服务:为虚拟机分配内网IP(如10.0.2.15)
- DNS转发:解析宿主机DNS配置
- 端口转发:实现
-netdev user,hostfwd=tcp::2222-:22
3. 启动配置
虚拟机启动时需传递内核参数:
console=ttyS0 earlycon=uart8250,mmio,0x10000000 root=/dev/ram0
构建与运行
依赖项:
- Windows SDK (含Hypervisor Platform API)
- GCC for Windows (MinGW-w64)
- 虚拟化支持:启用Hyper-V/WHPX
编译命令:
g++ -o minivm.exe main.cpp -lwinhvplatform -lws2_32
- 运行示例:
# 启动虚拟机
minivm.exe -kernel vmlinux -initrd initrd.img
# 网络测试 (从宿主机访问)
telnet localhost 2222
性能优化建议
批处理I/O:
- 使用DMA代替端口I/O
- 实现
VIRTIO_F_ANY_LAYOUT
特性
异步网络:
- 使用IOCP完成端口
- 零拷贝数据传递
中断合并:
// 延迟中断提交 void VirtioConsole::schedule_irq() { if (!irq_pending) { irq_timer = setTimeout(1ms, [this]{ inject_irq(); irq_pending = false; }); } }
此方案实现了核心功能,代码约500行可完成基础版本。实际开发中需处理更多边界情况,建议参考QEMU的hw/char/virtio-console.c
和net/slirp
实现细节。