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:
Wei Liu 2020-07-17 11:40:08 +00:00 committed by Samuel Ortiz
parent 12b37ef13b
commit e1af251c9f
3 changed files with 49 additions and 48 deletions

View File

@ -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()))
}
///

View File

@ -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,

View File

@ -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),