mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 21:55:20 +00:00
9f08aa6dc2
And modify to code to use the updated interfaces. Arguments for map_guest_memory, get_dirty_bitmap, vp.run(), import_isolated_pages, modify_gpa_host_access have changed. Update these to use the new interfaces, including new MSHV_* definitions, and remove some redundant arguments. Update seccomp IOCTLs to reflect interface changes. Fix irq-related definitions naming. Bump vfio-ioctls to support mshv v0.3.0. Signed-off-by: Nuno Das Neves <nudasnev@microsoft.com>
315 lines
8.3 KiB
Rust
315 lines
8.3 KiB
Rust
// Copyright © 2019 Intel Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
|
|
//
|
|
// Copyright © 2020, Microsoft Corporation
|
|
//
|
|
// Copyright 2018-2019 CrowdStrike, Inc.
|
|
//
|
|
//
|
|
|
|
//! A generic abstraction around hypervisor functionality
|
|
//!
|
|
//! This crate offers a trait abstraction for underlying hypervisors
|
|
//!
|
|
//! # Platform support
|
|
//!
|
|
//! - x86_64
|
|
//! - arm64
|
|
//!
|
|
|
|
#[macro_use]
|
|
extern crate anyhow;
|
|
#[allow(unused_imports)]
|
|
#[macro_use]
|
|
extern crate log;
|
|
|
|
/// Architecture specific definitions
|
|
#[macro_use]
|
|
pub mod arch;
|
|
|
|
#[cfg(feature = "kvm")]
|
|
/// KVM implementation module
|
|
pub mod kvm;
|
|
|
|
/// Microsoft Hypervisor implementation module
|
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
|
pub mod mshv;
|
|
|
|
/// Hypervisor related module
|
|
mod hypervisor;
|
|
|
|
/// Vm related module
|
|
mod vm;
|
|
|
|
/// CPU related module
|
|
mod cpu;
|
|
|
|
/// Device related module
|
|
mod device;
|
|
|
|
pub use crate::hypervisor::{Hypervisor, HypervisorError};
|
|
use concat_idents::concat_idents;
|
|
#[cfg(target_arch = "x86_64")]
|
|
pub use cpu::CpuVendor;
|
|
pub use cpu::{HypervisorCpuError, Vcpu, VmExit};
|
|
pub use device::HypervisorDeviceError;
|
|
#[cfg(all(feature = "kvm", target_arch = "aarch64"))]
|
|
pub use kvm::{aarch64, GicState};
|
|
use std::sync::Arc;
|
|
pub use vm::{
|
|
DataMatch, HypervisorVmError, InterruptSourceConfig, LegacyIrqSourceConfig, MsiIrqSourceConfig,
|
|
Vm, VmOps,
|
|
};
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub enum HypervisorType {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm,
|
|
#[cfg(feature = "mshv")]
|
|
Mshv,
|
|
}
|
|
|
|
pub fn new() -> std::result::Result<Arc<dyn Hypervisor>, HypervisorError> {
|
|
#[cfg(feature = "kvm")]
|
|
if kvm::KvmHypervisor::is_available()? {
|
|
return kvm::KvmHypervisor::new();
|
|
}
|
|
|
|
#[cfg(feature = "mshv")]
|
|
if mshv::MshvHypervisor::is_available()? {
|
|
return mshv::MshvHypervisor::new();
|
|
}
|
|
|
|
Err(HypervisorError::HypervisorCreate(anyhow!(
|
|
"no supported hypervisor"
|
|
)))
|
|
}
|
|
|
|
// Returns a `Vec<T>` with a size in bytes at least as large as `size_in_bytes`.
|
|
fn vec_with_size_in_bytes<T: Default>(size_in_bytes: usize) -> Vec<T> {
|
|
let rounded_size = (size_in_bytes + size_of::<T>() - 1) / size_of::<T>();
|
|
let mut v = Vec::with_capacity(rounded_size);
|
|
v.resize_with(rounded_size, T::default);
|
|
v
|
|
}
|
|
|
|
// The kvm API has many structs that resemble the following `Foo` structure:
|
|
//
|
|
// ```
|
|
// #[repr(C)]
|
|
// struct Foo {
|
|
// some_data: u32
|
|
// entries: __IncompleteArrayField<__u32>,
|
|
// }
|
|
// ```
|
|
//
|
|
// In order to allocate such a structure, `size_of::<Foo>()` would be too small because it would not
|
|
// include any space for `entries`. To make the allocation large enough while still being aligned
|
|
// for `Foo`, a `Vec<Foo>` is created. Only the first element of `Vec<Foo>` would actually be used
|
|
// as a `Foo`. The remaining memory in the `Vec<Foo>` is for `entries`, which must be contiguous
|
|
// with `Foo`. This function is used to make the `Vec<Foo>` with enough space for `count` entries.
|
|
use std::mem::size_of;
|
|
pub fn vec_with_array_field<T: Default, F>(count: usize) -> Vec<T> {
|
|
let element_space = count * size_of::<F>();
|
|
let vec_size_bytes = size_of::<T>() + element_space;
|
|
vec_with_size_in_bytes(vec_size_bytes)
|
|
}
|
|
|
|
///
|
|
/// User memory region structure
|
|
///
|
|
#[derive(Debug, Default, Eq, PartialEq)]
|
|
pub struct UserMemoryRegion {
|
|
pub slot: u32,
|
|
pub guest_phys_addr: u64,
|
|
pub memory_size: u64,
|
|
pub userspace_addr: u64,
|
|
pub flags: u32,
|
|
}
|
|
|
|
///
|
|
/// Flags for user memory region
|
|
///
|
|
pub const USER_MEMORY_REGION_READ: u32 = 1;
|
|
pub const USER_MEMORY_REGION_WRITE: u32 = 1 << 1;
|
|
pub const USER_MEMORY_REGION_EXECUTE: u32 = 1 << 2;
|
|
pub const USER_MEMORY_REGION_LOG_DIRTY: u32 = 1 << 3;
|
|
pub const USER_MEMORY_REGION_ADJUSTABLE: u32 = 1 << 4;
|
|
|
|
#[derive(Debug)]
|
|
pub enum MpState {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm(kvm_bindings::kvm_mp_state),
|
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
|
Mshv, /* MSHV does not support MpState yet */
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub enum IoEventAddress {
|
|
Pio(u64),
|
|
Mmio(u64),
|
|
}
|
|
|
|
#[derive(Clone, serde::Serialize, serde::Deserialize)]
|
|
#[allow(clippy::large_enum_variant)]
|
|
pub enum CpuState {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm(kvm::VcpuKvmState),
|
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
|
Mshv(mshv::VcpuMshvState),
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
|
|
#[cfg(target_arch = "x86_64")]
|
|
pub enum ClockData {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm(kvm_bindings::kvm_clock_data),
|
|
#[cfg(feature = "mshv")]
|
|
Mshv(mshv::MshvClockData),
|
|
}
|
|
|
|
#[cfg(target_arch = "x86_64")]
|
|
impl ClockData {
|
|
pub fn reset_flags(&mut self) {
|
|
match self {
|
|
#[cfg(feature = "kvm")]
|
|
ClockData::Kvm(s) => s.flags = 0,
|
|
#[allow(unreachable_patterns)]
|
|
_ => {}
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone)]
|
|
pub enum IrqRoutingEntry {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm(kvm_bindings::kvm_irq_routing_entry),
|
|
#[cfg(feature = "mshv")]
|
|
Mshv(mshv_bindings::mshv_user_irq_entry),
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
|
|
pub enum StandardRegisters {
|
|
#[cfg(feature = "kvm")]
|
|
Kvm(kvm_bindings::kvm_regs),
|
|
#[cfg(all(feature = "mshv", target_arch = "x86_64"))]
|
|
Mshv(mshv_bindings::StandardRegisters),
|
|
}
|
|
|
|
macro_rules! set_x86_64_reg {
|
|
($reg_name:ident) => {
|
|
concat_idents!(method_name = "set_", $reg_name {
|
|
#[cfg(target_arch = "x86_64")]
|
|
impl StandardRegisters {
|
|
pub fn method_name(&mut self, val: u64) {
|
|
match self {
|
|
#[cfg(feature = "kvm")]
|
|
StandardRegisters::Kvm(s) => s.$reg_name = val,
|
|
#[cfg(feature = "mshv")]
|
|
StandardRegisters::Mshv(s) => s.$reg_name = val,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
macro_rules! get_x86_64_reg {
|
|
($reg_name:ident) => {
|
|
concat_idents!(method_name = "get_", $reg_name {
|
|
#[cfg(target_arch = "x86_64")]
|
|
impl StandardRegisters {
|
|
pub fn method_name(&self) -> u64 {
|
|
match self {
|
|
#[cfg(feature = "kvm")]
|
|
StandardRegisters::Kvm(s) => s.$reg_name,
|
|
#[cfg(feature = "mshv")]
|
|
StandardRegisters::Mshv(s) => s.$reg_name,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
set_x86_64_reg!(rax);
|
|
set_x86_64_reg!(rbx);
|
|
set_x86_64_reg!(rcx);
|
|
set_x86_64_reg!(rdx);
|
|
set_x86_64_reg!(rsi);
|
|
set_x86_64_reg!(rdi);
|
|
set_x86_64_reg!(rsp);
|
|
set_x86_64_reg!(rbp);
|
|
set_x86_64_reg!(r8);
|
|
set_x86_64_reg!(r9);
|
|
set_x86_64_reg!(r10);
|
|
set_x86_64_reg!(r11);
|
|
set_x86_64_reg!(r12);
|
|
set_x86_64_reg!(r13);
|
|
set_x86_64_reg!(r14);
|
|
set_x86_64_reg!(r15);
|
|
set_x86_64_reg!(rip);
|
|
set_x86_64_reg!(rflags);
|
|
|
|
get_x86_64_reg!(rax);
|
|
get_x86_64_reg!(rbx);
|
|
get_x86_64_reg!(rcx);
|
|
get_x86_64_reg!(rdx);
|
|
get_x86_64_reg!(rsi);
|
|
get_x86_64_reg!(rdi);
|
|
get_x86_64_reg!(rsp);
|
|
get_x86_64_reg!(rbp);
|
|
get_x86_64_reg!(r8);
|
|
get_x86_64_reg!(r9);
|
|
get_x86_64_reg!(r10);
|
|
get_x86_64_reg!(r11);
|
|
get_x86_64_reg!(r12);
|
|
get_x86_64_reg!(r13);
|
|
get_x86_64_reg!(r14);
|
|
get_x86_64_reg!(r15);
|
|
get_x86_64_reg!(rip);
|
|
get_x86_64_reg!(rflags);
|
|
|
|
macro_rules! set_aarch64_reg {
|
|
($reg_name:ident, $type:ty) => {
|
|
concat_idents!(method_name = "set_", $reg_name {
|
|
#[cfg(target_arch = "aarch64")]
|
|
impl StandardRegisters {
|
|
pub fn method_name(&mut self, val: $type) {
|
|
match self {
|
|
#[cfg(feature = "kvm")]
|
|
StandardRegisters::Kvm(s) => s.regs.$reg_name = val,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
macro_rules! get_aarch64_reg {
|
|
($reg_name:ident, $type:ty) => {
|
|
concat_idents!(method_name = "get_", $reg_name {
|
|
#[cfg(target_arch = "aarch64")]
|
|
impl StandardRegisters {
|
|
pub fn method_name(&self) -> $type {
|
|
match self {
|
|
#[cfg(feature = "kvm")]
|
|
StandardRegisters::Kvm(s) => s.regs.$reg_name,
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
set_aarch64_reg!(regs, [u64; 31usize]);
|
|
set_aarch64_reg!(sp, u64);
|
|
set_aarch64_reg!(pc, u64);
|
|
set_aarch64_reg!(pstate, u64);
|
|
|
|
get_aarch64_reg!(regs, [u64; 31usize]);
|
|
get_aarch64_reg!(sp, u64);
|
|
get_aarch64_reg!(pc, u64);
|
|
get_aarch64_reg!(pstate, u64);
|