mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-10-02 11:35:46 +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" }
|
hypervisor = { path = "../hypervisor" }
|
||||||
libc = "0.2.77"
|
libc = "0.2.77"
|
||||||
log = "0.4.11"
|
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-memory = { version = "0.2.1", features = ["backend-mmap"] }
|
||||||
|
vm-migration = { path = "../vm-migration" }
|
||||||
acpi_tables = { path = "../acpi_tables", optional = true }
|
acpi_tables = { path = "../acpi_tables", optional = true }
|
||||||
arch_gen = { path = "../arch_gen" }
|
arch_gen = { path = "../arch_gen" }
|
||||||
|
|
||||||
|
@ -2,13 +2,45 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
pub mod kvm {
|
pub mod kvm {
|
||||||
use crate::aarch64::gic::kvm::KvmGICDevice;
|
use crate::aarch64::gic::dist_regs::{get_dist_regs, read_ctlr, set_dist_regs, write_ctlr};
|
||||||
use crate::aarch64::gic::{Error, GICDevice};
|
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 crate::layout;
|
||||||
|
use anyhow::anyhow;
|
||||||
use hypervisor::kvm::kvm_bindings;
|
use hypervisor::kvm::kvm_bindings;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{boxed::Box, result};
|
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>;
|
type Result<T> = result::Result<T, Error>;
|
||||||
|
|
||||||
pub struct KvmGICv3 {
|
pub struct KvmGICv3 {
|
||||||
@ -25,6 +57,15 @@ pub mod kvm {
|
|||||||
vcpu_count: u64,
|
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 {
|
impl KvmGICv3 {
|
||||||
// Unfortunately bindgen omits defines that are based on other defines.
|
// Unfortunately bindgen omits defines that are based on other defines.
|
||||||
// See arch/arm64/include/uapi/asm/kvm.h file from the linux kernel.
|
// 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 {
|
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
||||||
vcpu_count * KvmGICv3::KVM_VGIC_V3_REDIST_SIZE
|
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 {
|
impl GICDevice for KvmGICv3 {
|
||||||
@ -107,7 +190,7 @@ pub mod kvm {
|
|||||||
fn init_device_attributes(
|
fn init_device_attributes(
|
||||||
_vm: &Arc<dyn hypervisor::Vm>,
|
_vm: &Arc<dyn hypervisor::Vm>,
|
||||||
gic_device: &dyn GICDevice,
|
gic_device: &dyn GICDevice,
|
||||||
) -> Result<()> {
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
/* Setting up the distributor attribute.
|
/* Setting up the distributor attribute.
|
||||||
We are placing the GIC below 1GB so we need to substract the size of the distributor.
|
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(())
|
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
|
clippy::cast_ptr_alignment
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
extern crate anyhow;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate hypervisor;
|
extern crate hypervisor;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
@ -23,7 +24,13 @@ extern crate log;
|
|||||||
extern crate acpi_tables;
|
extern crate acpi_tables;
|
||||||
extern crate arch_gen;
|
extern crate arch_gen;
|
||||||
extern crate linux_loader;
|
extern crate linux_loader;
|
||||||
|
extern crate serde;
|
||||||
extern crate vm_memory;
|
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::fmt;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
Loading…
Reference in New Issue
Block a user