mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-01-21 20:15:21 +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 {
|
||||
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_vcpu_events as VcpuEvents, kvm_ioctls::DeviceFd, kvm_ioctls::IoEventAddress,
|
||||
kvm_ioctls::VcpuExit,
|
||||
@ -70,6 +70,37 @@ pub struct KvmVm {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
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
|
||||
/// Example:
|
||||
@ -167,9 +198,20 @@ impl vm::Vm for KvmVm {
|
||||
/// Sets the GSI routing table entries, overwriting any previously set
|
||||
/// 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
|
||||
.set_gsi_routing(irq_routing)
|
||||
.set_gsi_routing(&irq_routing[0])
|
||||
.map_err(|e| vm::HypervisorVmError::SetGsiRouting(e.into()))
|
||||
}
|
||||
///
|
||||
|
@ -13,7 +13,7 @@ use crate::aarch64::VcpuInit;
|
||||
use crate::cpu::Vcpu;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::ClockData;
|
||||
use crate::{CreateDevice, DeviceFd, IoEventAddress, IrqRouting, MemoryRegion};
|
||||
use crate::{CreateDevice, DeviceFd, IoEventAddress, IrqRoutingEntry, MemoryRegion};
|
||||
use kvm_ioctls::Cap;
|
||||
use std::sync::Arc;
|
||||
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.
|
||||
fn unregister_ioevent(&self, fd: &EventFd, addr: &IoEventAddress) -> Result<()>;
|
||||
/// 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
|
||||
fn make_user_memory_region(
|
||||
&self,
|
||||
|
@ -6,7 +6,6 @@
|
||||
use devices::interrupt_controller::InterruptController;
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::mem::size_of;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use vm_allocator::SystemAllocator;
|
||||
@ -19,35 +18,6 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
/// Reuse std::io::Result to simplify interoperability among crates.
|
||||
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 {
|
||||
pub gsi: u32,
|
||||
pub irq_fd: EventFd,
|
||||
@ -357,7 +327,7 @@ where
|
||||
pub mod kvm {
|
||||
use super::*;
|
||||
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 KvmRoutingEntry = RoutingEntry<kvm_irq_routing_entry>;
|
||||
@ -412,18 +382,7 @@ pub mod kvm {
|
||||
entry_vec.push(entry.route);
|
||||
}
|
||||
|
||||
let mut irq_routing =
|
||||
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| {
|
||||
self.vm.set_gsi_routing(&entry_vec).map_err(|e| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("Failed setting GSI routing: {}", e),
|
||||
|
Loading…
x
Reference in New Issue
Block a user