mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-01-28 19:29:20 +00:00
kvm: add set_irq_routing method
This is used by the plugin process API, which may register an IRQ routing table. TEST=./build_test BUG=chromium:800626 Change-Id: If40965e8abfb0c9074c90b5fc77f9042f06499e0 Reviewed-on: https://chromium-review.googlesource.com/857910 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
0ba70d8d3c
commit
086922c222
2 changed files with 101 additions and 0 deletions
100
kvm/src/lib.rs
100
kvm/src/lib.rs
|
@ -14,6 +14,7 @@ mod cap;
|
|||
use std::fs::File;
|
||||
use std::collections::{BinaryHeap, HashMap};
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::mem::size_of;
|
||||
use std::os::raw::*;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
|
||||
|
@ -168,6 +169,18 @@ impl Into<u64> for NoDatamatch {
|
|||
}
|
||||
}
|
||||
|
||||
/// A source of IRQs in an `IrqRoute`.
|
||||
pub enum IrqSource {
|
||||
Irqchip { chip: u32, pin: u32 },
|
||||
Msi { address: u64, data: u32 },
|
||||
}
|
||||
|
||||
/// A single route for an IRQ.
|
||||
pub struct IrqRoute {
|
||||
pub gsi: u32,
|
||||
pub source: IrqSource,
|
||||
}
|
||||
|
||||
/// A wrapper around creating and using a VM.
|
||||
pub struct Vm {
|
||||
vm: File,
|
||||
|
@ -473,6 +486,55 @@ impl Vm {
|
|||
errno_result()
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the GSI routing table, replacing any table set with previous calls to
|
||||
/// `set_gsi_routing`.
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub fn set_gsi_routing(&self, routes: &[IrqRoute]) -> Result<()> {
|
||||
let vec_size_bytes = size_of::<kvm_irq_routing>() +
|
||||
(routes.len() * size_of::<kvm_irq_routing_entry>());
|
||||
let bytes: Vec<u8> = vec![0; vec_size_bytes];
|
||||
let irq_routing: &mut kvm_irq_routing = unsafe {
|
||||
// We have ensured in new that there is enough space for the structure so this
|
||||
// conversion is safe.
|
||||
&mut *(bytes.as_ptr() as *mut kvm_irq_routing)
|
||||
};
|
||||
irq_routing.nr = routes.len() as u32;
|
||||
|
||||
{
|
||||
// Safe because we ensured there is enough space in irq_routing to hold the number of
|
||||
// route entries.
|
||||
let irq_routes = unsafe { irq_routing.entries.as_mut_slice(routes.len()) };
|
||||
for (route, irq_route) in routes.iter().zip(irq_routes.iter_mut()) {
|
||||
irq_route.gsi = route.gsi;
|
||||
match route.source {
|
||||
IrqSource::Irqchip { chip, pin } => {
|
||||
irq_route.type_ = KVM_IRQ_ROUTING_IRQCHIP;
|
||||
irq_route.u.irqchip = kvm_irq_routing_irqchip {
|
||||
irqchip: chip,
|
||||
pin,
|
||||
}
|
||||
}
|
||||
IrqSource::Msi { address, data } => {
|
||||
irq_route.type_ = KVM_IRQ_ROUTING_MSI;
|
||||
irq_route.u.msi = kvm_irq_routing_msi {
|
||||
address_lo: address as u32,
|
||||
address_hi: (address >> 32) as u32,
|
||||
data: data,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let ret = unsafe { ioctl_with_ref(self, KVM_SET_GSI_ROUTING(), irq_routing) };
|
||||
if ret == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
errno_result()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Vm {
|
||||
|
@ -981,6 +1043,44 @@ mod tests {
|
|||
vm.unregister_irqfd(&evtfd3, 4).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_gsi_routing() {
|
||||
let kvm = Kvm::new().unwrap();
|
||||
let gm = GuestMemory::new(&vec![(GuestAddress(0), 0x10000)]).unwrap();
|
||||
let vm = Vm::new(&kvm, gm).unwrap();
|
||||
vm.set_gsi_routing(&[]).unwrap();
|
||||
vm.set_gsi_routing(&[IrqRoute {
|
||||
gsi: 1,
|
||||
source: IrqSource::Irqchip {
|
||||
chip: KVM_IRQCHIP_IOAPIC,
|
||||
pin: 3,
|
||||
},
|
||||
}]).unwrap();
|
||||
vm.set_gsi_routing(&[IrqRoute {
|
||||
gsi: 1,
|
||||
source: IrqSource::Msi {
|
||||
address: 0xf000000,
|
||||
data: 0xa0,
|
||||
},
|
||||
}]).unwrap();
|
||||
vm.set_gsi_routing(&[
|
||||
IrqRoute {
|
||||
gsi: 1,
|
||||
source: IrqSource::Irqchip {
|
||||
chip: KVM_IRQCHIP_IOAPIC,
|
||||
pin: 3,
|
||||
},
|
||||
},
|
||||
IrqRoute {
|
||||
gsi: 2,
|
||||
source: IrqSource::Msi {
|
||||
address: 0xf000000,
|
||||
data: 0xa0,
|
||||
},
|
||||
},
|
||||
]).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_vcpu() {
|
||||
let kvm = Kvm::new().unwrap();
|
||||
|
|
|
@ -20,6 +20,7 @@ pub mod x86 {
|
|||
pub mod bindings;
|
||||
pub use bindings::*;
|
||||
|
||||
ioctl_iow_nr!(KVM_SET_GSI_ROUTING, KVMIO, 0x6a, kvm_irq_routing);
|
||||
ioctl_iowr_nr!(KVM_GET_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
|
||||
ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
|
||||
ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
|
||||
|
|
Loading…
Reference in a new issue