mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-08-21 15:31:15 +00:00
vmm, hypervisor: adjust set_gsi_routing / set_gsi_routes
Make set_gsi_routing take a list of IrqRoutingEntry. The construction of hypervisor specific structure is left to set_gsi_routing. Now set_gsi_routes, which is part of the interrupt module, is only responsible for constructing a list of routing entries. This further splits hypervisor specific code from hypervisor agnostic code. Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
parent
12b37ef13b
commit
e1af251c9f
@ -58,7 +58,7 @@ pub use kvm_ioctls::{Cap, Kvm};
|
|||||||
///
|
///
|
||||||
pub use {
|
pub use {
|
||||||
kvm_bindings::kvm_clock_data as ClockData, kvm_bindings::kvm_create_device as CreateDevice,
|
kvm_bindings::kvm_clock_data as ClockData, kvm_bindings::kvm_create_device as CreateDevice,
|
||||||
kvm_bindings::kvm_irq_routing as IrqRouting, kvm_bindings::kvm_mp_state as MpState,
|
kvm_bindings::kvm_irq_routing_entry as IrqRoutingEntry, kvm_bindings::kvm_mp_state as MpState,
|
||||||
kvm_bindings::kvm_userspace_memory_region as MemoryRegion,
|
kvm_bindings::kvm_userspace_memory_region as MemoryRegion,
|
||||||
kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress,
|
kvm_bindings::kvm_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress,
|
||||||
kvm_ioctls::VcpuExit,
|
kvm_ioctls::VcpuExit,
|
||||||
@ -70,6 +70,37 @@ pub struct KvmVm {
|
|||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
msrs: MsrEntries,
|
msrs: MsrEntries,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Implementation of Vm trait for KVM
|
/// Implementation of Vm trait for KVM
|
||||||
/// Example:
|
/// Example:
|
||||||
@ -167,9 +198,20 @@ impl vm::Vm for KvmVm {
|
|||||||
/// Sets the GSI routing table entries, overwriting any previously set
|
/// Sets the GSI routing table entries, overwriting any previously set
|
||||||
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
/// entries, as per the `KVM_SET_GSI_ROUTING` ioctl.
|
||||||
///
|
///
|
||||||
fn set_gsi_routing(&self, irq_routing: &IrqRouting) -> vm::Result<()> {
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> vm::Result<()> {
|
||||||
|
let mut irq_routing =
|
||||||
|
vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(entries.len());
|
||||||
|
irq_routing[0].nr = entries.len() as u32;
|
||||||
|
irq_routing[0].flags = 0;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let entries_slice: &mut [kvm_irq_routing_entry] =
|
||||||
|
irq_routing[0].entries.as_mut_slice(entries.len());
|
||||||
|
entries_slice.copy_from_slice(&entries);
|
||||||
|
}
|
||||||
|
|
||||||
self.fd
|
self.fd
|
||||||
.set_gsi_routing(irq_routing)
|
.set_gsi_routing(&irq_routing[0])
|
||||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||||
}
|
}
|
||||||
///
|
///
|
||||||
|
@ -13,7 +13,7 @@ use crate::aarch64::VcpuInit;
|
|||||||
use crate::cpu::Vcpu;
|
use crate::cpu::Vcpu;
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
use crate::ClockData;
|
use crate::ClockData;
|
||||||
use crate::{CreateDevice, DeviceFd, IoEventAddress, IrqRouting, MemoryRegion};
|
use crate::{CreateDevice, DeviceFd, IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
||||||
use kvm_ioctls::Cap;
|
use kvm_ioctls::Cap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@ -148,7 +148,7 @@ pub trait Vm: Send + Sync {
|
|||||||
/// Unregister an event from a certain address it has been previously registered to.
|
/// Unregister an event from a certain address it has been previously registered to.
|
||||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
||||||
/// Sets the GSI routing table entries, overwriting any previously set
|
/// Sets the GSI routing table entries, overwriting any previously set
|
||||||
fn set_gsi_routing(&self, irq_routing: &IrqRouting) -> Result<()>;
|
fn set_gsi_routing(&self, entries: &[IrqRoutingEntry]) -> Result<()>;
|
||||||
/// Creates a memory region structure that can be used with set_user_memory_region
|
/// Creates a memory region structure that can be used with set_user_memory_region
|
||||||
fn make_user_memory_region(
|
fn make_user_memory_region(
|
||||||
&self,
|
&self,
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
use devices::interrupt_controller::InterruptController;
|
use devices::interrupt_controller::InterruptController;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::mem::size_of;
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use vm_allocator::SystemAllocator;
|
use vm_allocator::SystemAllocator;
|
||||||
@ -19,35 +18,6 @@ use vmm_sys_util::eventfd::EventFd;
|
|||||||
/// Reuse std::io::Result to simplify interoperability among crates.
|
/// Reuse std::io::Result to simplify interoperability among crates.
|
||||||
pub type Result<T> = std::io::Result<T>;
|
pub type Result<T> = std::io::Result<T>;
|
||||||
|
|
||||||
// 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.
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
struct InterruptRoute {
|
struct InterruptRoute {
|
||||||
pub gsi: u32,
|
pub gsi: u32,
|
||||||
pub irq_fd: EventFd,
|
pub irq_fd: EventFd,
|
||||||
@ -357,7 +327,7 @@ where
|
|||||||
pub mod kvm {
|
pub mod kvm {
|
||||||
use super::*;
|
use super::*;
|
||||||
use hypervisor::kvm::KVM_MSI_VALID_DEVID;
|
use hypervisor::kvm::KVM_MSI_VALID_DEVID;
|
||||||
use hypervisor::kvm::{kvm_irq_routing, kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
use hypervisor::kvm::{kvm_irq_routing_entry, KVM_IRQ_ROUTING_MSI};
|
||||||
|
|
||||||
type KvmMsiInterruptGroup = MsiInterruptGroup<kvm_irq_routing_entry>;
|
type KvmMsiInterruptGroup = MsiInterruptGroup<kvm_irq_routing_entry>;
|
||||||
type KvmRoutingEntry = RoutingEntry<kvm_irq_routing_entry>;
|
type KvmRoutingEntry = RoutingEntry<kvm_irq_routing_entry>;
|
||||||
@ -412,18 +382,7 @@ pub mod kvm {
|
|||||||
entry_vec.push(entry.route);
|
entry_vec.push(entry.route);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut irq_routing =
|
self.vm.set_gsi_routing(&entry_vec).map_err(|e| {
|
||||||
vec_with_array_field::<kvm_irq_routing, kvm_irq_routing_entry>(entry_vec.len());
|
|
||||||
irq_routing[0].nr = entry_vec.len() as u32;
|
|
||||||
irq_routing[0].flags = 0;
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
let entries: &mut [kvm_irq_routing_entry] =
|
|
||||||
irq_routing[0].entries.as_mut_slice(entry_vec.len());
|
|
||||||
entries.copy_from_slice(&entry_vec);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.vm.set_gsi_routing(&irq_routing[0]).map_err(|e| {
|
|
||||||
io::Error::new(
|
io::Error::new(
|
||||||
io::ErrorKind::Other,
|
io::ErrorKind::Other,
|
||||||
format!("Failed setting GSI routing: {}", e),
|
format!("Failed setting GSI routing: {}", e),
|
||||||
|
Loading…
Reference in New Issue
Block a user