arch, vmm: Pass cpu topology configuation to FDT

In an Arm system, the hierarchy of CPUs is defined through three
entities that are used to describe the layout of physical CPUs in
the system:

- cluster
- core
- thread

All these three entities have their own FDT node field. Therefore,
This commit adds an AArch64-specific helper to pass the config from
the Cloud Hypervisor command line to the `configure_system`, where
eventually the `create_fdt` is called.

Signed-off-by: Henry Wang <Henry.Wang@arm.com>
This commit is contained in:
Henry Wang 2021-07-29 03:44:50 -04:00 committed by Michael
parent 5c6139bbff
commit 7fb980f17b
4 changed files with 22 additions and 2 deletions

View File

@ -72,10 +72,12 @@ pub enum Error {
type Result<T> = result::Result<T, Error>;
/// Creates the flattened device tree for this aarch64 VM.
#[allow(clippy::too_many_arguments)]
pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline: &CStr,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
device_info: &HashMap<(DeviceType, String), T, S>,
gic_device: &dyn GicDevice,
initrd: &Option<InitramfsConfig>,
@ -98,7 +100,7 @@ pub fn create_fdt<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHash
// This is not mandatory but we use it to point the root node to the node
// containing description of the interrupt controller for this VM.
fdt.property_u32("interrupt-parent", GIC_PHANDLE)?;
create_cpu_nodes(&mut fdt, &vcpu_mpidr)?;
create_cpu_nodes(&mut fdt, &vcpu_mpidr, vcpu_topology)?;
create_memory_node(&mut fdt, guest_mem)?;
create_chosen_node(&mut fdt, cmdline.to_str().unwrap(), initrd)?;
create_gic_node(&mut fdt, gic_device)?;
@ -126,7 +128,11 @@ pub fn write_fdt_to_memory(fdt_final: Vec<u8>, guest_mem: &GuestMemoryMmap) -> R
}
// Following are the auxiliary function for creating the different nodes that we append to our FDT.
fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> FdtWriterResult<()> {
fn create_cpu_nodes(
fdt: &mut FdtWriter,
vcpu_mpidr: &[u64],
vcpu_topology: Option<(u8, u8, u8)>,
) -> FdtWriterResult<()> {
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/arm/cpus.yaml.
let cpus_node = fdt.begin_node("cpus")?;
fdt.property_u32("#address-cells", 0x1)?;

View File

@ -135,10 +135,12 @@ pub fn arch_memory_regions(size: GuestUsize) -> Vec<(GuestAddress, usize, Region
}
/// Configures the system and should be called once per vm before starting vcpu threads.
#[allow(clippy::too_many_arguments)]
pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::BuildHasher>(
guest_mem: &GuestMemoryMmap,
cmdline_cstring: &CStr,
vcpu_mpidr: Vec<u64>,
vcpu_topology: Option<(u8, u8, u8)>,
device_info: &HashMap<(DeviceType, String), T, S>,
initrd: &Option<super::InitramfsConfig>,
pci_space_address: &(u64, u64),
@ -148,6 +150,7 @@ pub fn configure_system<T: DeviceInfoForFdt + Clone + Debug, S: ::std::hash::Bui
guest_mem,
cmdline_cstring,
vcpu_mpidr,
vcpu_topology,
device_info,
gic_device,
initrd,

View File

@ -978,6 +978,14 @@ impl CpuManager {
.collect()
}
#[cfg(target_arch = "aarch64")]
pub fn get_vcpu_topology(&self) -> Option<(u8, u8, u8)> {
self.config
.topology
.clone()
.map(|t| (t.threads_per_core, t.cores_per_die, t.packages))
}
#[cfg(feature = "acpi")]
pub fn create_madt(&self) -> Sdt {
use crate::acpi;

View File

@ -1072,6 +1072,7 @@ impl Vm {
fn configure_system(&mut self) -> Result<()> {
let cmdline_cstring = self.get_cmdline()?;
let vcpu_mpidrs = self.cpu_manager.lock().unwrap().get_mpidrs();
let vcpu_topology = self.cpu_manager.lock().unwrap().get_vcpu_topology();
let mem = self.memory_manager.lock().unwrap().boot_guest_memory();
let initramfs_config = match self.initramfs {
Some(_) => Some(self.load_initramfs(&mem)?),
@ -1129,6 +1130,7 @@ impl Vm {
&mem,
&cmdline_cstring,
vcpu_mpidrs,
vcpu_topology,
device_info,
&initramfs_config,
&pci_space,
@ -2653,6 +2655,7 @@ mod tests {
&mem,
&CString::new("console=tty0").unwrap(),
vec![0],
Some((0, 0, 0)),
&dev_info,
&*gic,
&None,