mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-06 02:25:23 +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::fs::File;
|
||||||
use std::collections::{BinaryHeap, HashMap};
|
use std::collections::{BinaryHeap, HashMap};
|
||||||
use std::collections::hash_map::Entry;
|
use std::collections::hash_map::Entry;
|
||||||
|
use std::mem::size_of;
|
||||||
use std::os::raw::*;
|
use std::os::raw::*;
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
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.
|
/// A wrapper around creating and using a VM.
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
vm: File,
|
vm: File,
|
||||||
|
@ -473,6 +486,55 @@ impl Vm {
|
||||||
errno_result()
|
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 {
|
impl AsRawFd for Vm {
|
||||||
|
@ -981,6 +1043,44 @@ mod tests {
|
||||||
vm.unregister_irqfd(&evtfd3, 4).unwrap();
|
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]
|
#[test]
|
||||||
fn create_vcpu() {
|
fn create_vcpu() {
|
||||||
let kvm = Kvm::new().unwrap();
|
let kvm = Kvm::new().unwrap();
|
||||||
|
|
|
@ -20,6 +20,7 @@ pub mod x86 {
|
||||||
pub mod bindings;
|
pub mod bindings;
|
||||||
pub use 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_MSR_INDEX_LIST, KVMIO, 0x02, kvm_msr_list);
|
||||||
ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
|
ioctl_iowr_nr!(KVM_GET_SUPPORTED_CPUID, KVMIO, 0x05, kvm_cpuid2);
|
||||||
ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
|
ioctl_iowr_nr!(KVM_GET_EMULATED_CPUID, KVMIO, 0x09, kvm_cpuid2);
|
||||||
|
|
Loading…
Reference in a new issue