use std::ops::Index;
use std::vec::Vec;
use anyhow::anyhow;
use anyhow::Context;
use base::Error;
use base::Event;
use base::Result;
use hypervisor::IoapicState;
use hypervisor::IrqRoute;
use hypervisor::IrqSource;
use hypervisor::IrqSourceChip;
use hypervisor::LapicState;
use hypervisor::MPState;
use hypervisor::PicSelect;
use hypervisor::PicState;
use hypervisor::PitState;
use serde::Deserialize;
use serde::Serialize;
use crate::IrqChip;
use crate::IrqChipCap;
pub trait IrqChipX86_64: IrqChip {
fn try_box_clone(&self) -> Result<Box<dyn IrqChipX86_64>>;
fn as_irq_chip(&self) -> &dyn IrqChip;
fn as_irq_chip_mut(&mut self) -> &mut dyn IrqChip;
fn get_pic_state(&self, select: PicSelect) -> Result<PicState>;
fn set_pic_state(&mut self, select: PicSelect, state: &PicState) -> Result<()>;
fn get_ioapic_state(&self) -> Result<IoapicState>;
fn set_ioapic_state(&mut self, state: &IoapicState) -> Result<()>;
fn get_lapic_state(&self, vcpu_id: usize) -> Result<LapicState>;
fn set_lapic_state(&mut self, vcpu_id: usize, state: &LapicState) -> Result<()>;
fn lapic_frequency(&self) -> u32;
fn get_pit(&self) -> Result<PitState>;
fn set_pit(&mut self, state: &PitState) -> Result<()>;
fn pit_uses_speaker_port(&self) -> bool;
fn snapshot_chip_specific(&self) -> anyhow::Result<serde_json::Value>;
fn restore_chip_specific(&mut self, data: serde_json::Value) -> anyhow::Result<()>;
fn snapshot(&self, cpus_num: usize) -> anyhow::Result<serde_json::Value> {
let mut lapics: Vec<LapicState> = Vec::new();
let mut mp_states: Vec<MPState> = Vec::new();
let has_mp_states = self.check_capability(IrqChipCap::MpStateGetSet);
for i in 0..cpus_num {
lapics.push(self.get_lapic_state(i)?);
if has_mp_states {
mp_states.push(self.get_mp_state(i)?);
}
}
serde_json::to_value(IrqChipSnapshot {
ioapic_state: self.get_ioapic_state()?,
lapic_state: lapics,
pic_state_1: self.get_pic_state(PicSelect::Primary)?,
pic_state_2: self.get_pic_state(PicSelect::Secondary)?,
pit_state: self.get_pit()?,
chip_specific_state: self.snapshot_chip_specific()?,
mp_state: mp_states,
})
.context("failed to serialize KvmKernelIrqChip")
}
fn restore(&mut self, data: serde_json::Value, vcpus_num: usize) -> anyhow::Result<()> {
let deser: IrqChipSnapshot =
serde_json::from_value(data).context("failed to deserialize data")?;
if deser.lapic_state.len() != vcpus_num {
return Err(anyhow!(
"IrqChip has the wrong number of LAPIC state snapshots: got {}, expected {}",
deser.lapic_state.len(),
vcpus_num
));
}
let supports_mp_states = self.check_capability(IrqChipCap::MpStateGetSet);
if supports_mp_states {
if deser.mp_state.len() != vcpus_num {
return Err(anyhow!(
"IrqChip has the wrong number of mp state snapshots: got {}, expected {}",
deser.mp_state.len(),
vcpus_num
));
}
} else if !deser.mp_state.is_empty() {
return Err(anyhow!(
"IrqChip does not support mp state, but mp state was in the snapshot"
));
}
self.set_pit(&deser.pit_state)?;
self.set_pic_state(PicSelect::Primary, &deser.pic_state_1)
.context("failed to set primary PIC")?;
self.set_pic_state(PicSelect::Secondary, &deser.pic_state_2)
.context("failed to set secondary PIC")?;
self.set_ioapic_state(&deser.ioapic_state)
.context("failed to set IOAPIC state")?;
self.restore_chip_specific(deser.chip_specific_state)
.context("failed to set chip specific data")?;
for (i, lapic) in deser.lapic_state.iter().enumerate() {
self.set_lapic_state(i, lapic)
.context("failed to set LAPIC state")?;
}
if supports_mp_states {
for (i, mp_state) in deser.mp_state.iter().enumerate() {
self.set_mp_state(i, mp_state)
.context("failed to set mp state")?;
}
}
Ok(())
}
}
#[derive(Serialize, Deserialize)]
struct IrqChipSnapshot {
ioapic_state: IoapicState,
lapic_state: Vec<LapicState>,
pic_state_1: PicState,
pic_state_2: PicState,
pit_state: PitState,
chip_specific_state: serde_json::Value,
mp_state: Vec<MPState>,
}
pub struct Routes {
routes: Vec<Vec<IrqSource>>,
}
impl Routes {
pub fn new() -> Self {
Routes { routes: vec![] }
}
pub fn add(&mut self, route: IrqRoute) -> Result<()> {
let routes = self.get_mut(route.gsi as usize);
if routes.iter().any(|r| !Self::same_source(&route.source, r)) {
return Err(Error::new(libc::EINVAL));
}
routes.retain(|r| !Self::conflict(&route.source, r));
routes.push(route.source);
Ok(())
}
pub fn replace_all(&mut self, routes: &[IrqRoute]) -> Result<()> {
self.routes.clear();
for r in routes {
self.add(*r)?;
}
Ok(())
}
pub fn default_pic_ioapic_routes(ioapic_pins: usize) -> Vec<IrqRoute> {
let mut routes: Vec<IrqRoute> = Vec::new();
for i in 0..8 {
routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicPrimary, i));
routes.push(IrqRoute::ioapic_irq_route(i));
}
for i in 8..16 {
routes.push(IrqRoute::pic_irq_route(IrqSourceChip::PicSecondary, i));
routes.push(IrqRoute::ioapic_irq_route(i));
}
for i in 16..ioapic_pins as u32 {
routes.push(IrqRoute::ioapic_irq_route(i));
}
routes
}
pub fn get_routes(&self) -> Vec<IrqRoute> {
let mut routes = Vec::with_capacity(self.routes.len());
for (gsi, sources) in self.routes.iter().enumerate() {
for source in sources.iter() {
routes.push(IrqRoute {
gsi: gsi.try_into().expect("GSIs must be < u32::MAX"),
source: *source,
});
}
}
routes
}
fn conflict(source: &IrqSource, other: &IrqSource) -> bool {
use IrqSource::*;
if let (Msi { .. }, Msi { .. }) = (source, other) {
return true;
}
if let (
Irqchip { chip, .. },
Irqchip {
chip: other_chip, ..
},
) = (source, other)
{
return chip == other_chip;
}
false
}
fn same_source(source: &IrqSource, other: &IrqSource) -> bool {
use IrqSource::*;
matches!(
(source, other),
(Irqchip { .. }, Irqchip { .. }) | (Msi { .. }, Msi { .. })
)
}
fn get_mut(&mut self, irq: usize) -> &mut Vec<IrqSource> {
if irq >= self.routes.len() {
self.routes.resize_with(irq + 1, Vec::new);
}
self.routes.get_mut(irq).unwrap()
}
}
impl Default for Routes {
fn default() -> Self {
Self::new()
}
}
const EMPTY_ROUTE: [IrqSource; 0] = [];
impl Index<usize> for Routes {
type Output = [IrqSource];
fn index(&self, irq: usize) -> &Self::Output {
if irq < self.routes.len() {
self.routes[irq].as_slice()
} else {
&EMPTY_ROUTE
}
}
}
pub(super) struct DelayedIoApicIrqEvents {
pub events: Vec<usize>,
pub trigger: Event,
}
impl DelayedIoApicIrqEvents {
pub fn new() -> Result<Self> {
Ok(DelayedIoApicIrqEvents {
events: Vec::new(),
trigger: Event::new()?,
})
}
}