mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45: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]]
|
||||
name = "mshv-bindings"
|
||||
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 = [
|
||||
"libc",
|
||||
"serde",
|
||||
@ -608,7 +608,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "mshv-ioctls"
|
||||
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 = [
|
||||
"libc",
|
||||
"mshv-bindings",
|
||||
|
@ -5,17 +5,16 @@
|
||||
|
||||
use crate::arch::emulator::{PlatformEmulator, PlatformError};
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::x86::emulator::{Emulator, EmulatorCpuState};
|
||||
use crate::cpu;
|
||||
use crate::cpu::Vcpu;
|
||||
use crate::hypervisor;
|
||||
use crate::vec_with_array_field;
|
||||
use crate::vm::{self, VmmOps};
|
||||
pub use mshv_bindings::*;
|
||||
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 std::sync::Arc;
|
||||
use vm::DataMatch;
|
||||
@ -29,7 +28,6 @@ pub use x86_64::VcpuMshvState as CpuState;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
pub use x86_64::*;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::RwLock;
|
||||
|
||||
@ -101,12 +99,9 @@ impl hypervisor::Hypervisor for MshvHypervisor {
|
||||
}
|
||||
let vm_fd = Arc::new(fd);
|
||||
|
||||
let gsi_routes = Arc::new(RwLock::new(HashMap::new()));
|
||||
|
||||
Ok(Arc::new(MshvVm {
|
||||
fd: vm_fd,
|
||||
msrs,
|
||||
gsi_routes,
|
||||
hv_state: hv_state_init(),
|
||||
vmmops: None,
|
||||
}))
|
||||
@ -135,7 +130,6 @@ pub struct MshvVcpu {
|
||||
vp_index: u8,
|
||||
cpuid: CpuId,
|
||||
msrs: MsrEntries,
|
||||
gsi_routes: Arc<RwLock<HashMap<u32, MshvIrqRoutingEntry>>>,
|
||||
hv_state: Arc<RwLock<HvState>>, // Mshv State
|
||||
vmmops: Option<Arc<Box<dyn vm::VmmOps>>>,
|
||||
}
|
||||
@ -673,8 +667,6 @@ impl<'a> PlatformEmulator for MshvEmulatorContext<'a> {
|
||||
pub struct MshvVm {
|
||||
fd: Arc<VmFd>,
|
||||
msrs: MsrEntries,
|
||||
// GSI routing information
|
||||
gsi_routes: Arc<RwLock<HashMap<u32, MshvIrqRoutingEntry>>>,
|
||||
// Hypervisor State
|
||||
hv_state: Arc<RwLock<HvState>>,
|
||||
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<()> {
|
||||
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
|
||||
.register_irqfd(&fd, gsi, &request)
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
||||
} else {
|
||||
error!("No routing info found for GSI {}", gsi)
|
||||
}
|
||||
self.fd
|
||||
.register_irqfd(&fd, gsi)
|
||||
.map_err(|e| vm::HypervisorVmError::RegisterIrqFd(e.into()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -760,7 +742,6 @@ impl vm::Vm for MshvVm {
|
||||
vp_index: id,
|
||||
cpuid: CpuId::new(1).unwrap(),
|
||||
msrs: self.msrs.clone(),
|
||||
gsi_routes: self.gsi_routes.clone(),
|
||||
hv_state: self.hv_state.clone(),
|
||||
vmmops,
|
||||
};
|
||||
@ -844,17 +825,20 @@ impl vm::Vm for MshvVm {
|
||||
)))
|
||||
}
|
||||
|
||||
fn set_gsi_routing(&self, irq_routing: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||
let mut routes = self.gsi_routes.write().unwrap();
|
||||
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||
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();
|
||||
|
||||
for r in irq_routing {
|
||||
debug!("gsi routing {:x?}", r);
|
||||
routes.insert(r.gsi, *r);
|
||||
unsafe {
|
||||
let entries_slice: &mut [mshv_msi_routing_entry] =
|
||||
msi_routing[0].entries.as_mut_slice(entries.len());
|
||||
entries_slice.copy_from_slice(&entries);
|
||||
}
|
||||
|
||||
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
|
||||
@ -880,104 +864,6 @@ impl vm::Vm for MshvVm {
|
||||
}
|
||||
pub use hv_cpuid_entry as CpuIdEntry;
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
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 type IrqRoutingEntry = mshv_msi_routing_entry;
|
||||
|
||||
pub const CPUID_FLAG_VALID_INDEX: u32 = 0;
|
||||
|
@ -423,9 +423,9 @@ pub mod mshv {
|
||||
use super::*;
|
||||
use hypervisor::mshv::*;
|
||||
|
||||
type MshvMsiInterruptGroup = MsiInterruptGroup<MshvIrqRoutingEntry>;
|
||||
type MshvRoutingEntry = RoutingEntry<MshvIrqRoutingEntry>;
|
||||
pub type MshvMsiInterruptManager = MsiInterruptManager<MshvIrqRoutingEntry>;
|
||||
type MshvMsiInterruptGroup = MsiInterruptGroup<mshv_msi_routing_entry>;
|
||||
type MshvRoutingEntry = RoutingEntry<mshv_msi_routing_entry>;
|
||||
pub type MshvMsiInterruptManager = MsiInterruptManager<mshv_msi_routing_entry>;
|
||||
|
||||
impl RoutingEntryExt for MshvRoutingEntry {
|
||||
fn make_entry(
|
||||
@ -434,13 +434,11 @@ pub mod mshv {
|
||||
config: &InterruptSourceConfig,
|
||||
) -> Result<Box<Self>> {
|
||||
if let InterruptSourceConfig::MsiIrq(cfg) = &config {
|
||||
let route = MshvIrqRoutingEntry {
|
||||
let route = mshv_msi_routing_entry {
|
||||
gsi,
|
||||
route: MshvIrqRouting::Msi(MshvIrqRoutingMsi {
|
||||
address_lo: cfg.low_addr,
|
||||
address_hi: cfg.high_addr,
|
||||
data: cfg.data,
|
||||
}),
|
||||
address_lo: cfg.low_addr,
|
||||
address_hi: cfg.high_addr,
|
||||
data: cfg.data,
|
||||
};
|
||||
let entry = MshvRoutingEntry {
|
||||
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(
|
||||
&self,
|
||||
routes: &HashMap<u32, RoutingEntry<MshvIrqRoutingEntry>>,
|
||||
routes: &HashMap<u32, RoutingEntry<mshv_msi_routing_entry>>,
|
||||
) -> 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() {
|
||||
if entry.masked {
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user