mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-03 11:25:20 +00:00
hypervisor:mshv: Support the move of MSI routing to kernel
Signed-off-by: Vineeth Pillai <viremana@linux.microsoft.com>
This commit is contained in:
parent
7fad74cb04
commit
68401e6e4a
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -596,7 +596,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-bindings"
|
name = "mshv-bindings"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#e1e078b51fb049b38e5db32cacd44569c0ea5a1f"
|
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#1c2ae9a3bc67783f7ffe792e31de97cb851b6f4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"serde",
|
"serde",
|
||||||
@ -608,7 +608,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mshv-ioctls"
|
name = "mshv-ioctls"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#e1e078b51fb049b38e5db32cacd44569c0ea5a1f"
|
source = "git+https://github.com/cloud-hypervisor/mshv?branch=master#1c2ae9a3bc67783f7ffe792e31de97cb851b6f4e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"mshv-bindings",
|
"mshv-bindings",
|
||||||
|
@ -5,17 +5,16 @@
|
|||||||
|
|
||||||
use crate::arch::emulator::{PlatformEmulator, PlatformError};
|
use crate::arch::emulator::{PlatformEmulator, PlatformError};
|
||||||
|
|
||||||
use thiserror::Error;
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState};
|
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState};
|
||||||
use crate::cpu;
|
use crate::cpu;
|
||||||
use crate::cpu::Vcpu;
|
use crate::cpu::Vcpu;
|
||||||
use crate::hypervisor;
|
use crate::hypervisor;
|
||||||
|
use crate::vec_with_array_field;
|
||||||
use crate::vm::{self, VmmOps};
|
use crate::vm::{self, VmmOps};
|
||||||
pub use mshv_bindings::*;
|
pub use mshv_bindings::*;
|
||||||
pub use mshv_ioctls::IoEventAddress;
|
pub use mshv_ioctls::IoEventAddress;
|
||||||
use mshv_ioctls::{set_registers_64, InterruptRequest, Mshv, NoDatamatch, VcpuFd, VmFd};
|
use mshv_ioctls::{set_registers_64, Mshv, NoDatamatch, VcpuFd, VmFd};
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use vm::DataMatch;
|
use vm::DataMatch;
|
||||||
@ -29,7 +28,6 @@ pub use x86_64::VcpuMshvState as CpuState;
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub use x86_64::*;
|
pub use x86_64::*;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
@ -101,12 +99,9 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
|||||||
}
|
}
|
||||||
let vm_fd = Arc::new(fd);
|
let vm_fd = Arc::new(fd);
|
||||||
|
|
||||||
let gsi_routes = Arc::new(RwLock::new(HashMap::new()));
|
|
||||||
|
|
||||||
Ok(Arc::new(MshvVm {
|
Ok(Arc::new(MshvVm {
|
||||||
fd: vm_fd,
|
fd: vm_fd,
|
||||||
msrs,
|
msrs,
|
||||||
gsi_routes,
|
|
||||||
hv_state: hv_state_init(),
|
hv_state: hv_state_init(),
|
||||||
vmmops: None,
|
vmmops: None,
|
||||||
}))
|
}))
|
||||||
@ -135,7 +130,6 @@ pub struct MshvVcpu {
|
|||||||
vp_index: u8,
|
vp_index: u8,
|
||||||
cpuid: CpuId,
|
cpuid: CpuId,
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
gsi_routes: Arc<RwLock<HashMap<u32, MshvIrqRoutingEntry>>>,
|
|
||||||
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
||||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||||
}
|
}
|
||||||
@ -673,8 +667,6 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
|||||||
pub struct MshvVm {
|
pub struct MshvVm {
|
||||||
fd: Arc<VmFd>,
|
fd: Arc<VmFd>,
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
// GSI routing information
|
|
||||||
gsi_routes: Arc<RwLock<HashMap<u32, MshvIrqRoutingEntry>>>,
|
|
||||||
// Hypervisor State
|
// Hypervisor State
|
||||||
hv_state: Arc<RwLock<HvState>>,
|
hv_state: Arc<RwLock<HvState>>,
|
||||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||||
@ -715,19 +707,9 @@ impl vm::Vm for MshvVm {
|
|||||||
fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
|
fn register_irqfd(&self, fd: &EventFd, gsi: u32) -> vm::Result<()> {
|
||||||
debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
debug!("register_irqfd fd {} gsi {}", fd.as_raw_fd(), gsi);
|
||||||
|
|
||||||
let gsi_routes = self.gsi_routes.read().unwrap();
|
|
||||||
|
|
||||||
if let Some(e) = gsi_routes.get(&gsi) {
|
|
||||||
let msi = e
|
|
||||||
.get_msi_routing()
|
|
||||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
|
||||||
let request = msi.to_interrupt_request();
|
|
||||||
self.fd
|
self.fd
|
||||||
.register_irqfd(&fd, gsi, &request)
|
.register_irqfd(&fd, gsi)
|
||||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
||||||
} else {
|
|
||||||
error!("No routing info found for GSI {}", gsi)
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -760,7 +742,6 @@ impl vm::Vm for MshvVm {
|
|||||||
vp_index: id,
|
vp_index: id,
|
||||||
cpuid: CpuId::new(1).unwrap(),
|
cpuid: CpuId::new(1).unwrap(),
|
||||||
msrs: self.msrs.clone(),
|
msrs: self.msrs.clone(),
|
||||||
gsi_routes: self.gsi_routes.clone(),
|
|
||||||
hv_state: self.hv_state.clone(),
|
hv_state: self.hv_state.clone(),
|
||||||
vmmops,
|
vmmops,
|
||||||
};
|
};
|
||||||
@ -844,17 +825,20 @@ impl vm::Vm for MshvVm {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_gsi_routing(&self, irq_routing: &[IrqRoutingEntry]) -> vm::Result<()> {
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||||
let mut routes = self.gsi_routes.write().unwrap();
|
let mut msi_routing =
|
||||||
|
vec_with_array_field::<mshv_msi_routing, mshv_msi_routing_entry>(entries.len());
|
||||||
|
msi_routing[0].nr = entries.len() as u32;
|
||||||
|
|
||||||
routes.drain();
|
unsafe {
|
||||||
|
let entries_slice: &mut [mshv_msi_routing_entry] =
|
||||||
for r in irq_routing {
|
msi_routing[0].entries.as_mut_slice(entries.len());
|
||||||
debug!("gsi routing {:x?}", r);
|
entries_slice.copy_from_slice(&entries);
|
||||||
routes.insert(r.gsi, *r);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
self.fd
|
||||||
|
.set_msi_routing(&msi_routing[0])
|
||||||
|
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
/// Get the Vm state. Return VM specific data
|
/// Get the Vm state. Return VM specific data
|
||||||
@ -880,104 +864,6 @@ impl vm::Vm for MshvVm {
|
|||||||
}
|
}
|
||||||
pub use hv_cpuid_entry as CpuIdEntry;
|
pub use hv_cpuid_entry as CpuIdEntry;
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
pub type IrqRoutingEntry = mshv_msi_routing_entry;
|
||||||
pub struct MshvIrqRoutingMsi {
|
|
||||||
pub address_lo: u32,
|
|
||||||
pub address_hi: u32,
|
|
||||||
pub data: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub enum MshvIrqRouting {
|
|
||||||
Msi(MshvIrqRoutingMsi),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
|
||||||
pub enum MshvIrqRoutingEntryError {
|
|
||||||
#[error("Invalid MSI address: {0}")]
|
|
||||||
InvalidMsiAddress(#[source] anyhow::Error),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
|
||||||
pub struct MshvIrqRoutingEntry {
|
|
||||||
pub gsi: u32,
|
|
||||||
pub route: MshvIrqRouting,
|
|
||||||
}
|
|
||||||
pub type IrqRoutingEntry = MshvIrqRoutingEntry;
|
|
||||||
|
|
||||||
impl MshvIrqRoutingEntry {
|
|
||||||
fn get_msi_routing(&self) -> Result<MshvIrqRoutingMsi, MshvIrqRoutingEntryError> {
|
|
||||||
let MshvIrqRouting::Msi(msi) = self.route;
|
|
||||||
if msi.address_hi != 0 {
|
|
||||||
return Err(MshvIrqRoutingEntryError::InvalidMsiAddress(anyhow!(
|
|
||||||
"MSI high address part is not zero"
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Ok(msi)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MshvIrqRoutingMsi {
|
|
||||||
///
|
|
||||||
/// See Intel SDM vol3 10.11.1
|
|
||||||
/// We assume APIC ID and Hyper-V Vcpu ID are the same value
|
|
||||||
///
|
|
||||||
|
|
||||||
fn get_destination(&self) -> u64 {
|
|
||||||
((self.address_lo >> 12) & 0xff).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_destination_mode(&self) -> bool {
|
|
||||||
if (self.address_lo >> 2) & 0x1 == 0x1 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_vector(&self) -> u8 {
|
|
||||||
(self.data & 0xff) as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// True means level triggered
|
|
||||||
///
|
|
||||||
fn get_trigger_mode(&self) -> bool {
|
|
||||||
if (self.data >> 15) & 0x1 == 0x1 {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_delivery_mode(&self) -> u8 {
|
|
||||||
((self.data & 0x700) >> 8) as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Translate from architectural defined delivery mode to Hyper-V type
|
|
||||||
/// See Intel SDM vol3 10.11.2
|
|
||||||
///
|
|
||||||
fn get_interrupt_type(&self) -> Option<hv_interrupt_type> {
|
|
||||||
match self.get_delivery_mode() {
|
|
||||||
0 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_FIXED),
|
|
||||||
1 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_LOWESTPRIORITY),
|
|
||||||
2 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_SMI),
|
|
||||||
4 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_NMI),
|
|
||||||
5 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_INIT),
|
|
||||||
7 => Some(hv_interrupt_type_HV_X64_INTERRUPT_TYPE_EXTINT),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_interrupt_request(&self) -> InterruptRequest {
|
|
||||||
InterruptRequest {
|
|
||||||
interrupt_type: self.get_interrupt_type().unwrap(),
|
|
||||||
apic_id: self.get_destination(),
|
|
||||||
vector: self.get_vector() as u32,
|
|
||||||
level_triggered: self.get_trigger_mode(),
|
|
||||||
logical_destination_mode: self.get_destination_mode(),
|
|
||||||
long_mode: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
||||||
|
@ -423,9 +423,9 @@ pub mod mshv {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use hypervisor::mshv::*;
|
use hypervisor::mshv::*;
|
||||||
|
|
||||||
type MshvMsiInterruptGroup = MsiInterruptGroup<MshvIrqRoutingEntry>;
|
type MshvMsiInterruptGroup = MsiInterruptGroup<mshv_msi_routing_entry>;
|
||||||
type MshvRoutingEntry = RoutingEntry<MshvIrqRoutingEntry>;
|
type MshvRoutingEntry = RoutingEntry<mshv_msi_routing_entry>;
|
||||||
pub type MshvMsiInterruptManager = MsiInterruptManager<MshvIrqRoutingEntry>;
|
pub type MshvMsiInterruptManager = MsiInterruptManager<mshv_msi_routing_entry>;
|
||||||
|
|
||||||
impl RoutingEntryExt for MshvRoutingEntry {
|
impl RoutingEntryExt for MshvRoutingEntry {
|
||||||
fn make_entry(
|
fn make_entry(
|
||||||
@ -434,13 +434,11 @@ pub mod mshv {
|
|||||||
config: &InterruptSourceConfig,
|
config: &InterruptSourceConfig,
|
||||||
) -> Result<Box<Self>> {
|
) -> Result<Box<Self>> {
|
||||||
if let InterruptSourceConfig::MsiIrq(cfg) = &config {
|
if let InterruptSourceConfig::MsiIrq(cfg) = &config {
|
||||||
let route = MshvIrqRoutingEntry {
|
let route = mshv_msi_routing_entry {
|
||||||
gsi,
|
gsi,
|
||||||
route: MshvIrqRouting::Msi(MshvIrqRoutingMsi {
|
|
||||||
address_lo: cfg.low_addr,
|
address_lo: cfg.low_addr,
|
||||||
address_hi: cfg.high_addr,
|
address_hi: cfg.high_addr,
|
||||||
data: cfg.data,
|
data: cfg.data,
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
let entry = MshvRoutingEntry {
|
let entry = MshvRoutingEntry {
|
||||||
route,
|
route,
|
||||||
@ -457,12 +455,12 @@ pub mod mshv {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MsiInterruptGroupOps<MshvIrqRoutingEntry> for MshvMsiInterruptGroup {
|
impl MsiInterruptGroupOps<mshv_msi_routing_entry> for MshvMsiInterruptGroup {
|
||||||
fn set_gsi_routes(
|
fn set_gsi_routes(
|
||||||
&self,
|
&self,
|
||||||
routes: &HashMap<u32, RoutingEntry<MshvIrqRoutingEntry>>,
|
routes: &HashMap<u32, RoutingEntry<mshv_msi_routing_entry>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut entry_vec: Vec<MshvIrqRoutingEntry> = Vec::new();
|
let mut entry_vec: Vec<mshv_msi_routing_entry> = Vec::new();
|
||||||
for (_, entry) in routes.iter() {
|
for (_, entry) in routes.iter() {
|
||||||
if entry.masked {
|
if entry.masked {
|
||||||
continue;
|
continue;
|
||||||
|
Loading…
Reference in New Issue
Block a user