pvm

Host kernel

host/build.sh produces Ubuntu-installable debs (linux-image, linux-headers) whose release string ends in -pvm. The PVM switcher is core-kernel code — it cannot ship as a DKMS module, so PVM hosts run this kernel wholesale.

Config composition

  1. Base: configs/host-base.config, a pinned linux-gcp config carrying the distro’s GCP driver coverage (virtio, gVNIC, NVMe), so the debs work on any GCP instance type. It is vendored rather than pulled from apt at build time: the newest linux-gcp in the archive tracks a later release than kernel.pin, and olddefconfig resolves that version gap silently — a green build shipping a subtly different kernel each run. Pinning the base makes a pinned source reproducible.
  2. configs/host-pvm.config: CONFIG_KVM=m, CONFIG_KVM_PVM=m. That is the entire PVM delta; upstream’s host reference config shows no other requirement (KASLR, PTI and 5-level paging all stay at distro defaults).
  3. Build hygiene: Canonical’s signing-key and debug-info options are stripped (SYSTEM_TRUSTED_KEYS, DEBUG_INFO*) — they cannot build outside Canonical’s packaging and a PVM node does not need them.
  4. After olddefconfig the build asserts the PVM, GCP-driver and container-networking symbols survive, so a base refresh cannot silently drop one (e.g. gVNIC) behind a green build.

Refreshing the base

Refresh configs/host-base.config deliberately when bumping kernel.pin, so GCP driver coverage keeps pace with the distro. On an up-to-date Ubuntu build host, extract the matching linux-gcp config and re-vendor it:

pkg=$(apt-cache search --names-only '^linux-modules-[0-9].*-gcp$' \
	| awk '{print $1}' | sort -V | tail -1)
apt-get download "$pkg"
dpkg-deb --fsys-tarfile "$pkg"*.deb \
	| tar -xO --wildcards './boot/config-*' > configs/host-base.config

Then run host/build.sh and confirm the assertion loop passes. BASE_CONFIG points the build at an alternate base without editing the tree.

Install

host/install.sh is deliberately two-phase:

sudo ./install.sh .          # dpkg -i + one-shot grub-reboot into -pvm
sudo reboot
uname -r && lsmod | grep kvm_pvm && ls /dev/kvm
sudo ./install.sh --commit . # make it the default only after validation

A broken kernel therefore costs one reboot, never a dead node. Secure Boot must be off (the kernel is unsigned); the script refuses to install otherwise.

scripts/gcp-host-e2e.sh runs the whole loop against a fresh GCP e2 instance: install → reboot → kvm_pvm loaded → guest smoke boot → teardown.