mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-07-05 01:12:36 +00:00
aarch64: Avoid depending on layout
in GIC code
Removing the dependency on `layout` helps moving GIC code into `hypervisor` crate. Signed-off-by: Michael Zhao <michael.zhao@arm.com>
This commit is contained in:
parent
4a2d3cb4f5
commit
0fd6521759
@ -326,7 +326,7 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
|
|||||||
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
|
// interrupt source. The type shall be a <u32> and the value shall be 3 if no PPI affinity description
|
||||||
// is required.
|
// is required.
|
||||||
fdt.property_u32("#interrupt-cells", 3)?;
|
fdt.property_u32("#interrupt-cells", 3)?;
|
||||||
fdt.property_array_u64("reg", gic_reg_prop)?;
|
fdt.property_array_u64("reg", &gic_reg_prop)?;
|
||||||
fdt.property_u32("phandle", GIC_PHANDLE)?;
|
fdt.property_u32("phandle", GIC_PHANDLE)?;
|
||||||
fdt.property_u32("#address-cells", 2)?;
|
fdt.property_u32("#address-cells", 2)?;
|
||||||
fdt.property_u32("#size-cells", 2)?;
|
fdt.property_u32("#size-cells", 2)?;
|
||||||
@ -345,7 +345,7 @@ fn create_gic_node(fdt: &mut FdtWriter, gic_device: &dyn GicDevice) -> FdtWriter
|
|||||||
fdt.property_null("msi-controller")?;
|
fdt.property_null("msi-controller")?;
|
||||||
fdt.property_u32("phandle", MSI_PHANDLE)?;
|
fdt.property_u32("phandle", MSI_PHANDLE)?;
|
||||||
let msi_reg_prop = gic_device.msi_properties();
|
let msi_reg_prop = gic_device.msi_properties();
|
||||||
fdt.property_array_u64("reg", msi_reg_prop)?;
|
fdt.property_array_u64("reg", &msi_reg_prop)?;
|
||||||
fdt.end_node(msic_node)?;
|
fdt.end_node(msic_node)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,9 +31,7 @@ pub trait GicDevice: Send {
|
|||||||
fn device(&self) -> &Arc<dyn hypervisor::Device>;
|
fn device(&self) -> &Arc<dyn hypervisor::Device>;
|
||||||
|
|
||||||
/// Returns the hypervisor agnostic Device of the ITS device
|
/// Returns the hypervisor agnostic Device of the ITS device
|
||||||
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>> {
|
fn its_device(&self) -> Option<&Arc<dyn hypervisor::Device>>;
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the fdt compatibility property of the device
|
/// Returns the fdt compatibility property of the device
|
||||||
fn fdt_compatibility(&self) -> &str;
|
fn fdt_compatibility(&self) -> &str;
|
||||||
@ -42,25 +40,19 @@ pub trait GicDevice: Send {
|
|||||||
fn fdt_maint_irq(&self) -> u32;
|
fn fdt_maint_irq(&self) -> u32;
|
||||||
|
|
||||||
/// Returns an array with GIC device properties
|
/// Returns an array with GIC device properties
|
||||||
fn device_properties(&self) -> &[u64];
|
fn device_properties(&self) -> [u64; 4];
|
||||||
|
|
||||||
/// Returns the number of vCPUs this GIC handles
|
/// Returns the number of vCPUs this GIC handles
|
||||||
fn vcpu_count(&self) -> u64;
|
fn vcpu_count(&self) -> u64;
|
||||||
|
|
||||||
/// Returns whether the GIC device is MSI compatible or not
|
/// Returns whether the GIC device is MSI compatible or not
|
||||||
fn msi_compatible(&self) -> bool {
|
fn msi_compatible(&self) -> bool;
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the MSI compatibility property of the device
|
/// Returns the MSI compatibility property of the device
|
||||||
fn msi_compatibility(&self) -> &str {
|
fn msi_compatibility(&self) -> &str;
|
||||||
""
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the MSI reg property of the device
|
/// Returns the MSI reg property of the device
|
||||||
fn msi_properties(&self) -> &[u64] {
|
fn msi_properties(&self) -> [u64; 2];
|
||||||
&[]
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>);
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>);
|
||||||
|
|
||||||
@ -163,11 +155,23 @@ pub mod kvm {
|
|||||||
/// Vector holding values of GICR_TYPER for each vCPU
|
/// Vector holding values of GICR_TYPER for each vCPU
|
||||||
gicr_typers: Vec<u64>,
|
gicr_typers: Vec<u64>,
|
||||||
|
|
||||||
/// GIC device properties, to be used for setting up the fdt entry
|
/// GIC distributor address
|
||||||
gic_properties: [u64; 4],
|
dist_addr: u64,
|
||||||
|
|
||||||
/// MSI device properties, to be used for setting up the fdt entry
|
/// GIC distributor size
|
||||||
msi_properties: [u64; 2],
|
dist_size: u64,
|
||||||
|
|
||||||
|
/// GIC distributors address
|
||||||
|
redists_addr: u64,
|
||||||
|
|
||||||
|
/// GIC distributors size
|
||||||
|
redists_size: u64,
|
||||||
|
|
||||||
|
/// GIC MSI address
|
||||||
|
msi_addr: u64,
|
||||||
|
|
||||||
|
/// GIC MSI size
|
||||||
|
msi_size: u64,
|
||||||
|
|
||||||
/// Number of CPUs handled by the device
|
/// Number of CPUs handled by the device
|
||||||
vcpu_count: u64,
|
vcpu_count: u64,
|
||||||
@ -192,34 +196,6 @@ pub mod kvm {
|
|||||||
/// Device trees specific constants
|
/// Device trees specific constants
|
||||||
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
pub const ARCH_GIC_V3_MAINT_IRQ: u32 = 9;
|
||||||
|
|
||||||
/// Get the address of the GIC distributor.
|
|
||||||
pub fn get_dist_addr() -> u64 {
|
|
||||||
layout::GIC_V3_DIST_START.raw_value()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the GIC distributor.
|
|
||||||
pub fn get_dist_size() -> u64 {
|
|
||||||
layout::GIC_V3_DIST_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the address of the GIC redistributors.
|
|
||||||
pub fn get_redists_addr(vcpu_count: u64) -> u64 {
|
|
||||||
KvmGicV3Its::get_dist_addr() - KvmGicV3Its::get_redists_size(vcpu_count)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the size of the GIC redistributors.
|
|
||||||
pub fn get_redists_size(vcpu_count: u64) -> u64 {
|
|
||||||
vcpu_count * layout::GIC_V3_REDIST_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_msi_size() -> u64 {
|
|
||||||
layout::GIC_V3_ITS_SIZE
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_msi_addr(vcpu_count: u64) -> u64 {
|
|
||||||
KvmGicV3Its::get_redists_addr(vcpu_count) - KvmGicV3Its::get_msi_size()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Save the state of GICv3ITS.
|
/// Save the state of GICv3ITS.
|
||||||
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3ItsState> {
|
fn state(&self, gicr_typers: &[u64]) -> Result<Gicv3ItsState> {
|
||||||
let gicd_ctlr = read_ctlr(self.device())?;
|
let gicd_ctlr = read_ctlr(self.device())?;
|
||||||
@ -376,6 +352,7 @@ pub mod kvm {
|
|||||||
fn init_device_attributes(
|
fn init_device_attributes(
|
||||||
&mut self,
|
&mut self,
|
||||||
vm: &Arc<dyn hypervisor::Vm>,
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
nr_irqs: u32,
|
||||||
) -> crate::aarch64::gic::Result<()> {
|
) -> crate::aarch64::gic::Result<()> {
|
||||||
// GicV3 part attributes
|
// GicV3 part attributes
|
||||||
/* Setting up the distributor attribute.
|
/* Setting up the distributor attribute.
|
||||||
@ -385,7 +362,7 @@ pub mod kvm {
|
|||||||
self.device(),
|
self.device(),
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
|
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_DIST),
|
||||||
&KvmGicV3Its::get_dist_addr() as *const u64 as u64,
|
&self.dist_addr as *const u64 as u64,
|
||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -396,7 +373,7 @@ pub mod kvm {
|
|||||||
self.device(),
|
self.device(),
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
|
u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST),
|
||||||
&KvmGicV3Its::get_redists_addr(self.vcpu_count()) as *const u64 as u64,
|
&self.redists_addr as *const u64 as u64,
|
||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -415,7 +392,7 @@ pub mod kvm {
|
|||||||
&its_fd,
|
&its_fd,
|
||||||
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR,
|
||||||
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
|
u64::from(kvm_bindings::KVM_VGIC_ITS_ADDR_TYPE),
|
||||||
&KvmGicV3Its::get_msi_addr(self.vcpu_count()) as *const u64 as u64,
|
&self.msi_addr as *const u64 as u64,
|
||||||
0,
|
0,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -432,7 +409,6 @@ pub mod kvm {
|
|||||||
/* We need to tell the kernel how many irqs to support with this vgic.
|
/* We need to tell the kernel how many irqs to support with this vgic.
|
||||||
* See the `layout` module for details.
|
* See the `layout` module for details.
|
||||||
*/
|
*/
|
||||||
let nr_irqs: u32 = layout::IRQ_NUM;
|
|
||||||
let nr_irqs_ptr = &nr_irqs as *const u32;
|
let nr_irqs_ptr = &nr_irqs as *const u32;
|
||||||
Self::set_device_attribute(
|
Self::set_device_attribute(
|
||||||
self.device(),
|
self.device(),
|
||||||
@ -489,29 +465,50 @@ pub mod kvm {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Function that saves RDIST pending tables into guest RAM.
|
||||||
|
///
|
||||||
|
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
||||||
|
pub fn save_pending_tables(vgic: &Arc<dyn hypervisor::Device>) -> Result<()> {
|
||||||
|
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
||||||
|
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
||||||
|
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
|
||||||
|
addr: 0,
|
||||||
|
flags: 0,
|
||||||
|
};
|
||||||
|
vgic.set_device_attr(&init_gic_attr)
|
||||||
|
.map_err(super::Error::SetDeviceAttribute)
|
||||||
|
}
|
||||||
|
|
||||||
/// Method to initialize the GIC device
|
/// Method to initialize the GIC device
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
fn new(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
fn new(
|
||||||
|
vm: &Arc<dyn hypervisor::Vm>,
|
||||||
|
vcpu_count: u64,
|
||||||
|
dist_addr: u64,
|
||||||
|
dist_size: u64,
|
||||||
|
redist_size: u64,
|
||||||
|
msi_size: u64,
|
||||||
|
nr_irqs: u32,
|
||||||
|
) -> Result<Box<dyn GicDevice>> {
|
||||||
let vgic = Self::create_device(vm)?;
|
let vgic = Self::create_device(vm)?;
|
||||||
|
let redists_size: u64 = redist_size * vcpu_count;
|
||||||
|
let redists_addr: u64 = dist_addr - redists_size;
|
||||||
|
let msi_addr: u64 = redists_addr - msi_size;
|
||||||
|
|
||||||
let mut gic_device = Box::new(KvmGicV3Its {
|
let mut gic_device = Box::new(KvmGicV3Its {
|
||||||
device: vgic,
|
device: vgic,
|
||||||
its_device: None,
|
its_device: None,
|
||||||
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
gicr_typers: vec![0; vcpu_count.try_into().unwrap()],
|
||||||
gic_properties: [
|
dist_addr,
|
||||||
KvmGicV3Its::get_dist_addr(),
|
dist_size,
|
||||||
KvmGicV3Its::get_dist_size(),
|
redists_addr,
|
||||||
KvmGicV3Its::get_redists_addr(vcpu_count),
|
redists_size,
|
||||||
KvmGicV3Its::get_redists_size(vcpu_count),
|
msi_addr,
|
||||||
],
|
msi_size,
|
||||||
msi_properties: [
|
|
||||||
KvmGicV3Its::get_msi_addr(vcpu_count),
|
|
||||||
KvmGicV3Its::get_msi_size(),
|
|
||||||
],
|
|
||||||
vcpu_count,
|
vcpu_count,
|
||||||
});
|
});
|
||||||
|
|
||||||
gic_device.init_device_attributes(vm)?;
|
gic_device.init_device_attributes(vm, nr_irqs)?;
|
||||||
|
|
||||||
Ok(gic_device)
|
Ok(gic_device)
|
||||||
}
|
}
|
||||||
@ -521,21 +518,15 @@ pub mod kvm {
|
|||||||
///
|
///
|
||||||
pub fn create_gic(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
pub fn create_gic(vm: &Arc<dyn hypervisor::Vm>, vcpu_count: u64) -> Result<Box<dyn GicDevice>> {
|
||||||
debug!("creating a GICv3-ITS");
|
debug!("creating a GICv3-ITS");
|
||||||
KvmGicV3Its::new(vm, vcpu_count)
|
KvmGicV3Its::new(
|
||||||
}
|
vm,
|
||||||
|
vcpu_count,
|
||||||
/// Function that saves RDIST pending tables into guest RAM.
|
layout::GIC_V3_DIST_START.raw_value(),
|
||||||
///
|
layout::GIC_V3_DIST_SIZE,
|
||||||
/// The tables get flushed to guest RAM whenever the VM gets stopped.
|
layout::GIC_V3_REDIST_SIZE,
|
||||||
pub fn save_pending_tables(gic: &Arc<dyn hypervisor::Device>) -> Result<()> {
|
layout::GIC_V3_ITS_SIZE,
|
||||||
let init_gic_attr = kvm_bindings::kvm_device_attr {
|
layout::IRQ_NUM,
|
||||||
group: kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL,
|
)
|
||||||
attr: u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES),
|
|
||||||
addr: 0,
|
|
||||||
flags: 0,
|
|
||||||
};
|
|
||||||
gic.set_device_attr(&init_gic_attr)
|
|
||||||
.map_err(super::Error::SetDeviceAttribute)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GicDevice for KvmGicV3Its {
|
impl GicDevice for KvmGicV3Its {
|
||||||
@ -563,18 +554,23 @@ pub mod kvm {
|
|||||||
KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
|
KvmGicV3Its::ARCH_GIC_V3_MAINT_IRQ
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msi_properties(&self) -> &[u64] {
|
|
||||||
&self.msi_properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fn device_properties(&self) -> &[u64] {
|
|
||||||
&self.gic_properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fn vcpu_count(&self) -> u64 {
|
fn vcpu_count(&self) -> u64 {
|
||||||
self.vcpu_count
|
self.vcpu_count
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn device_properties(&self) -> [u64; 4] {
|
||||||
|
[
|
||||||
|
self.dist_addr,
|
||||||
|
self.dist_size,
|
||||||
|
self.redists_addr,
|
||||||
|
self.redists_size,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn msi_properties(&self) -> [u64; 2] {
|
||||||
|
[self.msi_addr, self.msi_size]
|
||||||
|
}
|
||||||
|
|
||||||
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>) {
|
fn set_its_device(&mut self, its_device: Option<Arc<dyn hypervisor::Device>>) {
|
||||||
self.its_device = its_device;
|
self.its_device = its_device;
|
||||||
}
|
}
|
||||||
@ -612,7 +608,7 @@ pub mod kvm {
|
|||||||
impl Pausable for KvmGicV3Its {
|
impl Pausable for KvmGicV3Its {
|
||||||
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||||
// Flush redistributors pending tables to guest RAM.
|
// Flush redistributors pending tables to guest RAM.
|
||||||
save_pending_tables(self.device()).map_err(|e| {
|
KvmGicV3Its::save_pending_tables(self.device()).map_err(|e| {
|
||||||
MigratableError::Pause(anyhow!(
|
MigratableError::Pause(anyhow!(
|
||||||
"Could not save GICv3ITS GIC pending tables {:?}",
|
"Could not save GICv3ITS GIC pending tables {:?}",
|
||||||
e
|
e
|
||||||
|
@ -305,7 +305,7 @@ impl InterruptManager for MsiInterruptManager {
|
|||||||
#[cfg(target_arch = "aarch64")]
|
#[cfg(target_arch = "aarch64")]
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use arch::aarch64::gic::kvm::{create_gic, save_pending_tables};
|
use arch::aarch64::gic::kvm::{create_gic, KvmGicV3Its};
|
||||||
use arch::aarch64::gic::{
|
use arch::aarch64::gic::{
|
||||||
get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
|
get_dist_regs, get_icc_regs, get_redist_regs, set_dist_regs, set_icc_regs, set_redist_regs,
|
||||||
};
|
};
|
||||||
@ -375,6 +375,6 @@ mod tests {
|
|||||||
let _ = vm.create_vcpu(0, None).unwrap();
|
let _ = vm.create_vcpu(0, None).unwrap();
|
||||||
let gic = create_gic(&vm, 1).expect("Cannot create gic");
|
let gic = create_gic(&vm, 1).expect("Cannot create gic");
|
||||||
|
|
||||||
assert!(save_pending_tables(gic.device()).is_ok());
|
assert!(KvmGicV3Its::save_pending_tables(gic.device()).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user