aarch64: Expose MTE to guests

A proposed set of kernel patches makes it possible to map anonymous
MAP_SHARED mappings into the IPA space of a virtual machine with MTE
enabled. With these patches we can use most features of crosvm with the
exception of pmem which relies on being able to make file mappings in the
IPA space. Therefore, we make MTE an opt-in feature via the --mte command
line argument and forbid specifying --mte together with --pmem-device
or --rw-pmem-device.

Bug: b:234779841
Change-Id: I70bf2d0a8c1aff7c5956d6009ca5169a623bc6b2
Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3892141
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Auto-Submit: Peter Collingbourne <pcc@chromium.org>
Commit-Queue: Peter Collingbourne <pcc@chromium.org>
This commit is contained in:
Peter Collingbourne 2022-09-12 17:38:45 -07:00 committed by crosvm LUCI
parent 7150e63ee3
commit 96b95accf3
11 changed files with 51 additions and 3 deletions

View file

@ -20,6 +20,7 @@ use libc::ENOTSUP;
use libc::ENXIO;
use vm_memory::GuestAddress;
use super::Config;
use super::Kvm;
use super::KvmCap;
use super::KvmVcpu;
@ -76,6 +77,16 @@ impl Kvm {
}
impl KvmVm {
/// Does platform specific initialization for the KvmVm.
pub fn init_arch(&self, cfg: &Config) -> Result<()> {
#[cfg(target_arch = "aarch64")]
if cfg.mte {
// Safe because it does not take pointer arguments.
unsafe { self.enable_raw_capability(KvmCap::ArmMte, 0, &[0, 0, 0, 0])? }
}
Ok(())
}
/// Checks if a particular `VmCap` is available, or returns None if arch-independent
/// Vm.check_capability() should handle the check.
pub fn check_capability_arch(&self, _c: VmCap) -> Option<bool> {

View file

@ -238,13 +238,15 @@ impl KvmVm {
}
})?;
Ok(KvmVm {
let vm = KvmVm {
kvm: kvm.try_clone()?,
vm: vm_descriptor,
guest_mem,
mem_regions: Arc::new(Mutex::new(BTreeMap::new())),
mem_slot_gaps: Arc::new(Mutex::new(BinaryHeap::new())),
})
};
vm.init_arch(&cfg)?;
Ok(vm)
}
fn create_vcpu(&self, id: usize) -> Result<KvmVcpu> {

View file

@ -23,6 +23,7 @@ use libc::E2BIG;
use libc::ENXIO;
use vm_memory::GuestAddress;
use super::Config;
use super::Kvm;
use super::KvmVcpu;
use super::KvmVm;
@ -158,6 +159,11 @@ impl HypervisorX86_64 for Kvm {
}
impl KvmVm {
/// Does platform specific initialization for the KvmVm.
pub fn init_arch(&self, _cfg: &Config) -> Result<()> {
Ok(())
}
/// Checks if a particular `VmCap` is available, or returns None if arch-independent
/// Vm.check_capability() should handle the check.
pub fn check_capability_arch(&self, c: VmCap) -> Option<bool> {

View file

@ -561,12 +561,17 @@ pub enum ProtectionType {
#[derive(Clone, Copy)]
pub struct Config {
#[cfg(target_arch = "aarch64")]
/// enable the Memory Tagging Extension in the guest
pub mte: bool,
pub protection_type: ProtectionType,
}
impl Default for Config {
fn default() -> Config {
Config {
#[cfg(target_arch = "aarch64")]
mte: false,
protection_type: ProtectionType::Unprotected,
}
}

View file

@ -122,4 +122,5 @@ pub enum Cap {
ArmPmuV3 = KVM_CAP_ARM_PMU_V3,
IoapicNumPins = KVM_CAP_IOAPIC_NUM_PINS,
ArmProtectedVm = KVM_CAP_ARM_PROTECTED_VM,
ArmMte = KVM_CAP_ARM_MTE,
}

View file

@ -10,7 +10,9 @@ cd "$(dirname "${BASH_SOURCE[0]}")/.."
source tools/impl/bindgen-common.sh
KVM_EXTRAS="// Added by kvm_sys/bindgen.sh
KVM_EXTRAS="// TODO(pcc): Remove this when Chrome OS updates its kernel.
pub const KVM_CAP_ARM_MTE: u32 = 205;
// Added by kvm_sys/bindgen.sh
pub const KVM_SYSTEM_EVENT_S2IDLE: u32 = 4;
pub const KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2: u64 = 0x1;
// TODO(tjeznach): Remove this when reporting KVM_IOAPIC_NUM_PINS is no longer required.

View file

@ -5,6 +5,8 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
// TODO(pcc): Remove this when Chrome OS updates its kernel.
pub const KVM_CAP_ARM_MTE: u32 = 205;
// Added by kvm_sys/bindgen.sh
pub const KVM_SYSTEM_EVENT_S2IDLE: u32 = 4;
pub const KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2: u64 = 0x1;

View file

@ -5,6 +5,8 @@
#![allow(non_snake_case)]
#![allow(dead_code)]
// TODO(pcc): Remove this when Chrome OS updates its kernel.
pub const KVM_CAP_ARM_MTE: u32 = 205;
// Added by kvm_sys/bindgen.sh
pub const KVM_SYSTEM_EVENT_S2IDLE: u32 = 4;
pub const KVM_SYSTEM_EVENT_RESET_FLAG_PSCI_RESET2: u64 = 0x1;

View file

@ -753,6 +753,10 @@ pub struct RunCommand {
)]
/// MMIO address ranges
pub mmio_address_ranges: Option<Vec<AddressRange>>,
#[cfg(target_arch = "aarch64")]
#[argh(switch)]
/// enable the Memory Tagging Extension in the guest
pub mte: bool,
#[cfg(unix)]
#[argh(option, arg_name = "N")]
/// virtio net virtual queue pairs. (default: 1)
@ -1351,6 +1355,13 @@ impl TryFrom<RunCommand> for super::config::Config {
#[cfg(target_arch = "aarch64")]
{
if cmd.mte && !(cmd.pmem_devices.is_empty() && cmd.rw_pmem_devices.is_empty()) {
return Err(
"--mte cannot be specified together with --pmem-device or --rw-pmem-device"
.to_string(),
);
}
cfg.mte = cmd.mte;
cfg.swiotlb = cmd.swiotlb;
}

View file

@ -1235,6 +1235,8 @@ pub struct Config {
pub memory: Option<u64>,
pub memory_file: Option<PathBuf>,
pub mmio_address_ranges: Vec<AddressRange>,
#[cfg(target_arch = "aarch64")]
pub mte: bool,
#[cfg(windows)]
pub net_vhost_user_tube: Option<Tube>,
pub net_vq_pairs: Option<u16>,
@ -1440,6 +1442,8 @@ impl Default for Config {
memory: None,
memory_file: None,
mmio_address_ranges: Vec::new(),
#[cfg(target_arch = "aarch64")]
mte: false,
#[cfg(windows)]
net_vhost_user_tube: None,
net_vq_pairs: None,

View file

@ -1150,6 +1150,8 @@ fn setup_vm_components(cfg: &Config) -> Result<VmComponents> {
no_smt: cfg.no_smt,
hugepages: cfg.hugepages,
hv_cfg: hypervisor::Config {
#[cfg(target_arch = "aarch64")]
mte: cfg.mte,
protection_type: cfg.protection_type,
},
vm_image,