mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-01 17:35:19 +00:00
arch: AArch64: implement save/restore for GICv3
This commit implements the save/restore for GICv3. Signed-off-by: Henry Wang <Henry.Wang@arm.com>
This commit is contained in:
parent
7ddcad1d8b
commit
39c9583b48
@ -13,7 +13,11 @@ byteorder = "1.3.4"
|
||||
hypervisor = { path = "../hypervisor" }
|
||||
libc = "0.2.77"
|
||||
log = "0.4.11"
|
||||
serde = {version = ">=1.0.27", features = ["rc"] }
|
||||
serde_derive = ">=1.0.27"
|
||||
serde_json = ">=1.0.9"
|
||||
vm-memory = { version = "0.2.1", features = ["backend-mmap"] }
|
||||
vm-migration = { path = "../vm-migration" }
|
||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||
arch_gen = { path = "../arch_gen" }
|
||||
|
||||
|
@ -2,13 +2,45 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
pub mod kvm {
|
||||
use crate::aarch64::gic::kvm::KvmGICDevice;
|
||||
use crate::aarch64::gic::{Error, GICDevice};
|
||||
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||
use crate::aarch64::gic::icc_regs::{get_icc_regs, set_icc_regs};
|
||||
use crate::aarch64::gic::kvm::{save_pending_tables, KvmGICDevice};
|
||||
use crate::aarch64::gic::redist_regs::{get_redist_regs, set_redist_regs};
|
||||
use crate::aarch64::gic::GICDevice;
|
||||
use crate::layout;
|
||||
use anyhow::anyhow;
|
||||
use hypervisor::kvm::kvm_bindings;
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
use std::{boxed::Box, result};
|
||||
use vm_migration::{
|
||||
Migratable, MigratableError, Pausable, Snapshot, SnapshotDataSection, Snapshottable,
|
||||
Transportable,
|
||||
};
|
||||
|
||||
/// Errors thrown while saving/restoring the GICv3.
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Error in saving RDIST pending tables into guest RAM.
|
||||
SavePendingTables(crate::aarch64::gic::Error),
|
||||
/// Error in saving GIC distributor registers.
|
||||
SaveDistributorRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in restoring GIC distributor registers.
|
||||
RestoreDistributorRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in saving GIC distributor control registers.
|
||||
SaveDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in restoring GIC distributor control registers.
|
||||
RestoreDistributorCtrlRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in saving GIC redistributor registers.
|
||||
SaveRedistributorRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in restoring GIC redistributor registers.
|
||||
RestoreRedistributorRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in saving GIC CPU interface registers.
|
||||
SaveICCRegisters(crate::aarch64::gic::Error),
|
||||
/// Error in restoring GIC CPU interface registers.
|
||||
RestoreICCRegisters(crate::aarch64::gic::Error),
|
||||
}
|
||||
|
||||
type Result<T> = result::Result<T, Error>;
|
||||
|
||||
pub struct KvmGICv3 {
|
||||
@ -25,6 +57,15 @@ pub mod kvm {
|
||||
vcpu_count: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Gicv3State {
|
||||
dist: Vec<u32>,
|
||||
rdist: Vec<u32>,
|
||||
icc: Vec<u32>,
|
||||
// special register that enables interrupts and affinity routing
|
||||
gicd_ctlr: u32,
|
||||
}
|
||||
|
||||
impl KvmGICv3 {
|
||||
// Unfortunately bindgen omits defines that are based on other defines.
|
||||
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
|
||||
@ -54,6 +95,48 @@ pub mod kvm {
|
||||
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
||||
vcpu_count * KvmGICv3::KVM_VGIC_V3_REDIST_SIZE
|
||||
}
|
||||
|
||||
/// Save the state of GIC.
|
||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3State> {
|
||||
// Flush redistributors pending tables to guest RAM.
|
||||
save_pending_tables(&self.device()).map_err(Error::SavePendingTables)?;
|
||||
|
||||
let gicd_ctlr =
|
||||
read_ctlr(&self.device()).map_err(Error::SaveDistributorCtrlRegisters)?;
|
||||
|
||||
let dist_state =
|
||||
get_dist_regs(&self.device()).map_err(Error::SaveDistributorRegisters)?;
|
||||
|
||||
let rdist_state = get_redist_regs(&self.device(), &gicr_typers)
|
||||
.map_err(Error::SaveRedistributorRegisters)?;
|
||||
|
||||
let icc_state =
|
||||
get_icc_regs(&self.device(), &gicr_typers).map_err(Error::SaveICCRegisters)?;
|
||||
|
||||
Ok(Gicv3State {
|
||||
dist: dist_state,
|
||||
rdist: rdist_state,
|
||||
icc: icc_state,
|
||||
gicd_ctlr,
|
||||
})
|
||||
}
|
||||
|
||||
/// Restore the state of GIC.
|
||||
fn set_state(&mut self, gicr_typers: &[u64], state: &Gicv3State) -> Result<()> {
|
||||
write_ctlr(&self.device(), state.gicd_ctlr)
|
||||
.map_err(Error::RestoreDistributorCtrlRegisters)?;
|
||||
|
||||
set_dist_regs(&self.device(), &state.dist)
|
||||
.map_err(Error::RestoreDistributorRegisters)?;
|
||||
|
||||
set_redist_regs(&self.device(), gicr_typers, &state.rdist)
|
||||
.map_err(Error::RestoreRedistributorRegisters)?;
|
||||
|
||||
set_icc_regs(&self.device(), &gicr_typers, &state.icc)
|
||||
.map_err(Error::RestoreICCRegisters)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl GICDevice for KvmGICv3 {
|
||||
@ -107,7 +190,7 @@ pub mod kvm {
|
||||
fn init_device_attributes(
|
||||
_vm: &Arc<dyn hypervisor::Vm>,
|
||||
gic_device: &dyn GICDevice,
|
||||
) -> Result<()> {
|
||||
) -> crate::aarch64::gic::Result<()> {
|
||||
/* Setting up the distributor attribute.
|
||||
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
||||
*/
|
||||
@ -133,4 +216,55 @@ pub mod kvm {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
const GIC_V3_SNAPSHOT_ID: &str = "gic-v3";
|
||||
impl Snapshottable for KvmGICv3 {
|
||||
fn id(&self) -> String {
|
||||
GIC_V3_SNAPSHOT_ID.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
let gicr_typers = self.gicr_typers.clone();
|
||||
let snapshot = serde_json::to_vec(&self.state(&gicr_typers).unwrap())
|
||||
.map_err(|e| MigratableError::Snapshot(e.into()))?;
|
||||
|
||||
let mut gic_v3_snapshot = Snapshot::new(self.id().as_str());
|
||||
gic_v3_snapshot.add_data_section(SnapshotDataSection {
|
||||
id: format!("{}-section", self.id()),
|
||||
snapshot,
|
||||
});
|
||||
|
||||
Ok(gic_v3_snapshot)
|
||||
}
|
||||
|
||||
fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> {
|
||||
if let Some(gic_v3_section) = snapshot
|
||||
.snapshot_data
|
||||
.get(&format!("{}-section", self.id()))
|
||||
{
|
||||
let gic_v3_state = match serde_json::from_slice(&gic_v3_section.snapshot) {
|
||||
Ok(state) => state,
|
||||
Err(error) => {
|
||||
return Err(MigratableError::Restore(anyhow!(
|
||||
"Could not deserialize GICv3 {}",
|
||||
error
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let gicr_typers = self.gicr_typers.clone();
|
||||
return self.set_state(&gicr_typers, &gic_v3_state).map_err(|e| {
|
||||
MigratableError::Restore(anyhow!("Could not restore GICv3 state {:?}", e))
|
||||
});
|
||||
}
|
||||
|
||||
Err(MigratableError::Restore(anyhow!(
|
||||
"Could not find GICv3 snapshot section"
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl Pausable for KvmGICv3 {}
|
||||
impl Transportable for KvmGICv3 {}
|
||||
impl Migratable for KvmGICv3 {}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@
|
||||
clippy::cast_ptr_alignment
|
||||
)]
|
||||
|
||||
extern crate anyhow;
|
||||
extern crate byteorder;
|
||||
extern crate hypervisor;
|
||||
extern crate libc;
|
||||
@ -23,7 +24,13 @@ extern crate log;
|
||||
extern crate acpi_tables;
|
||||
extern crate arch_gen;
|
||||
extern crate linux_loader;
|
||||
extern crate serde;
|
||||
extern crate vm_memory;
|
||||
extern crate vm_migration;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
Loading…
x
Reference in New Issue
Block a user