Add KvmSevSnpIdBlock and KvmSevSnpIdAuth structs matching the AMD
SEV-SNP Firmware ABI Spec (Rev 1.58), and build them from the IGVM
SNP ID block directive during launch finish. This properly populates
id_block_uaddr/id_auth_uaddr in KVM_SEV_SNP_LAUNCH_FINISH and derives
auth_key_en from the assembled author key, matching QEMU's behavior.
Thread the guest policy from sev_snp_init to launch_finish via an
atomic on KvmVm so the ID block gets the correct policy value.
Also track has_snp_id_block in IgvmLoadedInfo to enable the ID block
based on whether the IGVM file actually contains one, rather than
hardcoding it for KVM.
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
Extract the SNP guest policy from IGVM initialization headers when
available, falling back to the default policy. This matches QEMU's
behaviour where only a non-zero IGVM policy overrides the default.
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
Preserve the original IGVM import order for KVM SNP launch updates.
The launch digest is order-sensitive, so only coalesce adjacent pages
that already share the same page type and size. MSHV continues to
sort by GPA for hypercall batching.
Signed-off-by: Kevin Hui <kevinhui@meta.com>
Introduce the KVM_SNP_PAGE_TYPE_ZERO page type for ZERO
pages. AMD SEV SNP can accept ZERO pages as a page in which
the page memory is functionally just zeroes
Signed-off-by: Kevin Hui <kevinhui@meta.com>
Verify the SEV hash table layout, GUID placement, kernel/initrd/cmdline
digest values, and the setup_sects > boot_params size branch. These
guard against silent regressions in the launch digest computation.
Signed-off-by: Kevin Hui <kevinhui@meta.com>
This introduces the kernel hashes measured boot table into
cloud hypervisor if a cmdline and kernel is passed into an
SEV-SNP CVM, incorporating a kernel/cmdline/optional initrd
into a memory page that is measured into the launch digest
of a SEV-SNP CVM. If both --kernel and --cmdline are not
provided, we do not insert this data page
Signed-off-by: Kevin Hui <kevinhui@meta.com>
For KVM SEV-SNP guests, the VMM should not modify the kernel
boot header before sending it via fw_cfg. The guest firmware is expected
to set fields like type_of_loader itself.
For upcoming measured boot logic for SEV-SNP, modifying `type_of_loader`
causes the kernel hash computed by the VMM to diverge from the hash that
`sev-snp-measure` (and the guest firmware) compute, resulting in a
launch measurement mismatch.
This matches QEMU's behavior, which skips kernel header modifications
for confidential guests so the data sent via fw_cfg matches the
original kernel file provided by the user.
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
Walk the input snapshot file extent by extent via lseek(SEEK_DATA) /
lseek(SEEK_HOLE) within each region's slot and read only those bytes
into guest RAM via the existing read_volatile_from primitive. Holes are
left as the guest mapping's natural zero-fill, which matches the source
content.
Symmetric counterpart to sparse-write on snapshot. Works for both new
sparse snapshots and old dense snapshots: a dense file has no holes, so
SEEK_DATA returns the full range as one extent and the I/O pattern
matches the previous behaviour.
If the input file's filesystem does not support SEEK_HOLE the code falls
back to the existing dense read path.
Measured on a 4 GiB shared-memory VM (2 vCPUs, ~340 MiB touched), total
restore time as reported by the in-tree timing instrumentation:
Before (dense): ~1487ms, reads 4.0 GiB from file
After (sparse): ~136ms, reads 340 MiB from file (92% less I/O, 11x faster)
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
For memfd-backed guest RAM regions, walk the backing fd extent by extent
via lseek(SEEK_DATA) / lseek(SEEK_HOLE) and write each populated extent
into the snapshot file's per-region slot via
std::os::unix::fs::FileExt::write_at. Pre-size the file with
set_len(total): on filesystems that support sparse files unwritten bytes
become real holes; on others the kernel zero-fills the allocation, which
is still byte-correct.
If set_len fails (some FUSE backends reject ftruncate-extend with
EOPNOTSUPP), fall back entirely to the dense write path which streams
bytes sequentially via write_volatile_to and never writes past the
growing EOF.
When the guest region has no backing file (anonymous mmap) or the
backing fd does not support SEEK_HOLE (hugetlbfs), fall back to the
dense write path on a per-region basis.
The on-disk byte stream is identical to the dense format from the
perspective of any reader using read/pread/mmap, so old readers see no
change.
Measured on a 4 GiB shared-memory VM (2 vCPUs, ~340 MiB touched), total
snapshot time as reported by the in-tree timing instrumentation:
Before (dense): ~2400ms, 4.0 GiB on disk
After (sparse): ~132ms, 340 MiB on disk (92% smaller, 18x faster)
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Adds next_data_extent: a streaming helper that returns the next
populated extent within a window of a file descriptor using
lseek(SEEK_DATA) / lseek(SEEK_HOLE). Used by subsequent commits to walk
the snapshot file extent-by-extent without collecting the full extent
list.
Returns an error on fds or filesystems without SEEK_HOLE support so the
caller can fall back to a dense write path.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Replace explicit --kernel and --cmdline arguments with the
default_kernel_cmdline() helper in performance_net_throughput,
performance_net_latency, and performance_block_io. This
simplifies the code and ensures consistency with how the
kernel command line is configured across tests.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Confidential VMs (CVM) are not currently supported on the
AArch64 architecture. Add an early check in the performance
metrics binary to exit with a clear error message when CVM
mode is selected on AArch64.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Add a --vm-type command-line argument to allow users to select
between 'regular' (default) and 'confidential' (CVM) VM types
when running performance tests.
Example: --vm-type confidential
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Apply the vm_type override from PerformanceTestOverrides to the
effective_control used during test execution, alongside the
existing test_timeout override.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Add an optional vm_type field to PerformanceTestOverrides to
allow overriding the VM type at runtime. Include vm_type in
the Display output for override logging.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Replace hardcoded GuestVmType::Regular with control.vm_type
in all performance test functions to support CVM benchmarking:
net_throughput, net_latency, boot_time, boot_time_pmem,
block_io, and restore_latency.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Update performance_test_new_guest() to accept a GuestVmType
parameter. When set to Confidential, configure the guest with
CVM-specific settings: vm_type, boot_timeout, and nested
virtualization disabled.
All callers pass GuestVmType::Regular to preserve existing
behavior.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Add a vm_type field of type GuestVmType to PerformanceTestControl,
defaulting to GuestVmType::Regular. Include vm_type in the Display
output for test control logging.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Consolidate override application into a single effective_control
variable built once before the test loop. This removes duplicated
timeout override logic from both warmup and measurement iterations.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Add Display trait implementation for GuestVmType to enable
formatted output of the VM type in logs and diagnostics.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Add FromStr trait implementation for GuestVmType to enable
parsing from CLI string arguments. Supports "regular" and
"confidential" string values.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
Update mshv-bindings and mshv-ioctls from 0.6.8 to 0.6.9
in workspace Cargo.toml and fuzz/Cargo.toml.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
The total RAM in the system needs to consider any hotpluggable RAM that
is hotplugged in as well as the initial static "base" RAM.
Signed-off-by: Rob Bradford <rbradford@meta.com>
The reserve_bootloader_regions() call allocates RAM regions at
KVM-specific addresses (0xffc00000 for stage0, 0xfffffffff000
for VMSA) that are only needed by the KVM SEV-SNP boot path.
The existing #[cfg(all(feature = "kvm", feature = "sev_snp"))]
compile-time guard is insufficient when both 'mshv' and 'kvm'
features are enabled in the same binary. The runtime check only
verified sev_snp_enabled() but not the hypervisor type, causing
these KVM-specific memory regions to be allocated on MSHV.
On MSHV, these spurious RAM mappings at high addresses interfere
with the hypervisor's address space layout. When the guest kernel
subsequently accesses MMIO regions (e.g., IOAPIC at 0xFEC00000),
MSHV incorrectly reports HVMSG_UNACCEPTED_GPA instead of routing
the access through MMIO emulation, crashing the guest.
Add a runtime hypervisor type check to ensure these regions are
only reserved when running on KVM.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Muminul Islam <muislam@microsoft.com>
The SnpCpuidInfo allocation and guest_memory.read() call in the
isolated page import loop are only needed for KVM's CPUID page
retry logic. However, when building with both 'mshv' and 'kvm'
features, #[cfg(feature = "kvm")] alone is insufficient as a
guard because both features compile into the same binary.
Without a runtime hypervisor type check, this code executes on
MSHV as well, reading guest memory at arbitrary GPAs that may
not be valid in the MSHV memory layout. This can cause undefined
behavior or crashes during IGVM loading.
Add #[cfg(feature = "kvm")] to the variable declarations and
wrap the guest_memory.read() call in a runtime check for
HypervisorType::Kvm to ensure it only executes on KVM.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Muminul Islam <muislam@microsoft.com>
The PageTypeConfig for MSHV incorrectly mapped the cpuid field
to HV_ISOLATED_PAGE_TYPE_NORMAL (0) and the secrets field to
HV_ISOLATED_PAGE_TYPE_UNMEASURED (3).
The correct MSHV page type constants are:
- CPUID pages: HV_ISOLATED_PAGE_TYPE_CPUID (5)
- Secrets pages: HV_ISOLATED_PAGE_TYPE_SECRETS (4)
This was introduced in commit 75ed2c9f90 ("vmm: add KVM
SEV-SNP support to IGVM loader") which abstracted page types
into a PageTypeConfig struct but assigned wrong values for the
MSHV variant. Using incorrect page types causes the MSHV
hypervisor to reject or mishandle isolated page imports,
leading to guest boot failure.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Muminul Islam <muislam@microsoft.com>
For SEV-SNP guests using IGVM, the ACPI tables and system
configuration (MP tables, EBDA, SMBIOS, PVH start info, e820)
are provided by the IGVM file. The rsdp_addr is set to None
for these guests to indicate ACPI table creation was skipped.
Commit 7d65187350 ("vmm: make RSDP address optional in
configure_system") removed the guard that prevented calling
configure_system when rsdp_addr is None. This caused MSHV
SEV-SNP guests to crash because configure_system writes to
guest memory locations that conflict with the IGVM-provided
layout.
Restore the guard by only calling configure_system when
rsdp_addr is Some, which preserves the intended behavior
for CVM guests while still allowing the Option<GuestAddress>
refactoring.
Assisted-by: Claude:Opus-4.6
Signed-off-by: Muminul Islam <muislam@microsoft.com>
If querying the fd's MTU fails (because it was from a different network
namespace). Degrade gracefully by not advertising the VIRTIO_NET_F_MTU
feature and instead let the guest kernel use the default 1500 Ethernet
MTU.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Use the VP register page to read and write emulation-related
special registers directly, avoiding expensive IOCTLs for
registers that instruction emulation never touches.
In cpu_state(), read only segments, cr0, and efer from the VP
register page instead of calling get_sregs() which issues
IOCTLs for tr, ldt, gdt, idt, cr2, apic_base, and
pending_interruption.
In update_cpu_state(), when segments change, write only the 6
segment registers to the VP register page and set the segment
dirty bit, instead of calling set_sregs() which issues IOCTLs
for tr, ldt, gdt, idt, cr0-cr4, cr8, efer, and apic_base.
Both paths fall back to the IOCTL-based methods when the VP
register page is not available.
Signed-off-by: Muminul Islam <muislam@microsoft.com>
VfioUserDmaMapping::map is reached from the virtio-iommu MAP handler
with (iova, gpa, size) all guest-controlled. Validate the length of the
region fits, not just the start.
Before this change the vfio-user on the other end could get a size that
spans past the end of its backing storage.
Signed-off-by: Dylan Reid <dgreid@fb.com>
The TX path's inline-data branch didn't check the inline buffer length
against the guest-supplied pkt.len() field. The worker will later panic
when it tries to index the packet.
Add the missing check, mirroring the other TX branches.
Signed-off-by: Dylan Reid <dgreid@fb.com>
dma_unmap computed `iova + size - 1` unchecked while the sibling dma_map
already used checked_add/checked_sub. A guest reaching dma_unmap via
VIRTIO_IOMMU_T_UNMAP could cause a panic.
Signed-off-by: Dylan Reid <dgreid@fb.com>
Catch u64 overflows on map so that later translation requests from the
guest don't have a vector for causing a host panic.
Signed-off-by: Dylan Reid <dgreid@fb.com>
prepare_activator() called queue.is_valid() and only logged the failure,
then still pushed the queue to the activator. This would later panic.
Technically this is a fixup for:
a10508970 "virtio-devices: Support driver programming fewer queues"
But that's been in there since 2021. The intent was to allow a subset of
possible queues to be configured, but the invalid queues slipped through
too.
Signed-off-by: Dylan Reid <dgreid@fb.com>