QEMU virtualization
Updated 11 November 2026

KVM (Kernel-based Virtual Machine) is hardware virtualization support at the Linux kernel level for Intel VT and AMD SVM processors. QEMU is a hardware emulator that also works without KVM, but with KVM guest systems run much faster, so the QEMU + KVM combination is the main way to virtualize in Calculate. libvirt is a daemon and an interface for managing virtual machines of different technologies; many applications and web interfaces have been released for it; the graphical virt-manager is useful out of the box.
Calculate supports two ways to virtualize, and you have to choose between them:
| task | what to use |
|---|---|
| several isolated Linux systems on a shared kernel | LXC containers and cl-lxc |
| run a ready-made image (.iso, .qcow2) or another OS with a single command | QEMU directly |
| a permanent set of guest machines: console, snapshots, networking from a graphical editor | virt-manager on top of libvirt |
| work with a guest machine disk without booting the machine | qemu-nbd |
Checking KVM support
Hardware acceleration requires CPU virtualization flags and the /dev/kvm device:
grep -m1 'model name' /proc/cpuinfo
vmx
A non-empty vmx (Intel) or svm (AMD) response means the processor supports virtualization; empty output means the flags are missing (for example, inside another virtual machine without extension passthrough). If the flags are present but /dev/kvm is not, virtualization is usually disabled in the BIOS. Modules are loaded on demand:
modprobe kvm; modprobe kvm_intel
For AMD, replace kvm_intel with kvm_amd. Without KVM, QEMU remains functional on the built-in processor emulator (TCG), but is noticeably slower.
Installation
The basic set is QEMU and the libvirt daemon:
emerge -aq --getbinpkg qemu libvirt
The --getbinpkg option first tries the binary packages from the Calculate mirror. For 3D acceleration and shared folders via virtiofs, you need flags that are not enabled by default - add them before installing:
/etc/portage/package.use/custom
app-emulation/qemu opengl virgl fuse spice usbredir vhost-net app-emulation/libvirt virtiofsd app-emulation/spice -smartcard
The fuse flag for qemu is not enabled in either the Calculate profile or the binary package from the mirror - with it, the package is rebuilt from source. Check after installation:
app-emulation/libvirt-12.6.0 app-emulation/qemu-10.2.3-r3 app-emulation/qemu-10.2.3-r3 app-emulation/qemu-10.2.3-r3
The graphical manager and the domain installer are installed separately:
emerge -aq virt-manager
libvirtd daemon
The service is called libvirtd - start it and add it to autostart:
rc-service libvirtd start; rc-update add libvirtd default
* Starting libvirtd ... [ ok ]
The virsh client checks the connection to the daemon and that QEMU is available to the hypervisor:
12.6.0
qemu:///system
Name State Autostart Persistent -------------------------------------------- default active yes yes
To manage machines without the root password, add the user you log in as to the libvirt group:
gpasswd -a user libvirt
Log in to this account again: group membership is applied at login time. The libvirt package is built with polkit support, so group membership decides - without it a non-root user gets an authentication failure, with it the user gets the list of machines:
Id Name State ----------------------- 1 docvm running
Kernel modules for networking
A virtual network and accelerated network processing require the tun and vhost_net modules:
modprobe -a tun vhost_net
To load them at boot, list them in a /etc/modules-load.d/qemu.conf file:
/etc/modules-load.d/qemu.conf
tun vhost_net
Working with disk images
A new dynamic qcow2 disk is created with a single command; the size is specified with the M and G suffixes, and the file fills up as it is written:
Formatting 'disk.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
image: disk.qcow2
file format: qcow2
virtual size: 1 GiB (1073741824 bytes)
disk size: 196 KiB
cluster_size: 65536
Format specific information:
compat: 1.1
compression type: zlib
lazy refcounts: false
refcount bits: 16
corrupt: false
extended l2: false
If the space for the disk is allocated in advance, the guest system will not have to allocate it while running, and it will be faster. This is how metadata preallocation works:
Formatting 'prealloc.qcow2', fmt=qcow2 cluster_size=65536 extended_l2=off preallocation=metadata compression_type=zlib size=1073741824 lazy_refcounts=off refcount_bits=16
The difference is visible in the space used - for a regular image the metadata has not been created yet (196 KiB), for a preallocated one it is allocated (324 KiB):
virtual size: 1 GiB (1073741824 bytes) disk size: 324 KiB
Converting raw to compressed qcow2 and checking consistency:
qemu-img convert -f raw -O qcow2 -c seed.bin seed.qcow2
No errors were found on the image. Image end offset: 262144
Disk contents without starting the machine
The image is available as a kernel block device via NBD - this is how you create partitions on it, format it, and mount it to a regular directory. Keep the guest machine powered off while doing this. Run everything as root on the host:
(no output; the device appears in /dev)
brw-rw---- 1 root disk 43, 0 Nov 10 00:52 /dev/nbd0
Next, work with /dev/nbd0 as you would with a real disk - partitioning, filesystem, mounting:
parted -s /dev/nbd0 mklabel msdos mkpart primary ext4 1MiB 100%
mkfs.ext4 -q /dev/nbd0p1
mkdir -p /mnt/nbd; mount /dev/nbd0p1 /mnt/nbd
Checking that the data goes into the qcow2 image itself:
nbd-marker
Once done, unmount and disconnect the image - without the second step the disk remains busy:
/dev/nbd0 disconnected
The same method is available without the nbd module via the FUSE block export: the QEMU daemon exposes a block node as a file, which is then mounted like a regular image:
Once the daemon is running, a representation of the image appears instead of the file:
-r-------- 1 root root 134217728 Nov 10 00:52 fs.raw.fuse
The daemon runs while the command is running; to run it in the background, add --daemonize. Mounting such a file as a filesystem on this build failed (the kernel reported can't read superblock), so for practical work with the disk contents, use qemu-nbd from the previous section.
Creating a virtual machine
The easiest way to install a machine is with the virt-install utility from the virt-manager package - it creates the disk, the network, and the libvirt configuration on its own:
virt-install --name docvm --memory 1024 --vcpus 2 --import \
--disk path=/var/lib/libvirt/images/alpine.qcow2,format=qcow2 \
--osinfo alpinelinux3.20 --graphics none --connect qemu:///system
The guest operating system variant is chosen from the osinfo database; osinfo-query os gives the list. If the media and the disk are already ready, --import is enough. Next, the machine is managed through virt-manager or with virsh commands:
virsh start docvm; virsh console docvm
virsh list --all
virt-manager also provides the list of machines with their state and a CPU usage graph:


An emergency stop is comparable to powering off:
virsh destroy docvm
For normal stop and restart, ACPI must be running in the guest machine; in a Calculate guest, this is done as follows:
emerge -aq acpid; rc-update add acpid boot
Autostart of the domain together with the daemon:
virsh autostart docvm
The domain configuration is stored in XML; it is viewed and edited with the virsh dumpxml and virsh edit commands. Typical elements are memory, vCPU, disk, and interface:
<domain type='kvm'>
<name>docvm</name>
<memory unit='MiB'>1024</memory>
<vcpu>2</vcpu>
<devices>
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2'/>
<source file='/var/lib/libvirt/images/alpine.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
<interface type='network'>
<source network='default'/>
</interface>
</devices>
</domain>
The same parameters can also be edited in the graphical domain editor: the Overview tab shows the machine hardware and the hypervisor properties - qemu-system-x86_64, the Q35 chipset, the BIOS firmware.


Guest network
By default, an isolated network with NAT access to the external network is used; the built-in DHCP issues addresses:
<forward mode='nat'>
</forward>
<bridge name='virbr0' stp='on' delay='0'/>
<range start='192.168.122.2' end='192.168.122.254'/>
Other modes are also possible: routed (no NAT, with routing configured externally), an isolated network without egress, a bridge with addresses from the real network, and PCI passthrough of a network card to the guest. The description of all modes is in the libvirt documentation on the Network XML format.
Graphics acceleration, shared folders, and clipboard
3D acceleration consists of three parts: the opengl and virgl flags for qemu (see the installation), the SPICE server of the machine and the virtio driver in the guest. In virt-manager, these are the Video section (virtio model, 3D acceleration enabled) and the Display section (Type: Spice server, Listen type: None, OpenGL enabled). The same set expressed in XML:
<graphics type="spice"> <listen type="none"/> <image compression="off"/> <gl enable="yes"/> </graphics>
Works with open-source Mesa/virglrenderer drivers (including on AMD and Intel video cards); with proprietary ones, check the behavior of your specific configuration. In a Calculate or Gentoo guest, the virtual GPU needs the Mesa flag:
/etc/portage/package.use/custom (в гостевой машине)
media-libs/mesa video_cards_virgl
The shared clipboard requires the SPICE agent in the guest system:
emerge -aq spice-vdagent; rc-update add spice-vdagent default
For Windows guests, the spice-guest-tools package from the SPICE website provides the same functionality.
Shared folders are built on virtiofs: the host exports a directory through the virtiofsd daemon, and the machine mounts it as a virtiofs filesystem. Do not confuse it with the qemu virtfs flag, which enables the Calculate profile - this is the old 9p transport, not virtiofs. On the libvirt side, the package must be built with the virtiofsd flag; otherwise the device is unavailable. Shared memory is required (memory-backend with shared access). In the domain configuration, it looks like this:
<memoryBacking> <source type="memfd"/> <access mode="shared"/> </memoryBacking>
The host directory is set by the <filesystem> tag with a mount tag that the guest specifies when mounting:
<filesystem accessmode='mapped'> <driver name='virtiofs' queue='1024'/> <source dir='/home/user/shared'/> <target dir='myshare'/> </filesystem>
In the guest, the directory is mounted by its mount tag: mount -t virtiofs myshare /mnt/share.
Project history
QEMU development has been ongoing since 2005, and libvirt since 2005; the QEMU and KVM developers decided to integrate KVM support into the main QEMU branch (mainline), and hardware virtualization support itself entered the Linux kernel starting with version 2.6.20. In Calculate, the binary package mirror updates the branch, so you should rely on the versions actually present in the Portage tree:
| package | version in the tree |
|---|---|
| app-emulation/qemu | 10.2.3-r3 |
| app-emulation/libvirt | 12.6.0 |
| app-emulation/virt-manager | 5.1.0-r1 |
| app-emulation/virtiofsd | 1.13.2 |
| app-emulation/guestfs-tools | 1.55.6 |
Current upstream releases: QEMU 11.1.x, libvirt 12.9.0, guestfs-tools 1.57.5 - the tree lag is explained by the time it takes to deliver updates to Portage, not by the state of Calculate.