Setting up a QEMU + Linux 5.18 lab environment on Windows
WindowsTask Manager → Performance → CPU → Confirm Virtualization: Enabled
Or in PowerShell:
Get-ComputerInfo -Property HyperVisorPresent, HyperVRequirementVirtualizationFirmwareEnabled
Intel VT-x or AMD-V in BIOS/UEFI settings| Method | Characteristics | Recommended For |
|---|---|---|
| Method 1: WSL2 + QEMU | Linux command-line environment, KVM acceleration support | Students with development experience (recommended) |
| Method 2: Windows Native QEMU | Run directly in Windows environment | Environments without WSL2 |
Running QEMU inside WSL2 allows you to use KVM acceleration for better performance.
Run PowerShell as Administrator:
wsl --install
After rebooting, complete the Ubuntu 22.04 setup (enter username/password).
If WSL1 is already installed, upgrade to WSL2:
wsl --set-default-version 2
wsl --set-version Ubuntu 2
Verify the version:
wsl --list --verbose
# NAME STATE VERSION
# Ubuntu Running 2 ← Must be 2
Open a WSL2 terminal (Ubuntu):
# Check if KVM device exists
ls /dev/kvm
# If missing: Enable "Virtual Machine Platform" in Windows Features (see below)
If /dev/kvm is not present:
# In PowerShell as Administrator
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
dism.exe /online /enable-feature /featurename:Microsoft-Hyper-V /all /norestart
Reboot and restart WSL2:
wsl --shutdown
wsl
sudo apt update
sudo apt install -y qemu-system-x86 qemu-utils
qemu-system-x86_64 --version
All subsequent steps are performed in the WSL2 terminal. Follow the same steps as the Linux guide (setup-linux.md) starting from step 2.
mkdir -p ~/qemu-lab && cd ~/qemu-lab
# Download ISO
wget -O ubuntu-22.04-server-amd64.iso \
https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso
# Create disk images (OS on virtio, test disk on NVMe — separate)
qemu-img create -f qcow2 ubuntu.qcow2 30G
qemu-img create -f raw nvme_disk.raw 16G
rmmod/insmod the NVMe driver. If the OS resides on an NVMe device, removing the driver will freeze the system. Therefore, the OS goes on a virtio disk (/dev/vda) and the test disk goes on the NVMe device (/dev/nvme0n1).
Install Ubuntu:
qemu-system-x86_64 \
-m 4G -smp 4 \
-enable-kvm \
-drive file=ubuntu.qcow2,if=virtio,format=qcow2 \
-cdrom ubuntu-22.04-server-amd64.iso \
-boot d \
-net nic -net user,hostfwd=tcp::2222-:22 \
-nographic
Boot with NVMe after installation:
qemu-system-x86_64 \
-m 4G -smp 4 \
-enable-kvm \
-drive file=ubuntu.qcow2,if=virtio,format=qcow2 \
-drive file=nvme_disk.raw,id=nvm,if=none,format=raw \
-device nvme,id=nvme0,serial=deadbeef \
-device nvme-ns,drive=nvm,bus=nvme0,nsid=1,logical_block_size=512,physical_block_size=512 \
-net nic -net user,hostfwd=tcp::2222-:22 \
-nographic
SSH connection:
ssh -p 2222 <username>@localhost
Kernel 5.18 installation and NVMe verification are the same as Step 8 and Step 9.
Run QEMU directly on Windows without WSL2. WHPX (Windows Hypervisor Platform) is used for acceleration.
Run PowerShell as Administrator:
# Enable Windows Hypervisor Platform (for WHPX acceleration)
dism.exe /online /enable-feature /featurename:HypervisorPlatform /all /norestart
# Enable Hyper-V
dism.exe /online /enable-feature /featurename:Microsoft-Hyper-V-All /all /norestart
Verify after rebooting:
Get-WindowsOptionalFeature -Online -FeatureName HypervisorPlatform | Select-Object State
# State: Enabled
# Install Scoop (if not installed)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
irm get.scoop.sh | iex
# Install QEMU
scoop install qemu
# Install Chocolatey (if not installed, Administrator PowerShell)
Set-ExecutionPolicy Bypass -Scope Process -Force
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
# Install QEMU
choco install qemu
Download the latest Windows installer from https://www.qemu.org/download/#windows and install.
Example installation path: C:\Program Files\qemu
Add to PATH (PowerShell):
$env:PATH += ";C:\Program Files\qemu"
# Permanent registration
[System.Environment]::SetEnvironmentVariable("PATH", $env:PATH, "Machine")
Verify installation:
qemu-system-x86_64 --version
qemu-img --version
PowerShell:
mkdir $HOME\qemu-lab
cd $HOME\qemu-lab
# PowerShell 7+ or use curl
curl.exe -L -o ubuntu-22.04-server-amd64.iso `
https://releases.ubuntu.com/22.04/ubuntu-22.04.5-live-server-amd64.iso
Or download directly via browser and move to C:\Users\<username>\qemu-lab\.
rmmod/insmod the NVMe driver. If the OS resides on an NVMe device, removing the driver will freeze the system. Therefore, the OS goes on a virtio disk (/dev/vda) and the test disk goes on the NVMe device (/dev/nvme0n1).
cd $HOME\qemu-lab
qemu-img create -f qcow2 ubuntu.qcow2 30G
qemu-img create -f raw nvme_disk.raw 16G
cd $HOME\qemu-lab
qemu-system-x86_64 `
-m 4G -smp 4 `
-accel whpx `
-drive file=ubuntu.qcow2,if=virtio,format=qcow2 `
-cdrom ubuntu-22.04-server-amd64.iso `
-boot d `
-net nic -net user,hostfwd=tcp::2222-:22 `
-nographic
-accel whpx with -accel tcg (software emulation, slower)
sudo lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv && sudo resize2fs /dev/ubuntu-vg/ubuntu-lvCtrl+A Xcd $HOME\qemu-lab
qemu-system-x86_64 `
-m 4G -smp 4 `
-accel whpx `
-drive file=ubuntu.qcow2,if=virtio,format=qcow2 `
-drive file=nvme_disk.raw,id=nvm,if=none,format=raw `
-device nvme,id=nvme0,serial=deadbeef `
-device nvme-ns,drive=nvm,bus=nvme0,nsid=1,logical_block_size=512,physical_block_size=512 `
-net nic -net user,hostfwd=tcp::2222-:22 `
-nographic
Windows 10/11 comes with a built-in OpenSSH client.
ssh -p 2222 <username>@localhost
If SSH is not available:
# Install OpenSSH client (Administrator PowerShell)
Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
Or use PuTTY:
localhost, Port: 2222, Connection type: SSH(Common to both Method 1 and Method 2 — proceed inside the Guest VM after SSH connection)
sudo apt update && sudo apt install -y wget
KVER=5.18.0-051800
mkdir -p /tmp/kernel && cd /tmp/kernel
wget \
https://kernel.ubuntu.com/mainline/v5.18/amd64/linux-image-unsigned-${KVER}-generic_${KVER}.202205222030_amd64.deb \
https://kernel.ubuntu.com/mainline/v5.18/amd64/linux-modules-${KVER}-generic_${KVER}.202205222030_amd64.deb \
https://kernel.ubuntu.com/mainline/v5.18/amd64/linux-headers-${KVER}-generic_${KVER}.202205222030_amd64.deb \
https://kernel.ubuntu.com/mainline/v5.18/amd64/linux-headers-${KVER}_${KVER}.202205222030_all.deb
sudo dpkg -i /tmp/kernel/*.deb
sudo reboot
After reconnecting, verify:
ssh -p 2222 <username>@localhost
uname -r
# 5.18.0-051800-generic
sudo apt install -y build-essential libncurses-dev bison flex \
libssl-dev libelf-dev bc pahole dwarves zstd
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.18-rc6.tar.xz
tar xf linux-5.18-rc6.tar.xz && cd linux-5.18-rc6
cp /boot/config-$(uname -r) .config
make olddefconfig
echo "-dpas-fast26" > localversion
make -j$(nproc) bindeb-pkg
sudo dpkg -i ../linux-image-*.deb ../linux-headers-*.deb
sudo reboot
uname -r
lsblk | grep nvme
# Enable poll_queues (reload nvme module)
sudo rmmod nvme
sudo modprobe nvme poll_queues=2
cat /sys/block/nvme0n1/queue/io_poll # 1
cat /sys/block/nvme0n1/queue/io_poll_delay # -1
sudo apt install -y fio
sudo fio --name=poll_test --filename=/dev/nvme0n1 \
--ioengine=io_uring --hipri=1 \
--rw=randread --bs=4k --direct=1 \
--iodepth=1 --numjobs=1 --runtime=10
In the WSL2 terminal:
cat > ~/qemu-lab/start-vm.sh << 'EOF'
#!/bin/bash
cd ~/qemu-lab
qemu-system-x86_64 \
-m 4G -smp 4 \
-enable-kvm \
-drive file=ubuntu.qcow2,if=virtio,format=qcow2 \
-drive file=nvme_disk.raw,id=nvm,if=none,format=raw \
-device nvme,id=nvme0,serial=deadbeef \
-device nvme-ns,drive=nvm,bus=nvme0,nsid=1,logical_block_size=512,physical_block_size=512 \
-net nic -net user,hostfwd=tcp::2222-:22 \
-nographic "$@"
EOF
chmod +x ~/qemu-lab/start-vm.sh
# $HOME\qemu-lab\start-vm.ps1
$QEMU_LAB = "$HOME\qemu-lab"
qemu-system-x86_64 `
-m 4G -smp 4 `
-accel whpx `
-drive "file=$QEMU_LAB\ubuntu.qcow2,if=virtio,format=qcow2" `
-drive "file=$QEMU_LAB\nvme_disk.raw,id=nvm,if=none,format=raw" `
-device nvme,id=nvme0,serial=deadbeef `
-device nvme-ns,drive=nvm,bus=nvme0,nsid=1,logical_block_size=512,physical_block_size=512 `
-net nic -net user,hostfwd=tcp::2222-:22 `
-nographic
Run:
.\start-vm.ps1
# If ExecutionPolicy error: Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
| Symptom | Cause | Solution |
|---|---|---|
WHPX: Failed to initialize | Windows Hypervisor Platform not enabled | Enable HypervisorPlatform feature via Administrator PowerShell and reboot |
WHPX not supported | Conflict with Hyper-V or unsupported hardware | Switch to -accel tcg (slower) |
qemu-system-x86_64: command not found | PATH not configured | Add QEMU installation path to PATH |
| PowerShell line continuation error | Space after backtick (`) | Ensure no spaces/tabs after the backtick (`) |
SSH Connection refused | VM still booting | Wait 30-60 seconds and retry |
nvme0n1 not found | Missing -device nvme | Check the QEMU launch command |
io_poll value is 0 | Guest kernel 5.19+ | Check uname -r, reinstall kernel 5.18 |
/dev/kvm missing in WSL2 | Hyper-V not enabled | Enable HypervisorPlatform and Microsoft-Hyper-V features |
PuTTY Connection timed out | Port forwarding error | Verify hostfwd=tcp::2222-:22 in QEMU, check Windows Firewall |