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
實現細節。