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:
Michael Zhao 2022-05-24 14:54:41 +08:00 committed by Xin Wang
parent 4a2d3cb4f5
commit 0fd6521759
3 changed files with 85 additions and 89 deletions

View File

@ -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)?;
} }

View File

@ -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

View File

@ -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());
} }
} }