From e1af251c9f4ae714380062f9f926861bc6f9fed3 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Fri, 17 Jul 2020 11:40:08 +0000 Subject: [PATCH] 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 --- hypervisor/src/kvm/mod.rs | 48 ++++++++++++++++++++++++++++++++++++--- hypervisor/src/vm.rs | 4 ++-- vmm/src/interrupt.rs | 45 ++---------------------------------- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 7199aa621..01ed27866 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -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` with a size in bytes at least as large as `size_in_bytes`. +fn vec_with_size_in_bytes(size_in_bytes: usize) -> Vec { + let rounded_size = (size_in_bytes + size_of::() - 1) / size_of::(); + 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::()` 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` is created. Only the first element of `Vec` would actually be used +// as a `Foo`. The remaining memory in the `Vec` is for `entries`, which must be contiguous +// with `Foo`. This function is used to make the `Vec` with enough space for `count` entries. +use std::mem::size_of; +fn vec_with_array_field(count: usize) -> Vec { + let element_space = count * size_of::(); + let vec_size_bytes = size_of::() + 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::(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())) } /// diff --git a/hypervisor/src/vm.rs b/hypervisor/src/vm.rs index b52722c7f..4622a2f5a 100644 --- a/hypervisor/src/vm.rs +++ b/hypervisor/src/vm.rs @@ -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, diff --git a/vmm/src/interrupt.rs b/vmm/src/interrupt.rs index ab72b4117..429c7c578 100644 --- a/vmm/src/interrupt.rs +++ b/vmm/src/interrupt.rs @@ -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 = std::io::Result; -// Returns a `Vec` with a size in bytes at least as large as `size_in_bytes`. -fn vec_with_size_in_bytes(size_in_bytes: usize) -> Vec { - let rounded_size = (size_in_bytes + size_of::() - 1) / size_of::(); - 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::()` 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` is created. Only the first element of `Vec` would actually be used -// as a `Foo`. The remaining memory in the `Vec` is for `entries`, which must be contiguous -// with `Foo`. This function is used to make the `Vec` with enough space for `count` entries. -fn vec_with_array_field(count: usize) -> Vec { - let element_space = count * size_of::(); - let vec_size_bytes = size_of::() + 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; type KvmRoutingEntry = RoutingEntry; @@ -412,18 +382,7 @@ pub mod kvm { entry_vec.push(entry.route); } - let mut irq_routing = - vec_with_array_field::(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),