feat(kvm)!: enable hypercall for SNP guests

Signed-off-by: Changyuan Lyu <changyuanl@google.com>
This commit is contained in:
Changyuan Lyu 2024-06-15 11:20:41 -07:00 committed by Lencerf
parent efbddfea39
commit 8e43412a2a
8 changed files with 99 additions and 15 deletions

View file

@ -214,6 +214,7 @@ where
_ => VmEntry::None,
}
}
VmExit::ConvertMemory { .. } => unimplemented!(),
VmExit::Unknown(msg) => break Err(Error::VmExit(msg)),
};
}

View file

@ -277,6 +277,11 @@ pub enum VmExit {
write: Option<u64>,
size: u8,
},
ConvertMemory {
gpa: u64,
size: u64,
private: bool,
},
Shutdown,
Reboot,
Unknown(String),

View file

@ -230,6 +230,7 @@ pub struct KvmRun {
pub union KvmExit {
pub mmio: KvmExitMmio,
pub io: KvmExitIo,
pub hypercall: KvmRunExitHypercall,
pub padding: [u8; 256],
}
@ -252,6 +253,15 @@ pub struct KvmExitIo {
pub data_offset: u64,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct KvmRunExitHypercall {
pub nr: u64,
pub args: [u64; 6],
pub ret: u64,
pub flags: u64,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union KvmSyncRegsBlock {
@ -259,6 +269,7 @@ pub union KvmSyncRegsBlock {
}
pub const KVM_EXIT_IO: u32 = 2;
pub const KVM_EXIT_HYPERCALL: u32 = 3;
pub const KVM_EXIT_MMIO: u32 = 6;
pub const KVM_EXIT_SHUTDOWN: u32 = 8;
@ -384,11 +395,23 @@ pub struct KvmMsi {
pub pad: [u8; 12usize],
}
pub const KVM_CAP_NR_MEMSLOTS: u64 = 10;
pub const KVM_CAP_IRQFD: u64 = 32;
pub const KVM_CAP_SIGNAL_MSI: u64 = 77;
pub const KVM_CAP_GUEST_MEMFD: u64 = 234;
pub const KVM_CAP_VM_TYPES: u64 = 235;
pub const KVM_CAP_NR_MEMSLOTS: u32 = 10;
pub const KVM_CAP_IRQFD: u32 = 32;
pub const KVM_CAP_SIGNAL_MSI: u32 = 77;
pub const KVM_CAP_EXIT_HYPERCALL: u32 = 201;
// pub const KVM_CAP_GUEST_MEMFD: u32 = 234;
// pub const KVM_CAP_VM_TYPES: u32 = 235;
pub const KVM_HC_MAP_GPA_RANGE: u64 = 12;
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
pub struct KvmMapGpaRangeFlag: u64 {
const PAGE_2M = 1 << 0;
const PAGE_1G = 1 << 1;
const ENCRYPTED = 1 << 4;
}
}
bitflags! {
#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -416,3 +439,12 @@ pub struct KvmEncRegion {
pub addr: u64,
pub size: u64,
}
#[repr(C)]
#[derive(Debug, Clone)]
pub struct KvmEnableCap {
pub cap: u32,
pub flags: u32,
pub args: [u64; 4],
pub pad: [u8; 64],
}

View file

@ -13,8 +13,8 @@
// limitations under the License.
use crate::hv::kvm::bindings::{
KvmCpuid2, KvmCreateGuestMemfd, KvmEncRegion, KvmIoEventFd, KvmIrqRouting, KvmIrqfd,
KvmMemoryAttributes, KvmMsi, KvmRegs, KvmSregs, KvmSregs2, KvmUserspaceMemoryRegion,
KvmCpuid2, KvmCreateGuestMemfd, KvmEnableCap, KvmEncRegion, KvmIoEventFd, KvmIrqRouting,
KvmIrqfd, KvmMemoryAttributes, KvmMsi, KvmRegs, KvmSregs, KvmSregs2, KvmUserspaceMemoryRegion,
KvmUserspaceMemoryRegion2, KVMIO,
};
use crate::utils::ioctls::{ioctl_io, ioctl_ior, ioctl_iowr};
@ -25,7 +25,7 @@ use crate::{
ioctl_none!(kvm_get_api_version, KVMIO, 0x00, 0);
ioctl_write_val!(kvm_create_vm, ioctl_io(KVMIO, 0x01));
ioctl_write_val!(kvm_check_extension, ioctl_io(KVMIO, 0x03));
ioctl_write_val!(kvm_check_extension, ioctl_io(KVMIO, 0x03), u32);
ioctl_none!(kvm_get_vcpu_mmap_size, KVMIO, 0x04, 0);
#[cfg(target_arch = "x86_64")]
ioctl_writeread_buf!(kvm_get_supported_cpuid, KVMIO, 0x05, KvmCpuid2);
@ -65,6 +65,7 @@ ioctl_write_ptr!(kvm_set_sregs, KVMIO, 0x84, KvmSregs);
#[cfg(target_arch = "x86_64")]
ioctl_write_buf!(kvm_set_cpuid2, KVMIO, 0x90, KvmCpuid2);
ioctl_write_ptr!(kvm_enable_cap, KVMIO, 0xa3, KvmEnableCap);
ioctl_write_ptr!(kvm_signal_msi, KVMIO, 0xa5, KvmMsi);
ioctl_writeread!(kvm_memory_encrypt_op, ioctl_iowr::<u64>(KVMIO, 0xba));

View file

@ -43,12 +43,12 @@ use crate::hv::Cpuid;
use crate::hv::{error, Coco, Hypervisor, MemMapOption, Result, VmConfig};
use bindings::{
KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, KvmCreateGuestMemfd, KVM_API_VERSION,
KVM_MAX_CPUID_ENTRIES, KVM_X86_DEFAULT_VM, KVM_X86_SNP_VM,
KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, KvmCreateGuestMemfd, KvmEnableCap, KVM_API_VERSION,
KVM_CAP_EXIT_HYPERCALL, KVM_MAX_CPUID_ENTRIES, KVM_X86_DEFAULT_VM, KVM_X86_SNP_VM,
};
use ioctls::{
kvm_create_guest_memfd, kvm_create_irqchip, kvm_create_vm, kvm_get_api_version,
kvm_get_vcpu_mmap_size,
kvm_check_extension, kvm_create_guest_memfd, kvm_create_irqchip, kvm_create_vm, kvm_enable_cap,
kvm_get_api_version, kvm_get_vcpu_mmap_size,
};
#[cfg(target_arch = "x86_64")]
use ioctls::{kvm_get_supported_cpuid, kvm_set_identity_map_addr, kvm_set_tss_addr};
@ -82,6 +82,16 @@ pub enum KvmError {
MmapOption { option: MemMapOption },
#[snafu(display("Failed to mmap a VCPU fd"))]
MmapVcpuFd { error: std::io::Error },
#[snafu(display("Failed to check extension {ext}"))]
CheckExtension {
ext: &'static str,
error: std::io::Error,
},
#[snafu(display("Failed to enable capability {cap}"))]
EnableCap {
cap: &'static str,
error: std::io::Error,
},
#[snafu(display("Failed to create guest memfd"))]
GuestMemfd { error: std::io::Error },
}
@ -184,6 +194,23 @@ impl Hypervisor for Kvm {
}
}
Coco::AmdSnp { .. } => {
let bitmap = unsafe { kvm_check_extension(&kvm_vm.vm, KVM_CAP_EXIT_HYPERCALL) }
.context(kvm_error::CheckExtension {
ext: "KVM_CAP_EXIT_HYPERCALL",
})?;
if bitmap != 0 {
let request = KvmEnableCap {
cap: KVM_CAP_EXIT_HYPERCALL,
args: [bitmap as _, 0, 0, 0],
flags: 0,
pad: [0; 64],
};
unsafe { kvm_enable_cap(&kvm_vm.vm, &request) }.context(
kvm_error::EnableCap {
cap: "KVM_CAP_EXIT_HYPERCALL",
},
)?;
}
let mut init = KvmSevInit::default();
kvm_vm.sev_op(KVM_SEV_INIT2, Some(&mut init))?;
log::debug!("vm-{}: snp init: {init:#x?}", kvm_vm.vm.as_raw_fd());

View file

@ -32,7 +32,7 @@ use crate::hv::{error, Error, Vcpu, VmEntry, VmExit};
#[cfg(target_arch = "x86_64")]
use crate::hv::{Cpuid, DtReg, DtRegVal, SReg, SegReg, SegRegVal};
use super::bindings::KVM_EXIT_SHUTDOWN;
use super::bindings::{KVM_EXIT_HYPERCALL, KVM_EXIT_SHUTDOWN};
pub(super) struct KvmRunBlock {
addr: usize,
@ -147,6 +147,7 @@ impl Vcpu for KvmVcpu {
},
Ok(_) => match self.kvm_run.exit_reason {
KVM_EXIT_IO => self.handle_io(),
KVM_EXIT_HYPERCALL => self.handle_hypercall(),
KVM_EXIT_MMIO => self.handle_mmio(),
KVM_EXIT_SHUTDOWN => Ok(VmExit::Shutdown),
reason => Ok(VmExit::Unknown(format!("unkown kvm exit: {:#x}", reason))),

View file

@ -106,7 +106,7 @@ impl VmInner {
Ok(())
}
fn check_extension(&self, id: u64) -> Result<i32, Error> {
fn check_extension(&self, id: u32) -> Result<i32, Error> {
let ret = unsafe { kvm_check_extension(self, id) };
match ret {
Ok(num) => Ok(num),

View file

@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::hv::kvm::bindings::{KVM_EXIT_IO_IN, KVM_EXIT_IO_OUT};
use crate::hv::kvm::bindings::{
KvmMapGpaRangeFlag, KVM_EXIT_IO_IN, KVM_EXIT_IO_OUT, KVM_HC_MAP_GPA_RANGE,
};
use crate::hv::{Error, VmExit};
use super::vcpu::KvmVcpu;
@ -60,4 +62,19 @@ impl KvmVcpu {
size: kvm_io.size,
})
}
pub(super) fn handle_hypercall(&mut self) -> Result<VmExit, Error> {
let hypercall = unsafe { self.kvm_run.exit.hypercall };
match hypercall.nr {
KVM_HC_MAP_GPA_RANGE => {
let flag = KvmMapGpaRangeFlag::from_bits_retain(hypercall.args[2]);
Ok(VmExit::ConvertMemory {
gpa: hypercall.args[0],
size: hypercall.args[1] << 12,
private: flag.contains(KvmMapGpaRangeFlag::ENCRYPTED),
})
}
_ => unimplemented!(),
}
}
}