Update to the latest pKVM ABI.

This involves two main changes:
 * Protected VMs must be created with KVM_VM_TYPE_ARM_PROTECTED.
 * pVM firmware is now loaded by IPA rather than memslot ID.

There are also a lot of trivial changes because the ProtectionType enum
was moved from the devices crate to the hypervisor crate.

BUG=b:209794844
TEST=Will tested manually with patched kernel and dummy firmware

Change-Id: I1dd75e20063ca4736f155292ca5f70b94664fdd9
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3330204
Auto-Submit: Andrew Walbran <qwandor@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Commit-Queue: Daniel Verkamp <dverkamp@chromium.org>
This commit is contained in:
Andrew Walbran 2021-12-10 17:13:08 +00:00 committed by Commit Bot
parent 7df3a323f7
commit 00f1c9fd46
34 changed files with 171 additions and 134 deletions

View file

@ -12,9 +12,10 @@ use base::{Event, MemoryMappingBuilder};
use devices::serial_device::{SerialHardware, SerialParameters};
use devices::{
Bus, BusDeviceObj, BusError, IrqChip, IrqChipAArch64, PciAddress, PciConfigMmio, PciDevice,
ProtectionType,
};
use hypervisor::{DeviceKind, Hypervisor, HypervisorCap, VcpuAArch64, VcpuFeature, VmAArch64};
use hypervisor::{
DeviceKind, Hypervisor, HypervisorCap, ProtectionType, VcpuAArch64, VcpuFeature, VmAArch64,
};
use minijail::Minijail;
use remain::sorted;
use resources::SystemAllocator;
@ -351,7 +352,7 @@ impl arch::LinuxArch for AArch64 {
}
if components.protected_vm == ProtectionType::Protected {
vm.enable_protected_vm(
vm.load_protected_vm_firmware(
GuestAddress(AARCH64_PROTECTED_VM_FW_START),
AARCH64_PROTECTED_VM_FW_MAX_SIZE,
)

View file

@ -20,10 +20,10 @@ use base::{syslog, AsRawDescriptor, AsRawDescriptors, Event, Tube};
use devices::virtio::VirtioDevice;
use devices::{
Bus, BusDevice, BusDeviceObj, BusError, BusResumeDevice, HotPlugBus, IrqChip, PciAddress,
PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProtectionType, ProxyDevice,
SerialHardware, SerialParameters, VfioPlatformDevice,
PciDevice, PciDeviceError, PciInterruptPin, PciRoot, ProxyDevice, SerialHardware,
SerialParameters, VfioPlatformDevice,
};
use hypervisor::{IoEventAddress, Vm};
use hypervisor::{IoEventAddress, ProtectionType, Vm};
use minijail::Minijail;
use remain::sorted;
use resources::{MmioType, SystemAllocator};

View file

@ -7,7 +7,8 @@ use std::sync::Arc;
use base::Event;
use devices::serial_device::{SerialHardware, SerialParameters, SerialType};
use devices::{Bus, ProtectionType, ProxyDevice, Serial};
use devices::{Bus, ProxyDevice, Serial};
use hypervisor::ProtectionType;
use minijail::Minijail;
use remain::sorted;
use sync::Mutex;

View file

@ -12,7 +12,7 @@ use std::sync::Arc;
use base::Event;
use cros_fuzz::fuzz_target;
use devices::virtio::{base_features, Block, Interrupt, Queue, VirtioDevice};
use devices::ProtectionType;
use hypervisor::ProtectionType;
use tempfile;
use vm_memory::{GuestAddress, GuestMemory};

View file

@ -180,9 +180,8 @@ impl IrqChip for KvmKernelIrqChip {
#[cfg(test)]
mod tests {
use hypervisor::kvm::{Kvm, KvmVm};
use hypervisor::{MPState, Vm};
use hypervisor::{MPState, ProtectionType, Vm};
use vm_memory::GuestMemory;
use crate::irqchip::{IrqChip, KvmKernelIrqChip};
@ -196,7 +195,8 @@ mod tests {
fn create_kvm_kernel_irqchip() {
let kvm = Kvm::new().expect("failed to instantiate Kvm");
let mem = GuestMemory::new(&[]).unwrap();
let vm = KvmVm::new(&kvm, mem).expect("failed to instantiate vm");
let vm =
KvmVm::new(&kvm, mem, ProtectionType::Unprotected).expect("failed to instantiate vm");
let mut chip = KvmKernelIrqChip::new(vm.try_clone().expect("failed to clone vm"), 1)
.expect("failed to instantiate KvmKernelIrqChip");
@ -210,7 +210,8 @@ mod tests {
fn mp_state() {
let kvm = Kvm::new().expect("failed to instantiate Kvm");
let mem = GuestMemory::new(&[]).unwrap();
let vm = KvmVm::new(&kvm, mem).expect("failed to instantiate vm");
let vm =
KvmVm::new(&kvm, mem, ProtectionType::Unprotected).expect("failed to instantiate vm");
let mut chip = KvmKernelIrqChip::new(vm.try_clone().expect("failed to clone vm"), 1)
.expect("failed to instantiate KvmKernelIrqChip");

View file

@ -723,7 +723,9 @@ mod tests {
use hypervisor::kvm::Kvm;
use vm_memory::GuestMemory;
use hypervisor::{IoapicRedirectionTableEntry, PitRWMode, TriggerMode, Vm, VmX86_64};
use hypervisor::{
IoapicRedirectionTableEntry, PitRWMode, ProtectionType, TriggerMode, Vm, VmX86_64,
};
use super::super::super::tests::*;
use crate::IrqChip;
@ -732,7 +734,8 @@ mod tests {
fn get_kernel_chip() -> KvmKernelIrqChip {
let kvm = Kvm::new().expect("failed to instantiate Kvm");
let mem = GuestMemory::new(&[]).unwrap();
let vm = KvmVm::new(&kvm, mem).expect("failed tso instantiate vm");
let vm =
KvmVm::new(&kvm, mem, ProtectionType::Unprotected).expect("failed tso instantiate vm");
let mut chip = KvmKernelIrqChip::new(vm.try_clone().expect("failed to clone vm"), 1)
.expect("failed to instantiate KvmKernelIrqChip");
@ -748,7 +751,8 @@ mod tests {
fn get_split_chip() -> KvmSplitIrqChip {
let kvm = Kvm::new().expect("failed to instantiate Kvm");
let mem = GuestMemory::new(&[]).unwrap();
let vm = KvmVm::new(&kvm, mem).expect("failed tso instantiate vm");
let vm =
KvmVm::new(&kvm, mem, ProtectionType::Unprotected).expect("failed tso instantiate vm");
let (_, device_tube) = Tube::pair().expect("failed to create irq tube");

View file

@ -68,12 +68,3 @@ pub use self::usb::host_backend::host_backend_device_provider::HostBackendDevice
pub use self::usb::xhci::xhci_controller::XhciController;
pub use self::vfio::{VfioContainer, VfioDevice};
pub use self::virtio::VirtioPciDevice;
/// Whether the VM should be run in protected mode or not.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ProtectionType {
/// The VM should be run in the unprotected mode, where the host has access to its memory.
Unprotected,
/// The VM should be run in protected mode, so the host cannot access its memory directly.
Protected,
}

View file

@ -10,9 +10,10 @@ use std::sync::Arc;
use std::thread::{self};
use base::{error, Event, RawDescriptor, Result};
use hypervisor::ProtectionType;
use crate::bus::BusAccessInfo;
use crate::{BusDevice, ProtectionType, SerialDevice};
use crate::{BusDevice, SerialDevice};
const LOOP_SIZE: usize = 0x40;

View file

@ -16,12 +16,11 @@ use base::{
error, info, read_raw_stdin, safe_descriptor_from_path, syslog, AsRawDescriptor, Event,
RawDescriptor,
};
use hypervisor::ProtectionType;
use minijail::Minijail;
use remain::sorted;
use thiserror::Error as ThisError;
use crate::ProtectionType;
#[sorted]
#[derive(ThisError, Debug)]
pub enum Error {

View file

@ -847,13 +847,13 @@ mod tests {
use data_model::{Le32, Le64};
use disk::SingleFileDisk;
use hypervisor::ProtectionType;
use tempfile::TempDir;
use vm_memory::GuestAddress;
use crate::virtio::base_features;
use crate::virtio::block::common::*;
use crate::virtio::descriptor_utils::{create_descriptor_chain, DescriptorType};
use crate::ProtectionType;
use super::*;

View file

@ -698,13 +698,13 @@ mod tests {
use std::mem::size_of_val;
use data_model::{Le32, Le64};
use hypervisor::ProtectionType;
use tempfile::tempfile;
use vm_memory::GuestAddress;
use crate::virtio::base_features;
use crate::virtio::block::common::*;
use crate::virtio::descriptor_utils::{create_descriptor_chain, DescriptorType};
use crate::ProtectionType;
use super::*;

View file

@ -11,6 +11,7 @@ use std::thread;
use base::{error, Event, PollToken, RawDescriptor, WaitContext};
use data_model::{DataInit, Le16, Le32};
use hypervisor::ProtectionType;
use remain::sorted;
use sync::Mutex;
use thiserror::Error as ThisError;
@ -20,7 +21,7 @@ use super::{
base_features, copy_config, Interrupt, Queue, Reader, SignalableInterrupt, VirtioDevice,
Writer, TYPE_CONSOLE,
};
use crate::{ProtectionType, SerialDevice};
use crate::SerialDevice;
pub(crate) const QUEUE_SIZE: u16 = 256;

View file

@ -59,10 +59,10 @@ pub use self::virtio_device::*;
pub use self::virtio_pci_device::*;
pub use self::wl::*;
use crate::ProtectionType;
use std::cmp;
use std::convert::TryFrom;
use hypervisor::ProtectionType;
use virtio_sys::virtio_ring::VIRTIO_RING_F_EVENT_IDX;
const DEVICE_RESET: u32 = 0x0;

View file

@ -355,7 +355,7 @@ pub mod tests {
use super::*;
use crate::virtio::base_features;
use crate::virtio::VIRTIO_MSI_NO_VECTOR;
use crate::ProtectionType;
use hypervisor::ProtectionType;
use net_util::fakes::FakeTap;
use std::path::PathBuf;
use std::result;

View file

@ -19,6 +19,7 @@ use base::{error, iov_max, warn, Event, Timer};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor, TimerAsync};
use data_model::DataInit;
use disk::create_async_disk_file;
use hypervisor::ProtectionType;
use vm_memory::GuestMemory;
use crate::virtio::block::asynchronous::{flush_disk, process_one_chain};
@ -27,7 +28,6 @@ use crate::virtio::vhost::user::device::handler::{
CallEvent, DeviceRequestHandler, VhostUserBackend,
};
use crate::virtio::{self, base_features, copy_config, Queue};
use crate::ProtectionType;
static BLOCK_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -15,6 +15,7 @@ use data_model::DataInit;
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
@ -28,7 +29,6 @@ use crate::virtio::vhost::user::device::handler::{
CallEvent, DeviceRequestHandler, VhostUserBackend,
};
use crate::virtio::{self, copy_config};
use crate::ProtectionType;
static CONSOLE_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -15,6 +15,7 @@ use data_model::{DataInit, Le32};
use fuse::Server;
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use hypervisor::ProtectionType;
use minijail::{self, Minijail};
use once_cell::sync::OnceCell;
use sync::Mutex;
@ -28,7 +29,6 @@ use crate::virtio::fs::{process_fs_queue, virtio_fs_config, FS_MAX_TAG_LEN};
use crate::virtio::vhost::user::device::handler::{
CallEvent, DeviceRequestHandler, VhostUserBackend,
};
use crate::ProtectionType;
static FS_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -17,19 +17,16 @@ use futures::{
pin_mut,
};
use getopts::Options;
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use crate::{
virtio::{
self, gpu,
vhost::user::device::handler::{CallEvent, DeviceRequestHandler, VhostUserBackend},
DescriptorChain, Gpu, GpuDisplayParameters, GpuParameters, Queue, QueueReader,
VirtioDevice,
},
ProtectionType,
use crate::virtio::{
self, gpu,
vhost::user::device::handler::{CallEvent, DeviceRequestHandler, VhostUserBackend},
DescriptorChain, Gpu, GpuDisplayParameters, GpuParameters, Queue, QueueReader, VirtioDevice,
};
static GPU_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -13,6 +13,7 @@ use cros_async::{EventAsync, Executor, IoSourceExt};
use data_model::DataInit;
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use hypervisor::ProtectionType;
use net_util::{MacAddress, Tap, TapT};
use once_cell::sync::OnceCell;
use sync::Mutex;
@ -20,6 +21,7 @@ use virtio_sys::virtio_net;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};
use crate::virtio;
use crate::virtio::net::{
build_config, process_ctrl, process_rx, process_tx, validate_and_configure_tap,
virtio_features_to_tap_offload, NetError,
@ -27,7 +29,6 @@ use crate::virtio::net::{
use crate::virtio::vhost::user::device::handler::{
CallEvent, DeviceRequestHandler, VhostUserBackend,
};
use crate::{virtio, ProtectionType};
thread_local! {
static NET_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -22,6 +22,7 @@ use base::{
use cros_async::{AsyncWrapper, Executor};
use data_model::{DataInit, Le64};
use getopts::Options;
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use vhost::{self, Vhost, Vsock};
use vm_memory::GuestMemory;
@ -34,16 +35,13 @@ use vmm_vhost::{
Error, Result, SlaveReqHandler, VhostUserSlaveReqHandlerMut,
};
use crate::{
virtio::{
base_features,
vhost::{
user::device::handler::{create_guest_memory, vmm_va_to_gpa, MappingInfo},
vsock,
},
Queue,
use crate::virtio::{
base_features,
vhost::{
user::device::handler::{create_guest_memory, vmm_va_to_gpa, MappingInfo},
vsock,
},
ProtectionType,
Queue,
};
static VSOCK_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -19,6 +19,7 @@ use base::{
use cros_async::{AsyncWrapper, EventAsync, Executor, IoSourceExt};
use futures::future::{AbortHandle, Abortable};
use getopts::Options;
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
@ -28,7 +29,6 @@ use crate::virtio::vhost::user::device::handler::{
CallEvent, DeviceRequestHandler, VhostUserBackend,
};
use crate::virtio::{base_features, wl, Queue};
use crate::ProtectionType;
static WL_EXECUTOR: OnceCell<Executor> = OnceCell::new();

View file

@ -19,9 +19,11 @@ pub trait VmAArch64: Vm {
/// Gets the `Hypervisor` that created this VM.
fn get_hypervisor(&self) -> &dyn Hypervisor;
/// Enables protected mode for the VM, creating a memslot for the firmware as needed.
/// Only works on VMs that support `VmCap::Protected`.
fn enable_protected_vm(&mut self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()>;
/// Load pVM firmware for the VM, creating a memslot for it as needed.
///
/// Only works on protected VMs (i.e. those that support `VmCap::Protected`).
fn load_protected_vm_firmware(&mut self, fw_addr: GuestAddress, fw_max_size: u64)
-> Result<()>;
/// Create a Vcpu with the specified Vcpu ID.
fn create_vcpu(&self, id: usize) -> Result<Box<dyn VcpuAArch64>>;

View file

@ -9,13 +9,12 @@ use base::{
MemoryMappingBuilder, Result,
};
use kvm_sys::*;
use std::os::raw::c_ulong;
use vm_memory::GuestAddress;
use super::{Kvm, KvmCap, KvmVcpu, KvmVm};
use crate::{
ClockState, DeviceKind, Hypervisor, IrqSourceChip, PsciVersion, VcpuAArch64, VcpuFeature, Vm,
VmAArch64, VmCap,
ClockState, DeviceKind, Hypervisor, IrqSourceChip, ProtectionType, PsciVersion, VcpuAArch64,
VcpuFeature, Vm, VmAArch64, VmCap,
};
impl Kvm {
@ -23,15 +22,21 @@ impl Kvm {
// Ideally, this would take a description of the memory map and return
// the closest machine type for this VM. Here, we just return the maximum
// the kernel support.
pub fn get_vm_type(&self) -> c_ulong {
pub fn get_vm_type(&self, protection_type: ProtectionType) -> Result<u32> {
// Safe because we know self is a real kvm fd
match unsafe { ioctl_with_val(self, KVM_CHECK_EXTENSION(), KVM_CAP_ARM_VM_IPA_SIZE.into()) }
{
let ipa_size = match unsafe {
ioctl_with_val(self, KVM_CHECK_EXTENSION(), KVM_CAP_ARM_VM_IPA_SIZE.into())
} {
// Not supported? Use 0 as the machine type, which implies 40bit IPA
ret if ret < 0 => 0,
// Use the lower 8 bits representing the IPA space as the machine type
ipa => (ipa & 0xff) as c_ulong,
}
ipa => ipa as u32,
};
let protection_flag = match protection_type {
ProtectionType::Unprotected => 0,
ProtectionType::Protected => KVM_VM_TYPE_ARM_PROTECTED,
};
// Use the lower 8 bits representing the IPA space as the machine type
Ok((ipa_size & KVM_VM_TYPE_ARM_IPA_SIZE_MASK) | protection_flag)
}
}
@ -86,6 +91,17 @@ impl KvmVm {
}?;
Ok(info)
}
fn set_protected_vm_firmware_ipa(&self, fw_addr: GuestAddress) -> Result<()> {
// Safe because none of the args are pointers.
unsafe {
self.enable_raw_capability(
KvmCap::ArmProtectedVm,
KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA,
&[fw_addr.0, 0, 0, 0],
)
}
}
}
#[repr(C)]
@ -99,13 +115,17 @@ impl VmAArch64 for KvmVm {
&self.kvm
}
fn enable_protected_vm(&mut self, fw_addr: GuestAddress, fw_max_size: u64) -> Result<()> {
fn load_protected_vm_firmware(
&mut self,
fw_addr: GuestAddress,
fw_max_size: u64,
) -> Result<()> {
if !self.check_capability(VmCap::Protected) {
return Err(Error::new(ENOSYS));
}
let info = self.get_protected_vm_info()?;
let memslot = if info.firmware_size == 0 {
u64::MAX
if info.firmware_size == 0 {
Err(Error::new(EINVAL))
} else {
if info.firmware_size > fw_max_size {
return Err(Error::new(ENOMEM));
@ -113,15 +133,8 @@ impl VmAArch64 for KvmVm {
let mem = MemoryMappingBuilder::new(info.firmware_size as usize)
.build()
.map_err(|_| Error::new(EINVAL))?;
self.add_memory_region(fw_addr, Box::new(mem), false, false)? as u64
};
// Safe because none of the args are pointers.
unsafe {
self.enable_raw_capability(
KvmCap::ArmProtectedVm,
KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE,
&[memslot, 0, 0, 0],
)
self.add_memory_region(fw_addr, Box::new(mem), false, false)?;
self.set_protected_vm_firmware_ipa(fw_addr)
}
}
@ -333,7 +346,7 @@ mod tests {
fn set_gsi_routing() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.create_irq_chip().unwrap();
vm.set_gsi_routing(&[]).unwrap();
vm.set_gsi_routing(&[IrqRoute {

View file

@ -42,7 +42,7 @@ use vm_memory::{GuestAddress, GuestMemory};
use crate::{
ClockState, Datamatch, DeviceKind, Hypervisor, HypervisorCap, IoEventAddress, IrqRoute,
IrqSource, MPState, MemSlot, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap,
IrqSource, MPState, MemSlot, ProtectionType, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap,
};
// Wrapper around KVM_SET_USER_MEMORY_REGION ioctl, which creates, modifies, or deletes a mapping
@ -163,10 +163,20 @@ pub struct KvmVm {
impl KvmVm {
/// Constructs a new `KvmVm` using the given `Kvm` instance.
pub fn new(kvm: &Kvm, guest_mem: GuestMemory) -> Result<KvmVm> {
pub fn new(
kvm: &Kvm,
guest_mem: GuestMemory,
protection_type: ProtectionType,
) -> Result<KvmVm> {
// Safe because we know kvm is a real kvm fd as this module is the only one that can make
// Kvm objects.
let ret = unsafe { ioctl_with_val(kvm, KVM_CREATE_VM(), kvm.get_vm_type()) };
let ret = unsafe {
ioctl_with_val(
kvm,
KVM_CREATE_VM(),
kvm.get_vm_type(protection_type)? as c_ulong,
)
};
if ret < 0 {
return errno_result();
}
@ -1194,14 +1204,14 @@ mod tests {
fn create_vm() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
KvmVm::new(&kvm, gm).unwrap();
KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
}
#[test]
fn clone_vm() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.try_clone().unwrap();
}
@ -1209,7 +1219,7 @@ mod tests {
fn send_vm() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
thread::spawn(move || {
let _vm = vm;
})
@ -1221,7 +1231,7 @@ mod tests {
fn check_vm_capability() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
assert!(vm.check_raw_capability(KvmCap::UserMemory));
// I assume nobody is testing this on s390
assert!(!vm.check_raw_capability(KvmCap::S390UserSigp));
@ -1231,7 +1241,7 @@ mod tests {
fn create_vcpu() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.create_vcpu(0).unwrap();
}
@ -1239,7 +1249,7 @@ mod tests {
fn get_memory() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let obj_addr = GuestAddress(0xf0);
vm.get_memory().write_obj_at_addr(67u8, obj_addr).unwrap();
let read_val: u8 = vm.get_memory().read_obj_from_addr(obj_addr).unwrap();
@ -1251,7 +1261,7 @@ mod tests {
let kvm = Kvm::new().unwrap();
let gm =
GuestMemory::new(&[(GuestAddress(0), 0x1000), (GuestAddress(0x5000), 0x5000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mem_size = 0x1000;
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
vm.add_memory_region(GuestAddress(0x1000), Box::new(mem), false, false)
@ -1265,7 +1275,7 @@ mod tests {
fn add_memory_ro() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mem_size = 0x1000;
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
vm.add_memory_region(GuestAddress(0x1000), Box::new(mem), true, false)
@ -1276,7 +1286,7 @@ mod tests {
fn remove_memory() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mem_size = 0x1000;
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
let mem_ptr = mem.as_ptr();
@ -1292,7 +1302,7 @@ mod tests {
fn remove_invalid_memory() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
assert!(vm.remove_memory_region(0).is_err());
}
@ -1300,7 +1310,7 @@ mod tests {
fn overlap_memory() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mem_size = 0x2000;
let mem = MemoryMappingBuilder::new(mem_size).build().unwrap();
assert!(vm
@ -1313,7 +1323,7 @@ mod tests {
let kvm = Kvm::new().unwrap();
let gm =
GuestMemory::new(&[(GuestAddress(0), 0x1000), (GuestAddress(0x5000), 0x5000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mem_size = 0x1000;
let mem = MemoryMappingArena::new(mem_size).unwrap();
let slot = vm
@ -1328,7 +1338,7 @@ mod tests {
fn register_irqfd() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let evtfd1 = Event::new().unwrap();
let evtfd2 = Event::new().unwrap();
let evtfd3 = Event::new().unwrap();
@ -1343,7 +1353,7 @@ mod tests {
fn unregister_irqfd() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let evtfd1 = Event::new().unwrap();
let evtfd2 = Event::new().unwrap();
let evtfd3 = Event::new().unwrap();
@ -1360,7 +1370,7 @@ mod tests {
fn irqfd_resample() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let evtfd1 = Event::new().unwrap();
let evtfd2 = Event::new().unwrap();
vm.create_irq_chip().unwrap();
@ -1375,7 +1385,7 @@ mod tests {
fn set_signal_mask() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
vcpu.set_signal_mask(&[base::SIGRTMIN() + 0]).unwrap();
}
@ -1393,7 +1403,7 @@ mod tests {
fn register_ioevent() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let evtfd = Event::new().unwrap();
vm.register_ioevent(&evtfd, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
.unwrap();
@ -1429,7 +1439,7 @@ mod tests {
fn unregister_ioevent() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let mut vm = KvmVm::new(&kvm, gm).unwrap();
let mut vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let evtfd = Event::new().unwrap();
vm.register_ioevent(&evtfd, IoEventAddress::Pio(0xf4), Datamatch::AnyLength)
.unwrap();

View file

@ -12,15 +12,14 @@ use base::{
};
use data_model::vec_with_array_field;
use kvm_sys::*;
use std::os::raw::c_ulong;
use vm_memory::GuestAddress;
use super::{Kvm, KvmVcpu, KvmVm};
use crate::{
ClockState, CpuId, CpuIdEntry, DebugRegs, DescriptorTable, DeviceKind, Fpu, HypervisorX86_64,
IoapicRedirectionTableEntry, IoapicState, IrqSourceChip, LapicState, PicSelect, PicState,
PitChannelState, PitState, Register, Regs, Segment, Sregs, VcpuX86_64, VmCap, VmX86_64,
MAX_IOAPIC_PINS, NUM_IOAPIC_PINS,
PitChannelState, PitState, ProtectionType, Register, Regs, Segment, Sregs, VcpuX86_64, VmCap,
VmX86_64, MAX_IOAPIC_PINS, NUM_IOAPIC_PINS,
};
type KvmCpuId = kvm::CpuId;
@ -66,9 +65,14 @@ impl Kvm {
get_cpuid_with_initial_capacity(self, kind, KVM_MAX_ENTRIES)
}
// The x86 machine type is always 0
pub fn get_vm_type(&self) -> c_ulong {
0
// The x86 machine type is always 0. Protected VMs are not supported.
pub fn get_vm_type(&self, protection_type: ProtectionType) -> Result<u32> {
if protection_type == ProtectionType::Unprotected {
Ok(0)
} else {
error!("Protected mode is not supported on x86_64.");
Err(Error::new(libc::EINVAL))
}
}
}
@ -1250,7 +1254,7 @@ mod tests {
fn check_vm_arch_capability() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x1000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
assert!(vm.check_capability(VmCap::PvClock));
}
@ -1426,7 +1430,7 @@ mod tests {
fn clock_handling() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let mut clock_data = vm.get_pvclock().unwrap();
clock_data.clock += 1000;
vm.set_pvclock(&clock_data).unwrap();
@ -1436,7 +1440,7 @@ mod tests {
fn set_gsi_routing() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.create_irq_chip().unwrap();
vm.set_gsi_routing(&[]).unwrap();
vm.set_gsi_routing(&[IrqRoute {
@ -1478,7 +1482,7 @@ mod tests {
fn set_identity_map_addr() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.set_identity_map_addr(GuestAddress(0x20000)).unwrap();
}
@ -1486,7 +1490,7 @@ mod tests {
fn mp_state() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.create_irq_chip().unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
let state = vcpu.get_mp_state().unwrap();
@ -1497,7 +1501,7 @@ mod tests {
fn enable_feature() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
vm.create_irq_chip().unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
unsafe { vcpu.enable_raw_capability(kvm_sys::KVM_CAP_HYPERV_SYNIC, &[0; 4]) }.unwrap();
@ -1522,7 +1526,7 @@ mod tests {
fn debugregs() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
let mut dregs = vcpu.get_debugregs().unwrap();
dregs.dr7 = 13;
@ -1539,7 +1543,7 @@ mod tests {
}
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
let mut xcrs = vcpu.get_xcrs().unwrap();
xcrs[0].value = 1;
@ -1552,7 +1556,7 @@ mod tests {
fn get_msrs() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
let mut msrs = vec![
// This one should succeed
@ -1574,7 +1578,7 @@ mod tests {
fn set_msrs() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
const MSR_TSC_AUX: u32 = 0xc0000103;
@ -1595,7 +1599,7 @@ mod tests {
fn get_hyperv_cpuid() {
let kvm = Kvm::new().unwrap();
let gm = GuestMemory::new(&[(GuestAddress(0), 0x10000)]).unwrap();
let vm = KvmVm::new(&kvm, gm).unwrap();
let vm = KvmVm::new(&kvm, gm, ProtectionType::Unprotected).unwrap();
let vcpu = vm.create_vcpu(0).unwrap();
let cpuid = vcpu.get_hyperv_cpuid();
// Older kernels don't support so tolerate this kind of failure.

View file

@ -439,3 +439,12 @@ pub enum MPState {
/// the vcpu is stopped (arm/arm64)
Stopped,
}
/// Whether the VM should be run in protected mode or not.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ProtectionType {
/// The VM should be run in the unprotected mode, where the host has access to its memory.
Unprotected,
/// The VM should be run in protected mode, so the host cannot access its memory directly.
Protected,
}

View file

@ -481,7 +481,8 @@ pub const KVM_VM_MIPS_AUTO: u32 = 0;
pub const KVM_VM_MIPS_VZ: u32 = 1;
pub const KVM_VM_MIPS_TE: u32 = 2;
pub const KVM_S390_SIE_PAGE_OFFSET: u32 = 1;
pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 255;
pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 0xff;
pub const KVM_VM_TYPE_ARM_PROTECTED: u32 = 0x100;
pub const KVM_CAP_IRQCHIP: u32 = 0;
pub const KVM_CAP_HLT: u32 = 1;
pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: u32 = 2;
@ -663,7 +664,7 @@ pub const KVM_CAP_ENFORCE_PV_FEATURE_CPUID: u32 = 190;
pub const KVM_CAP_IOAPIC_NUM_PINS: u32 = 8191;
// TODO(qwandor): Update this once the pKVM patches are merged upstream with a stable capability ID.
pub const KVM_CAP_ARM_PROTECTED_VM: u32 = 0xffbadab1;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE: u32 = 0;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA: u32 = 0;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO: u32 = 1;
pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1;
pub const KVM_IRQ_ROUTING_MSI: u32 = 2;

View file

@ -397,7 +397,8 @@ pub const KVM_VM_MIPS_AUTO: u32 = 0;
pub const KVM_VM_MIPS_VZ: u32 = 1;
pub const KVM_VM_MIPS_TE: u32 = 2;
pub const KVM_S390_SIE_PAGE_OFFSET: u32 = 1;
pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 255;
pub const KVM_VM_TYPE_ARM_IPA_SIZE_MASK: u32 = 0xff;
pub const KVM_VM_TYPE_ARM_PROTECTED: u32 = 0x100;
pub const KVM_CAP_IRQCHIP: u32 = 0;
pub const KVM_CAP_HLT: u32 = 1;
pub const KVM_CAP_MMU_SHADOW_CACHE_CONTROL: u32 = 2;
@ -572,7 +573,7 @@ pub const KVM_CAP_HYPERV_DIRECT_TLBFLUSH: u32 = 175;
pub const KVM_CAP_IOAPIC_NUM_PINS: u32 = 8191;
// TODO(qwandor): Update this once the pKVM patches are merged upstream with a stable capability ID.
pub const KVM_CAP_ARM_PROTECTED_VM: u32 = 0xffbadab1;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_ENABLE: u32 = 0;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_SET_FW_IPA: u32 = 0;
pub const KVM_CAP_ARM_PROTECTED_VM_FLAGS_INFO: u32 = 1;
pub const KVM_IRQ_ROUTING_IRQCHIP: u32 = 1;
pub const KVM_IRQ_ROUTING_MSI: u32 = 2;

View file

@ -33,8 +33,8 @@ use devices::virtio::VideoBackendType;
use devices::Ac97Parameters;
#[cfg(feature = "direct")]
use devices::BusRange;
use devices::ProtectionType;
use devices::StubPciParameters;
use hypervisor::ProtectionType;
use libc::{getegid, geteuid};
use vm_control::BatteryType;

View file

@ -50,7 +50,6 @@ use devices::virtio::{
};
#[cfg(feature = "audio")]
use devices::Ac97Dev;
use devices::ProtectionType;
use devices::{
self, BusDeviceObj, HostHotPlugKey, HotPlugBus, IrqChip, IrqEventIndex, KvmKernelIrqChip,
PciAddress, PciBridge, PciDevice, PcieRootPort, StubPciDevice, VcpuRunState, VfioContainer,
@ -59,7 +58,7 @@ use devices::{
#[cfg(feature = "usb")]
use devices::{HostBackendDeviceProvider, XhciController};
use hypervisor::kvm::{Kvm, KvmVcpu, KvmVm};
use hypervisor::{HypervisorCap, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
use hypervisor::{HypervisorCap, ProtectionType, Vcpu, VcpuExit, VcpuRunHandle, Vm, VmCap};
use minijail::{self, Minijail};
use net_util::{MacAddress, Tap};
use resources::{Alloc, MmioType, SystemAllocator};
@ -2581,7 +2580,7 @@ pub fn run_config(cfg: Config) -> Result<ExitState> {
}
guest_mem.set_memory_policy(mem_policy);
let kvm = Kvm::new_with_path(&cfg.kvm_device_path).context("failed to create kvm")?;
let vm = KvmVm::new(&kvm, guest_mem).context("failed to create vm")?;
let vm = KvmVm::new(&kvm, guest_mem, components.protected_vm).context("failed to create vm")?;
let vm_clone = vm.try_clone().context("failed to clone vm")?;
enum KvmIrqChip {

View file

@ -49,12 +49,13 @@ use devices::virtio::{
use devices::BusRange;
#[cfg(feature = "audio")]
use devices::{Ac97Backend, Ac97Parameters};
use devices::{PciAddress, PciClassCode, ProtectionType, StubPciParameters};
use devices::{PciAddress, PciClassCode, StubPciParameters};
use disk::{self, QcowFile};
#[cfg(feature = "composite-disk")]
use disk::{
create_composite_disk, create_disk_file, create_zero_filler, ImagePartitionType, PartitionInfo,
};
use hypervisor::ProtectionType;
use vm_control::{
client::{
do_modify_battery, do_usb_attach, do_usb_detach, do_usb_list, handle_request, vms_request,

View file

@ -230,7 +230,7 @@ pub fn phy_max_address_bits() -> u32 {
#[cfg(test)]
mod tests {
use super::*;
use hypervisor::CpuIdEntry;
use hypervisor::{CpuIdEntry, ProtectionType};
#[test]
fn feature_and_vendor_name() {
@ -238,7 +238,7 @@ mod tests {
let guest_mem =
vm_memory::GuestMemory::new(&[(vm_memory::GuestAddress(0), 0x10000)]).unwrap();
let kvm = hypervisor::kvm::Kvm::new().unwrap();
let vm = hypervisor::kvm::KvmVm::new(&kvm, guest_mem).unwrap();
let vm = hypervisor::kvm::KvmVm::new(&kvm, guest_mem, ProtectionType::Unprotected).unwrap();
let irq_chip = devices::KvmKernelIrqChip::new(vm, 1).unwrap();
let entries = &mut cpuid.cpu_id_entries;

View file

@ -60,9 +60,9 @@ use base::Event;
use devices::serial_device::{SerialHardware, SerialParameters};
use devices::{
BusDeviceObj, BusResumeDevice, IrqChip, IrqChipX86_64, PciAddress, PciConfigIo, PciConfigMmio,
PciDevice, ProtectionType,
PciDevice,
};
use hypervisor::{HypervisorX86_64, VcpuX86_64, VmX86_64};
use hypervisor::{HypervisorX86_64, ProtectionType, VcpuX86_64, VmX86_64};
use minijail::Minijail;
use remain::sorted;
use resources::SystemAllocator;

View file

@ -5,8 +5,8 @@
#![cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use arch::LinuxArch;
use devices::{IrqChipX86_64, ProtectionType};
use hypervisor::{HypervisorX86_64, VcpuExit, VcpuX86_64, VmX86_64};
use devices::IrqChipX86_64;
use hypervisor::{HypervisorX86_64, ProtectionType, VcpuExit, VcpuX86_64, VmX86_64};
use vm_memory::{GuestAddress, GuestMemory};
use super::cpuid::setup_cpuid;
@ -41,7 +41,8 @@ fn simple_kvm_kernel_irqchip_test() {
simple_vm_test::<_, _, KvmVcpu, _, _, _>(
|guest_mem| {
let kvm = Kvm::new().expect("failed to create kvm");
let vm = KvmVm::new(&kvm, guest_mem).expect("failed to create kvm vm");
let vm = KvmVm::new(&kvm, guest_mem, ProtectionType::Unprotected)
.expect("failed to create kvm vm");
(kvm, vm)
},
|vm, vcpu_count, _| {
@ -57,7 +58,8 @@ fn simple_kvm_split_irqchip_test() {
simple_vm_test::<_, _, KvmVcpu, _, _, _>(
|guest_mem| {
let kvm = Kvm::new().expect("failed to create kvm");
let vm = KvmVm::new(&kvm, guest_mem).expect("failed to create kvm vm");
let vm = KvmVm::new(&kvm, guest_mem, ProtectionType::Unprotected)
.expect("failed to create kvm vm");
(kvm, vm)
},
|vm, vcpu_count, device_tube| {