use std::sync::Arc;
use base::error;
use base::Error;
use base::Event;
use base::Result;
use hypervisor::geniezone::geniezone_sys::*;
use hypervisor::geniezone::GeniezoneVm;
use hypervisor::DeviceKind;
use hypervisor::IrqRoute;
use hypervisor::MPState;
use hypervisor::Vcpu;
use hypervisor::Vm;
use resources::SystemAllocator;
use sync::Mutex;
use crate::Bus;
use crate::IrqChip;
use crate::IrqChipAArch64;
use crate::IrqChipCap;
use crate::IrqEdgeEvent;
use crate::IrqEventIndex;
use crate::IrqEventSource;
use crate::IrqLevelEvent;
use crate::VcpuRunState;
fn default_irq_routing_table() -> Vec<IrqRoute> {
let mut routes: Vec<IrqRoute> = Vec::new();
for i in 0..AARCH64_GIC_NR_SPIS {
routes.push(IrqRoute::gic_irq_route(i));
}
routes
}
pub struct GeniezoneKernelIrqChip {
pub(super) vm: GeniezoneVm,
device_kind: DeviceKind,
pub(super) routes: Arc<Mutex<Vec<IrqRoute>>>,
}
const AARCH64_GIC_DIST_SIZE: u64 = 0x10000;
const AARCH64_GIC_DIST_BASE: u64 = 0x40000000 - AARCH64_GIC_DIST_SIZE;
const AARCH64_GIC_REDIST_SIZE: u64 = 0x20000;
pub const AARCH64_GIC_NR_SPIS: u32 = 32;
impl GeniezoneKernelIrqChip {
pub fn new(vm: GeniezoneVm, num_vcpus: usize) -> Result<GeniezoneKernelIrqChip> {
let dist_if_addr: u64 = AARCH64_GIC_DIST_BASE;
let redist_addr: u64 = dist_if_addr - (AARCH64_GIC_REDIST_SIZE * num_vcpus as u64);
let device_kind = DeviceKind::ArmVgicV3;
let device_dis = gzvm_create_device {
dev_type: gzvm_device_type_GZVM_DEV_TYPE_ARM_VGIC_V3_DIST,
id: 0,
flags: 0,
dev_addr: dist_if_addr,
dev_reg_size: AARCH64_GIC_DIST_SIZE,
attr_addr: 0_u64,
attr_size: 0_u64,
};
match vm.create_geniezone_device(device_dis) {
Ok(()) => {}
Err(e) => {
error!("failed to create geniezone device with err: {}", e);
return Err(e);
}
};
let device_redis = gzvm_create_device {
dev_type: gzvm_device_type_GZVM_DEV_TYPE_ARM_VGIC_V3_REDIST,
id: 0,
flags: 0,
dev_addr: redist_addr,
dev_reg_size: AARCH64_GIC_REDIST_SIZE,
attr_addr: 0_u64,
attr_size: 0_u64,
};
match vm.create_geniezone_device(device_redis) {
Ok(()) => {}
Err(e) => {
error!("failed to create geniezone device with err: {}", e);
return Err(e);
}
};
Ok(GeniezoneKernelIrqChip {
vm,
device_kind,
routes: Arc::new(Mutex::new(default_irq_routing_table())),
})
}
pub(super) fn arch_try_clone(&self) -> Result<Self> {
Ok(GeniezoneKernelIrqChip {
vm: self.vm.try_clone()?,
device_kind: self.device_kind,
routes: self.routes.clone(),
})
}
}
impl IrqChipAArch64 for GeniezoneKernelIrqChip {
fn try_box_clone(&self) -> Result<Box<dyn IrqChipAArch64>> {
Ok(Box::new(self.try_clone()?))
}
fn as_irq_chip(&self) -> &dyn IrqChip {
self
}
fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip {
self
}
fn get_vgic_version(&self) -> DeviceKind {
self.device_kind
}
fn has_vgic_its(&self) -> bool {
false
}
fn finalize(&self) -> Result<()> {
Ok(())
}
}
impl IrqChip for GeniezoneKernelIrqChip {
fn add_vcpu(&mut self, _vcpu_id: usize, _vcpu: &dyn Vcpu) -> Result<()> {
Ok(())
}
fn register_edge_irq_event(
&mut self,
irq: u32,
irq_event: &IrqEdgeEvent,
_source: IrqEventSource,
) -> Result<Option<IrqEventIndex>> {
self.vm.register_irqfd(irq, irq_event.get_trigger(), None)?;
Ok(None)
}
fn unregister_edge_irq_event(&mut self, irq: u32, irq_event: &IrqEdgeEvent) -> Result<()> {
self.vm.unregister_irqfd(irq, irq_event.get_trigger())
}
fn register_level_irq_event(
&mut self,
irq: u32,
irq_event: &IrqLevelEvent,
_source: IrqEventSource,
) -> Result<Option<IrqEventIndex>> {
self.vm
.register_irqfd(irq, irq_event.get_trigger(), Some(irq_event.get_resample()))?;
Ok(None)
}
fn unregister_level_irq_event(&mut self, irq: u32, irq_event: &IrqLevelEvent) -> Result<()> {
self.vm.unregister_irqfd(irq, irq_event.get_trigger())
}
fn route_irq(&mut self, route: IrqRoute) -> Result<()> {
let mut routes = self.routes.lock();
routes.retain(|r| r.gsi != route.gsi);
routes.push(route);
Ok(())
}
fn set_irq_routes(&mut self, routes: &[IrqRoute]) -> Result<()> {
let mut current_routes = self.routes.lock();
*current_routes = routes.to_vec();
Ok(())
}
fn irq_event_tokens(&self) -> Result<Vec<(IrqEventIndex, IrqEventSource, Event)>> {
Ok(Vec::new())
}
fn service_irq(&mut self, irq: u32, level: bool) -> Result<()> {
self.vm.set_irq_line(irq, level)
}
fn service_irq_event(&mut self, _event_index: IrqEventIndex) -> Result<()> {
error!("service_irq_event should never be called for GeniezoneKernelIrqChip");
Ok(())
}
fn broadcast_eoi(&self, _vector: u8) -> Result<()> {
error!("broadcast_eoi should never be called for GeniezoneKernelIrqChip");
Ok(())
}
fn inject_interrupts(&self, _vcpu: &dyn Vcpu) -> Result<()> {
Ok(())
}
fn halted(&self, _vcpu_id: usize) {}
fn wait_until_runnable(&self, _vcpu: &dyn Vcpu) -> Result<VcpuRunState> {
Ok(VcpuRunState::Runnable)
}
fn kick_halted_vcpus(&self) {}
fn get_mp_state(&self, _vcpu_id: usize) -> Result<MPState> {
Err(Error::new(libc::ENOENT))
}
fn set_mp_state(&mut self, _vcpu_id: usize, _state: &MPState) -> Result<()> {
Err(Error::new(libc::ENOENT))
}
fn try_clone(&self) -> Result<Self> {
self.arch_try_clone()
}
fn finalize_devices(
&mut self,
_resources: &mut SystemAllocator,
_io_bus: &Bus,
_mmio_bus: &Bus,
) -> Result<()> {
Ok(())
}
fn process_delayed_irq_events(&mut self) -> Result<()> {
Ok(())
}
fn irq_delayed_event_token(&self) -> Result<Option<Event>> {
Ok(None)
}
fn check_capability(&self, _c: IrqChipCap) -> bool {
false
}
}