From ec73733b2112d231f3ad8cf14d623002ad920cf7 Mon Sep 17 00:00:00 2001 From: Anirudh Rayabharam Date: Wed, 18 Mar 2026 11:39:32 +0000 Subject: [PATCH] vmm: add cache topology info to ACPI PPTT Read the host cache info from sysfs and pass through the same to the guest via the PPTT table. This is the same as the approach taken for FDT. Similar to that, assume that the L3 cache is always shared and the L2 cache is unique per CPU. Signed-off-by: Anirudh Rayabharam --- vmm/src/cpu.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 107 insertions(+), 4 deletions(-) diff --git a/vmm/src/cpu.rs b/vmm/src/cpu.rs index ff7575c0b..e6925bb7f 100644 --- a/vmm/src/cpu.rs +++ b/vmm/src/cpu.rs @@ -21,10 +21,12 @@ use std::sync::{Arc, Barrier, Mutex}; use std::{any, cmp, hint, io, panic, result, thread, time}; #[cfg(target_arch = "aarch64")] -use acpi_tables::pptt::{PPTT, ProcessorNode}; +use acpi_tables::pptt::{CacheNodeBuilder, CacheType, PPTT, ProcessorNode}; use acpi_tables::sdt::Sdt; use acpi_tables::{Aml, aml}; use anyhow::anyhow; +#[cfg(target_arch = "aarch64")] +use arch::aarch64::cache::{CacheTopologyInfo, read_cache_topology}; use arch::{EntryPoint, NumaNodes, layout}; #[cfg(target_arch = "aarch64")] use devices::gic::Gic; @@ -1955,11 +1957,90 @@ impl CpuManager { .unwrap_or((1, u16::try_from(self.max_vcpus()).unwrap(), 1, 1)); let cores_per_package = cores_per_die * dies_per_package; + // Add cache info. + let cache_info = read_cache_topology(); + let CacheTopologyInfo { + l1_d_cache_size, + l1_d_cache_line_size, + l1_d_cache_sets, + l1_i_cache_size, + l1_i_cache_line_size, + l1_i_cache_sets, + l2_cache_size, + l2_cache_line_size, + l2_cache_sets, + l3_cache_size, + l3_cache_line_size, + l3_cache_sets, + .. + } = cache_info.unwrap_or_default(); + let mut pptt = PPTT::new(*b"CLOUDH", *b"CHPPTT ", 1); + let l3_cache_handle = if l3_cache_size != 0 { + let l3_cache_node = CacheNodeBuilder::default() + .cache_type(CacheType::Unified) + .sets(l3_cache_sets) + .size(l3_cache_size) + .line_size(l3_cache_line_size as u16) + .to_node(); + Some(pptt.add_cache(l3_cache_node)) + } else { + None + }; + + let l2_cache_handle = if l2_cache_size != 0 { + let l2_cache_node = CacheNodeBuilder::default() + .cache_type(CacheType::Unified) + .sets(l2_cache_sets) + .size(l2_cache_size) + .line_size(l2_cache_line_size as u16) + .to_node(); + Some(pptt.add_cache(l2_cache_node)) + } else { + None + }; + + let l1d_cache_handle = if l1_d_cache_size != 0 { + let mut l1d_cache_node = CacheNodeBuilder::default() + .cache_type(CacheType::Data) + .sets(l1_d_cache_sets) + .size(l1_d_cache_size) + .line_size(l1_d_cache_line_size as u16); + + if let Some(ref l2_cache_handle) = l2_cache_handle { + l1d_cache_node = l1d_cache_node.next_level(l2_cache_handle); + } + + Some(pptt.add_cache(l1d_cache_node.to_node())) + } else { + None + }; + + let l1i_cache_handle = if l1_i_cache_size != 0 { + let mut l1i_cache_node = CacheNodeBuilder::default() + .cache_type(CacheType::Instruction) + .sets(l1_i_cache_sets) + .size(l1_i_cache_size) + .line_size(l1_i_cache_line_size as u16); + + if let Some(ref l2_cache_handle) = l2_cache_handle { + l1i_cache_node = l1i_cache_node.next_level(l2_cache_handle); + } + + Some(pptt.add_cache(l1i_cache_node.to_node())) + } else { + None + }; + for cluster_idx in 0..packages { if cpus < self.config.boot_vcpus as usize { - let cluster_hierarchy_node = ProcessorNode::new(None, cluster_idx as u32).valid(); + let mut cluster_hierarchy_node = + ProcessorNode::new(None, cluster_idx as u32).valid(); + if let Some(ref l3_cache_handle) = l3_cache_handle { + cluster_hierarchy_node = cluster_hierarchy_node.add_cache(l3_cache_handle); + } + let cluster_handle = pptt.add_processor(cluster_hierarchy_node); for core_idx in 0..cores_per_package { @@ -1969,19 +2050,41 @@ impl CpuManager { let core_handle = pptt.add_processor(core_hierarchy_node); for _thread_idx in 0..threads_per_core { - let thread_hierarchy_node = + let mut thread_hierarchy_node = ProcessorNode::new(Some(&core_handle), uid as u32) .valid() .thread() .leaf(); + + if let Some(ref l1d_cache_handle) = l1d_cache_handle { + thread_hierarchy_node = + thread_hierarchy_node.add_cache(l1d_cache_handle); + } + + if let Some(ref l1i_cache_handle) = l1i_cache_handle { + thread_hierarchy_node = + thread_hierarchy_node.add_cache(l1i_cache_handle); + } + pptt.add_processor(thread_hierarchy_node); uid += 1; } } else { - let thread_hierarchy_node = + let mut thread_hierarchy_node = ProcessorNode::new(Some(&cluster_handle), uid as u32) .valid() .leaf(); + + if let Some(ref l1d_cache_handle) = l1d_cache_handle { + thread_hierarchy_node = + thread_hierarchy_node.add_cache(l1d_cache_handle); + } + + if let Some(ref l1i_cache_handle) = l1i_cache_handle { + thread_hierarchy_node = + thread_hierarchy_node.add_cache(l1i_cache_handle); + } + pptt.add_processor(thread_hierarchy_node); uid += 1; }