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 <anrayabh@microsoft.com>
This commit is contained in:
Anirudh Rayabharam
2026-03-18 11:39:32 +00:00
committed by Rob Bradford
parent 9446dad1d0
commit ec73733b21

View File

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