2.1 · Getting a guest running
How to Check KVM Is Enabled on Raspberry Pi 5 (/dev/kvm, lsmod, dmesg)
Part 1 of this series explained how virtualization works, from the processor up to
QEMU and libvirt. Part 2 is hands-on: it sets up the host and builds a first VM. The
output in Part 2 was captured on home1, an SD card for my Raspberry Pi 5 (8 GB),
running Raspberry Pi OS Bookworm with Linux kernel 6.12, 64-bit.
Before installing anything, it is worth confirming that the host can actually run accelerated VMs. It takes three commands, and the second one returns nothing on a Raspberry Pi, in a way that looks alarming and is not.
Doing this first takes two minutes. Installing the whole virtualization stack and then discovering that acceleration was never available is a much worse way round.
What each check proves
Each command checks a different layer, and each layer only exists if the one below it worked:
Check 1: does /dev/kvm exist?
home1@home1:~ $ ls -l /dev/kvm
crw-rw----+ 1 root kvm 10, 232 Jun 11 15:08 /dev/kvm
This is the most important check. As post 1.2 explained, KVM only starts if the processor’s virtualization extension is present and usable, and when it starts, it creates this file. So the file existing proves the whole chain worked: the processor has the feature, the kernel found it and switched it on, and the interface QEMU will use is in place.
Three details in that line are worth reading:
| Detail | What it means |
|---|---|
The leading c | A character device: a stream of bytes, rather than a disk or an ordinary file. QEMU opens it, and then controls it with ioctl calls, as post 1.5 described. |
root kvm | Owned by root, but belonging to the kvm group. That is what lets an ordinary user use it, by joining the group, without sudo. The next post does that. |
The trailing + | An ACL, an extra permission rule, is set on the file. Raspberry Pi OS adds one by default, so access is usually more generous than the basic permissions suggest. |
If instead you get No such file or directory, KVM did not start. On a Raspberry Pi 5, the usual
cause is a 32-bit operating system: uname -m must report aarch64. On x86 computers, the usual
cause is virtualization being switched off in the firmware settings.
Check 2: is the kvm module loaded?
home1@home1:~ $ lsmod | grep kvm
Nothing at all.
This is where many people decide something is broken. Most KVM guides tell you to check lsmod,
and they all show output. On a Raspberry Pi you get nothing, while /dev/kvm is clearly there, and
the two seem to contradict each other.
They do not, and the explanation is worth knowing, because it applies well beyond KVM.
Built in, or loaded?
A part of the Linux kernel can be included in one of two ways:
| A loadable module | Built into the kernel | |
|---|---|---|
| How it is included | Compiled separately, and loaded while the system runs, with modprobe | Compiled into the kernel file itself |
| When it is present | From when it is loaded | From the moment the kernel starts |
Listed by lsmod | Yes | No: there is no separate module to list |
Most distributions build most drivers as modules, because it is flexible. Raspberry Pi OS builds KVM into the kernel.
lsmod only lists loadable modules. Code built into the kernel never appears, because there is no
module. So an empty lsmod | grep kvm does not mean KVM is missing. It means KVM is not a module. The
capability is the same either way; only the packaging differs.
The usual way to confirm this is the kernel’s build settings, which many kernels make available in
/proc/config.gz. On the Pi, that has a catch of its own:
home1@home1:~ $ zcat /proc/config.gz 2>/dev/null | grep -i kvm
home1@home1:~ $ zcat /proc/config.gz 2>/dev/null
home1@home1:~ $ zcat /proc/config.gz
gzip: /proc/config.gz: No such file or directory
The first two commands printed nothing, because 2>/dev/null hides error messages. Without it, the reason
appears: the file does not exist. On kernels that provide it, it would show CONFIG_KVM=y for built in, or
CONFIG_KVM=m for a module. Raspberry Pi OS’s kernel does not provide it by default, so another route is
needed.
Check 3: what did the kernel say when it started?
home1@home1:~ $ dmesg 2>/dev/null | grep -i kvm
[ 0.046684] kvm [1]: nv: 554 coarse grained trap handlers
[ 0.046799] kvm [1]: IPA Size Limit: 40 bits
[ 0.046811] kvm [1]: GICV region size/alignment is unsafe, using trapping (reduced performance)
[ 0.046835] kvm [1]: vgic interrupt IRQ9
[ 0.046846] kvm [1]: VHE mode initialized successfully
This settles it. KVM printed these messages as the kernel started, 0.046 seconds after power-on, before any programs were running. That timing is itself the clue: this is code built into the kernel, running during start-up, not a module loaded later.
VHE mode initialized successfully is the line that matters. As post 1.2 explained, it means KVM found the
virtualization extension and is running in the efficient arrangement where the host’s kernel itself runs at
EL2, the processor’s virtualization level. So KVM is not just working, it is working in its best mode.
The other lines are details of how KVM was set up:
IPA Size Limit: 40 bitsmeans a guest’s physical memory addresses can use up to 40 bits: up to 1 TiB of address space, far more than any VM on this Pi will need.GICV region size/alignment is unsafe, using trapping (reduced performance)is specific to this hardware, and not a problem. Part of the ARM interrupt controller cannot be mapped straight through to guests on this board, so KVM catches the guests’ accesses to it and handles them itself, inside the kernel. In the terms of post 1.5, that means extra VM exits, but quick ones, handled without involving QEMU. It does not affect whether acceleration works.
dmesg may need sudo on some systems.
The verdict
| Check | Result | Meaning |
|---|---|---|
/dev/kvm exists | Yes | KVM started, and its interface is in place |
crw-rw----+ ... root kvm | As expected | A character device, the kvm group, and an ACL |
lsmod | grep kvm | Nothing | Because KVM is built into the kernel, not a module |
dmesg | VHE mode initialized successfully | Running at EL2, in its efficient mode |
Three commands, one apparent contradiction, one clean explanation. This host can run accelerated ARM64 guests.
One consequence of KVM being built in removes a check other guides use. A loadable module shows a count in lsmod
of how many things are using it, and a common demonstration is to start a VM and watch that number rise as QEMU opens
/dev/kvm. With KVM built in, there is no module line and no count. To confirm a running VM really uses KVM, look
elsewhere: at <domain type='kvm'> in its XML, as post 3.4 does, or at -accel kvm
in the QEMU command, as post 3.9 does.
What this does not prove
/dev/kvm existing proves the kernel’s side is sound. It does not prove that the programs on top are installed, that
libvirt is running, that your user is allowed to use them, or that a virtual network exists.
Those are separate checks, and libvirt comes with a tool that runs them all at once, virt-host-validate. It is not
available yet, because it comes with libvirt. That is the next post,
along with what each of the nine packages in the stack does.
Summary
ls -l /dev/kvmis the main check. The file only exists if KVM started on a processor with a working virtualization extension.- The leading
cmeans a character device,root kvmis why thekvmgroup matters, and a trailing+means an ACL is set. lsmod | grep kvmshows nothing on Raspberry Pi OS, because KVM is built into the kernel, not a loadable module.lsmodonly lists modules./proc/config.gzwould normally show which, but Raspberry Pi OS’s kernel does not provide it.dmesg | grep -i kvmshows KVM starting with the kernel.VHE mode initialized successfullyconfirms the efficient EL2 mode.- The
GICV ... reduced performanceline is specific to this board: some interrupt controller accesses are handled by KVM in the kernel, which costs quick VM exits, not acceleration. - Because KVM is built in,
lsmodcannot show whether a VM is using it. Check the VM’s XML or its QEMU command instead.
Comments