mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
hypervisor, vmm: Add support for KVM_SEV_SNP_LAUNCH_UPDATE
Implement the KVM_SEV_SNP_LAUNCH_UPDATE ioctl. Extend Vm::import_isolated_pages() with a uaddrs parameter carrying host virtual addresses, which KVM needs, unlike MSHV. Compute uaddrs from guest memory mappings in the IGVM loader. Add KVM_SEV_SNP_LAUNCH_UPDATE to the seccomp allowlist. Co-authored-by: Keith Adler <kadler@cloudflare.com> Signed-off-by: Keith Adler <kadler@cloudflare.com> Co-authored-by: Alex Orozco <aorozco@google.com> Signed-off-by: Alex Orozco <aorozco@google.com> Signed-off-by: Ruben Hakobyan <hruben@meta.com>
This commit is contained in:
committed by
Rob Bradford
parent
2e004521e0
commit
24db5e1efd
@@ -142,6 +142,8 @@ ioctl_io_nr!(KVM_NMI, kvm_bindings::KVMIO, 0x9a);
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use kvm_bindings::{KVM_MEMORY_ATTRIBUTE_PRIVATE, KVM_X86_SNP_VM, kvm_memory_attributes};
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use x86_64::sev;
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
const KVM_EXIT_TDX: u32 = 50;
|
||||
@@ -635,6 +637,44 @@ impl vm::Vm for KvmVm {
|
||||
.map_err(|e| vm::HypervisorVmError::InitializeSevSnp(e.into()))
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "sev_snp", target_arch = "x86_64"))]
|
||||
fn import_isolated_pages(
|
||||
&self,
|
||||
page_type: u32,
|
||||
page_size: u32,
|
||||
// host page frame numbers
|
||||
pfns: &[u64],
|
||||
uaddrs: &[u64],
|
||||
) -> vm::Result<()> {
|
||||
if pfns.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
assert_eq!(pfns.len(), uaddrs.len());
|
||||
// VMSA pages are not supported by launch_update
|
||||
// https://elixir.bootlin.com/linux/v6.11/source/arch/x86/kvm/svm/sev.c#L2377
|
||||
if page_type == sev::SNP_PAGE_TYPE_VMSA {
|
||||
return Ok(());
|
||||
}
|
||||
for i in 0..pfns.len() {
|
||||
self.fd
|
||||
.set_memory_attributes(kvm_memory_attributes {
|
||||
address: pfns[i] << sev::GPA_METADATA_SHIFT_OFFSET,
|
||||
size: page_size as u64,
|
||||
attributes: kvm_bindings::KVM_MEMORY_ATTRIBUTE_PRIVATE as u64,
|
||||
// Flags must be zero o/w error (flags aren't being used here yet)
|
||||
flags: 0,
|
||||
})
|
||||
.map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into()))?;
|
||||
self.sev_fd
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.launch_update(&self.fd, uaddrs[i], page_size as u64, pfns[i], page_type)
|
||||
.map_err(|e| vm::HypervisorVmError::ImportIsolatedPages(e.into()))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
///
|
||||
/// Sets the address of the one-page region in the VM's address space.
|
||||
|
||||
@@ -19,6 +19,14 @@ pub(crate) type Result<T> = std::result::Result<T, errno::Error>;
|
||||
// KVM SEV command IDs — linux/include/uapi/linux/kvm.h
|
||||
const KVM_SEV_INIT2: u32 = 22;
|
||||
const KVM_SEV_SNP_LAUNCH_START: u32 = 100;
|
||||
const KVM_SEV_SNP_LAUNCH_UPDATE: u32 = 101;
|
||||
// SNP_LAUNCH_UPDATE page types — linux/arch/x86/include/uapi/asm/sev-guest.h
|
||||
pub const SNP_PAGE_TYPE_VMSA: u32 = 2;
|
||||
|
||||
// See AMD Spec Section 8.17 — SNP_LAUNCH_UPDATE
|
||||
// The last 12 bits are metadata about the guest context
|
||||
// https://docs.amd.com/v/u/en-US/56860_PUB_1.58_SEV_SNP
|
||||
pub const GPA_METADATA_SHIFT_OFFSET: u32 = 12;
|
||||
|
||||
// SNP in VMSA - linux/arch/x86/include/asm/svm.h
|
||||
const SVM_SEV_FEAT_SNP_ACTIVE: u64 = 1 << 0;
|
||||
@@ -59,6 +67,19 @@ pub(crate) struct KvmSevSnpLaunchStart {
|
||||
pub pad1: [u64; 4],
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
#[derive(Debug, Copy, Clone, Default)]
|
||||
pub(crate) struct KvmSevSnpLaunchUpdate {
|
||||
pub gfn_start: u64,
|
||||
pub uaddr: u64,
|
||||
pub len: u64,
|
||||
pub type_: u8,
|
||||
pub pad0: u8,
|
||||
pub flags: u16,
|
||||
pub pad1: u32,
|
||||
pub pad2: [u64; 4],
|
||||
}
|
||||
|
||||
impl SevFd {
|
||||
pub(crate) fn new(sev_path: impl AsRef<Path>) -> Result<Self> {
|
||||
let file = OpenOptions::new()
|
||||
@@ -110,4 +131,30 @@ impl SevFd {
|
||||
};
|
||||
sev_op(vm, &mut sev_cmd, "KVM_SEV_SNP_LAUNCH_START")
|
||||
}
|
||||
|
||||
pub(crate) fn launch_update(
|
||||
&self,
|
||||
vm: &VmFd,
|
||||
// host virtual address
|
||||
hva: u64,
|
||||
size: u64,
|
||||
// guest frame number
|
||||
gfn_start: u64,
|
||||
page_type: u32,
|
||||
) -> Result<()> {
|
||||
let mut update = KvmSevSnpLaunchUpdate {
|
||||
gfn_start,
|
||||
uaddr: hva,
|
||||
len: size,
|
||||
type_: page_type as u8,
|
||||
..Default::default()
|
||||
};
|
||||
let mut sev_cmd = kvm_sev_cmd {
|
||||
id: KVM_SEV_SNP_LAUNCH_UPDATE,
|
||||
data: &mut update as *mut KvmSevSnpLaunchUpdate as _,
|
||||
sev_fd: self.fd.as_raw_fd() as _,
|
||||
..Default::default()
|
||||
};
|
||||
sev_op(vm, &mut sev_cmd, "KVM_SEV_SNP_LAUNCH_UPDATE")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2272,6 +2272,7 @@ impl vm::Vm for MshvVm {
|
||||
page_type: u32,
|
||||
page_size: u32,
|
||||
pages: &[u64],
|
||||
_uaddrs: &[u64],
|
||||
) -> vm::Result<()> {
|
||||
debug_assert!(page_size == hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB);
|
||||
if pages.is_empty() {
|
||||
|
||||
@@ -429,6 +429,7 @@ pub trait Vm: Send + Sync + Any {
|
||||
_page_type: u32,
|
||||
_page_size: u32,
|
||||
_pages: &[u64],
|
||||
_uaddrs: &[u64],
|
||||
) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ use log::debug;
|
||||
use log::info;
|
||||
use mshv_bindings::*;
|
||||
use thiserror::Error;
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemory};
|
||||
use zerocopy::IntoBytes;
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
@@ -471,6 +473,16 @@ pub fn load_igvm(
|
||||
.iter()
|
||||
.map(|gpa| gpa.gpa >> HV_HYP_PAGE_SHIFT)
|
||||
.collect();
|
||||
let guest_memory = memory_manager.lock().unwrap().guest_memory().memory();
|
||||
let uaddrs: Vec<_> = group
|
||||
.iter()
|
||||
.map(|gpa| {
|
||||
let guest_region_mmap = guest_memory.to_region_addr(GuestAddress(gpa.gpa));
|
||||
let uaddr_base = guest_region_mmap.unwrap().0.as_ptr() as u64;
|
||||
let uaddr_offset: u64 = guest_region_mmap.unwrap().1.0;
|
||||
uaddr_base + uaddr_offset
|
||||
})
|
||||
.collect();
|
||||
memory_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -479,6 +491,7 @@ pub fn load_igvm(
|
||||
group[0].page_type,
|
||||
hv_isolated_page_size_HV_ISOLATED_PAGE_SIZE_4KB,
|
||||
&pfns,
|
||||
&uaddrs,
|
||||
)
|
||||
.map_err(Error::ImportIsolatedPages)?;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,7 @@ mod kvm {
|
||||
pub const KVM_GET_NESTED_STATE: u64 = 3229658814;
|
||||
pub const KVM_SET_NESTED_STATE: u64 = 1082175167;
|
||||
pub const KVM_SEV_SNP_LAUNCH_START: u64 = 0x4018_aeb4;
|
||||
pub const KVM_SEV_SNP_LAUNCH_UPDATE: u64 = 0x8018_aeb5;
|
||||
}
|
||||
|
||||
mod iommufd {
|
||||
@@ -269,6 +270,7 @@ fn create_vmm_ioctl_seccomp_rule_common_kvm() -> Result<Vec<SeccompRule>, Backen
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_GET_NESTED_STATE)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SET_NESTED_STATE)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SEV_SNP_LAUNCH_START)?],
|
||||
and![Cond::new(1, ArgLen::Dword, Eq, KVM_SEV_SNP_LAUNCH_UPDATE)?],
|
||||
])
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user