diff --git a/arch/src/aarch64/gic/gicv2.rs b/arch/src/aarch64/gic/gicv2.rs index 1ca795f1a..4fd0cb9a8 100644 --- a/arch/src/aarch64/gic/gicv2.rs +++ b/arch/src/aarch64/gic/gicv2.rs @@ -8,6 +8,7 @@ pub mod kvm { type Result = result::Result; use crate::layout; use hypervisor::kvm::kvm_bindings; + use std::convert::TryInto; use std::sync::Arc; /// Represent a GIC v2 device @@ -15,6 +16,11 @@ pub mod kvm { /// The hypervisor agnostic device device: Arc, + /// Vector holding values of GICR_TYPER for each vCPU + /// As GICv2 does not have redistributor, this field is always + /// a zero vector. + gicr_typers: Vec, + /// GIC device properties, to be used for setting up the fdt entry properties: [u64; 4], @@ -72,6 +78,10 @@ pub mod kvm { fn vcpu_count(&self) -> u64 { self.vcpu_count } + + fn set_gicr_typers(&mut self, gicr_typers: Vec) { + self.gicr_typers = gicr_typers; + } } impl KvmGICDevice for KvmGICv2 { @@ -85,6 +95,7 @@ pub mod kvm { ) -> Box { Box::new(KvmGICv2 { device, + gicr_typers: vec![0; vcpu_count.try_into().unwrap()], properties: [ KvmGICv2::get_dist_addr(), KvmGICv2::get_dist_size(), diff --git a/arch/src/aarch64/gic/gicv3.rs b/arch/src/aarch64/gic/gicv3.rs index c7a36db9c..280070a93 100644 --- a/arch/src/aarch64/gic/gicv3.rs +++ b/arch/src/aarch64/gic/gicv3.rs @@ -6,6 +6,7 @@ pub mod kvm { use crate::aarch64::gic::{Error, GICDevice}; use crate::layout; use hypervisor::kvm::kvm_bindings; + use std::convert::TryInto; use std::sync::Arc; use std::{boxed::Box, result}; type Result = result::Result; @@ -14,6 +15,9 @@ pub mod kvm { /// The hypervisor agnostic device device: Arc, + /// Vector holding values of GICR_TYPER for each vCPU + gicr_typers: Vec, + /// GIC device properties, to be used for setting up the fdt entry properties: [u64; 4], @@ -72,6 +76,10 @@ pub mod kvm { fn vcpu_count(&self) -> u64 { self.vcpu_count } + + fn set_gicr_typers(&mut self, gicr_typers: Vec) { + self.gicr_typers = gicr_typers; + } } impl KvmGICDevice for KvmGICv3 { @@ -85,6 +93,7 @@ pub mod kvm { ) -> Box { Box::new(KvmGICv3 { device, + gicr_typers: vec![0; vcpu_count.try_into().unwrap()], properties: [ KvmGICv3::get_dist_addr(), KvmGICv3::get_dist_size(), diff --git a/arch/src/aarch64/gic/gicv3_its.rs b/arch/src/aarch64/gic/gicv3_its.rs index 9220a7afd..f366159c7 100644 --- a/arch/src/aarch64/gic/gicv3_its.rs +++ b/arch/src/aarch64/gic/gicv3_its.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 pub mod kvm { + use std::convert::TryInto; use std::sync::Arc; use std::{boxed::Box, result}; type Result = result::Result; @@ -14,6 +15,9 @@ pub mod kvm { /// The hypervisor agnostic device device: Arc, + /// Vector holding values of GICR_TYPER for each vCPU + gicr_typers: Vec, + /// GIC device properties, to be used for setting up the fdt entry gic_properties: [u64; 4], @@ -68,6 +72,10 @@ pub mod kvm { fn vcpu_count(&self) -> u64 { self.vcpu_count } + + fn set_gicr_typers(&mut self, gicr_typers: Vec) { + self.gicr_typers = gicr_typers; + } } impl KvmGICDevice for KvmGICv3ITS { @@ -81,6 +89,7 @@ pub mod kvm { ) -> Box { Box::new(KvmGICv3ITS { device, + gicr_typers: vec![0; vcpu_count.try_into().unwrap()], gic_properties: [ KvmGICv3::get_dist_addr(), KvmGICv3::get_dist_size(), diff --git a/arch/src/aarch64/gic/mod.rs b/arch/src/aarch64/gic/mod.rs index c39b79864..2941305e0 100644 --- a/arch/src/aarch64/gic/mod.rs +++ b/arch/src/aarch64/gic/mod.rs @@ -56,6 +56,9 @@ pub trait GICDevice: Send { fn msi_properties(&self) -> &[u64] { &[] } + + /// Get the values of GICR_TYPER for each vCPU. + fn set_gicr_typers(&mut self, gicr_typers: Vec); } pub mod kvm { diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 4efa23a3b..f8196b675 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -50,6 +50,8 @@ use hypervisor::kvm_ioctls; use hypervisor::kvm_ioctls::*; #[cfg(feature = "mmio_support")] use hypervisor::vm::DataMatch; +#[cfg(target_arch = "aarch64")] +use hypervisor::CpuState; use libc::TIOCGWINSZ; use libc::{MAP_NORESERVE, MAP_PRIVATE, MAP_SHARED, O_TMPFILE, PROT_READ, PROT_WRITE}; #[cfg(feature = "pci_support")] @@ -1171,6 +1173,41 @@ impl DeviceManager { pub fn get_gic_device_entity(&self) -> Option<&Arc>>> { self.gic_device_entity.as_ref() } + #[cfg(target_arch = "aarch64")] + pub fn construct_gicr_typers(&self, vcpu_states: &[CpuState]) { + /* Pre-construct the GICR_TYPER: + * For our implementation: + * Top 32 bits are the affinity value of the associated CPU + * CommonLPIAff == 01 (redistributors with same Aff3 share LPI table) + * Processor_Number == CPU index starting from 0 + * DPGS == 0 (GICR_CTLR.DPG* not supported) + * Last == 1 if this is the last redistributor in a series of + * contiguous redistributor pages + * DirectLPI == 0 (direct injection of LPIs not supported) + * VLPIS == 0 (virtual LPIs not supported) + * PLPIS == 0 (physical LPIs not supported) + */ + let mut gicr_typers: Vec = Vec::new(); + for (index, state) in vcpu_states.iter().enumerate() { + let last = { + if index == vcpu_states.len() - 1 { + 1 + } else { + 0 + } + }; + //calculate affinity + let mut cpu_affid = state.mpidr & 1095233437695; + cpu_affid = ((cpu_affid & 0xFF00000000) >> 8) | (cpu_affid & 0xFFFFFF); + gicr_typers.push((cpu_affid << 32) | (1 << 24) | (index as u64) << 8 | (last << 4)); + } + + self.get_gic_device_entity() + .unwrap() + .lock() + .unwrap() + .set_gicr_typers(gicr_typers) + } #[cfg(target_arch = "aarch64")] pub fn enable_interrupt_controller(&self) -> DeviceManagerResult<()> {