aarch64/fdt: Forward host cache layout to guest

Using the data from sysfs forward the host host cache layout to the
guest using the FDT tables.

TEST=The host cache layout (from sysfs) can be seen in inside the guest
using lscpu.

Signed-off-by: zhongbingnan <zhongbingnan@bytedance.com>
This commit is contained in:
zhongbingnan 2023-05-20 00:13:55 +08:00 committed by Rob Bradford
parent 402a24a688
commit c1b33329db

View File

@ -24,6 +24,8 @@ use super::layout::{
IRQ_BASE, MEM_32BIT_DEVICES_SIZE, MEM_32BIT_DEVICES_START, MEM_PCI_IO_SIZE, MEM_PCI_IO_START,
PCI_HIGH_BASE, PCI_MMIO_CONFIG_SIZE_PER_SEGMENT,
};
use std::fs;
use std::path::Path;
use vm_fdt::{FdtWriter, FdtWriterResult};
use vm_memory::{Address, Bytes, GuestMemory, GuestMemoryError, GuestMemoryRegion};
@ -40,8 +42,12 @@ const VIRTIO_IOMMU_PHANDLE: u32 = 5;
// NOTE: Keep FIRST_VCPU_PHANDLE the last PHANDLE defined.
// This is a value for uniquely identifying the FDT node containing the first vCPU.
// The last number of vCPU phandle depends on the number of vCPUs.
const FIRST_VCPU_PHANDLE: u32 = 6;
const FIRST_VCPU_PHANDLE: u32 = 8;
// This is a value for uniquely identifying the FDT node containing the L2 cache info
const L2_CACHE_PHANDLE: u32 = 6;
// This is a value for uniquely identifying the FDT node containing the L3 cache info
const L3_CACHE_PHANDLE: u32 = 7;
// Read the documentation specified when appending the root node to the FDT.
const ADDRESS_CELLS: u32 = 0x2;
const SIZE_CELLS: u32 = 0x2;
@ -81,6 +87,97 @@ pub enum Error {
}
type Result<T> = result::Result<T, Error>;
pub enum CacheLevel {
/// L1 data cache
L1D = 0,
/// L1 instruction cache
L1I = 1,
/// L2 cache
L2 = 2,
/// L3 cache
L3 = 3,
}
/// NOTE: CACHE SIZE file directory example,
/// "/sys/devices/system/cpu/cpu0/cache/index0/size".
pub fn get_cache_size(cache_level: CacheLevel) -> u32 {
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
match cache_level {
CacheLevel::L1D => file_directory += "/index0/size",
CacheLevel::L1I => file_directory += "/index1/size",
CacheLevel::L2 => file_directory += "/index2/size",
CacheLevel::L3 => file_directory += "/index3/size",
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
error!("File: {} not exist.", file_directory);
0
} else {
info!("File: {} exist.", file_directory);
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
// The content of the file is as simple as a size, like: "32K"
let src = src.trim();
let src_digits: u32 = src[0..src.len() - 1].parse().unwrap();
let src_unit = &src[src.len() - 1..];
src_digits
* match src_unit {
"K" => 1024,
"M" => 1024u32.pow(2),
"G" => 1024u32.pow(3),
_ => 1,
}
}
}
/// NOTE: CACHE COHERENCY LINE SIZE file directory example,
/// "/sys/devices/system/cpu/cpu0/cache/index0/coherency_line_size".
pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 {
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
match cache_level {
CacheLevel::L1D => file_directory += "/index0/coherency_line_size",
CacheLevel::L1I => file_directory += "/index1/coherency_line_size",
CacheLevel::L2 => file_directory += "/index2/coherency_line_size",
CacheLevel::L3 => file_directory += "/index3/coherency_line_size",
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
error!("File: {} not exist.", file_directory);
0
} else {
info!("File: {} exist.", file_directory);
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
src.trim().parse::<u32>().unwrap()
}
}
/// NOTE: CACHE NUMBER OF SETS file directory example,
/// "/sys/devices/system/cpu/cpu0/cache/index0/number_of_sets".
pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 {
let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string();
match cache_level {
CacheLevel::L1D => file_directory += "/index0/number_of_sets",
CacheLevel::L1I => file_directory += "/index1/number_of_sets",
CacheLevel::L2 => file_directory += "/index2/number_of_sets",
CacheLevel::L3 => file_directory += "/index3/number_of_sets",
}
let file_path = Path::new(&file_directory);
if !file_path.exists() {
error!("File: {} not exist.", file_directory);
0
} else {
info!("File: {} exist.", file_directory);
let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted.");
src.trim().parse::<u32>().unwrap()
}
}
/// 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>(
@ -159,6 +256,54 @@ fn create_cpu_nodes(
let num_cpus = vcpu_mpidr.len();
// Add cache info.
// L1 Data Cache Info.
let mut l1_d_cache_size: u32 = 0;
let mut l1_d_cache_line_size: u32 = 0;
let mut l1_d_cache_sets: u32 = 0;
// L1 Instruction Cache Info.
let mut l1_i_cache_size: u32 = 0;
let mut l1_i_cache_line_size: u32 = 0;
let mut l1_i_cache_sets: u32 = 0;
// L2 Cache Info.
let mut l2_cache_size: u32 = 0;
let mut l2_cache_line_size: u32 = 0;
let mut l2_cache_sets: u32 = 0;
// L3 Cache Info.
let mut l3_cache_size: u32 = 0;
let mut l3_cache_line_size: u32 = 0;
let mut l3_cache_sets: u32 = 0;
let cache_path = Path::new("/sys/devices/system/cpu/cpu0/cache");
let cache_exist: bool = cache_path.exists();
if !cache_exist {
error!("cache sysfs system does not exist.");
} else {
info!("cache sysfs system exists.");
// L1 Data Cache Info.
l1_d_cache_size = get_cache_size(CacheLevel::L1D);
l1_d_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1D);
l1_d_cache_sets = get_cache_number_of_sets(CacheLevel::L1D);
// L1 Instruction Cache Info.
l1_i_cache_size = get_cache_size(CacheLevel::L1I);
l1_i_cache_line_size = get_cache_coherency_line_size(CacheLevel::L1I);
l1_i_cache_sets = get_cache_number_of_sets(CacheLevel::L1I);
// L2 Cache Info.
l2_cache_size = get_cache_size(CacheLevel::L2);
l2_cache_line_size = get_cache_coherency_line_size(CacheLevel::L2);
l2_cache_sets = get_cache_number_of_sets(CacheLevel::L2);
// L3 Cache Info.
l3_cache_size = get_cache_size(CacheLevel::L3);
l3_cache_line_size = get_cache_coherency_line_size(CacheLevel::L3);
l3_cache_sets = get_cache_number_of_sets(CacheLevel::L3);
}
for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) {
let cpu_name = format!("cpu@{cpu_id:x}");
let cpu_node = fdt.begin_node(&cpu_name)?;
@ -173,6 +318,21 @@ fn create_cpu_nodes(
fdt.property_u32("reg", (mpidr & 0x7FFFFF) as u32)?;
fdt.property_u32("phandle", cpu_id as u32 + FIRST_VCPU_PHANDLE)?;
if cache_exist && l1_d_cache_size != 0 && l1_i_cache_size != 0 {
// Add cache info.
fdt.property_u32("d-cache-size", l1_d_cache_size)?;
fdt.property_u32("d-cache-line-size", l1_d_cache_line_size)?;
fdt.property_u32("d-cache-sets", l1_d_cache_sets)?;
fdt.property_u32("i-cache-size", l1_i_cache_size)?;
fdt.property_u32("i-cache-line-size", l1_i_cache_line_size)?;
fdt.property_u32("i-cache-sets", l1_i_cache_sets)?;
if l2_cache_size != 0 {
fdt.property_u32("next-level-cache", L2_CACHE_PHANDLE)?;
}
}
// Add `numa-node-id` property if there is any numa config.
if numa_nodes.len() > 1 {
for numa_node_idx in 0..numa_nodes.len() {
@ -186,6 +346,36 @@ fn create_cpu_nodes(
fdt.end_node(cpu_node)?;
}
if cache_exist && l2_cache_size != 0 {
let l2_cache_name = "l2-cache0";
let l2_cache_node = fdt.begin_node(l2_cache_name)?;
fdt.property_u32("phandle", L2_CACHE_PHANDLE)?;
fdt.property_string("compatible", "cache")?;
fdt.property_u32("cache-size", l2_cache_size)?;
fdt.property_u32("cache-line-size", l2_cache_line_size)?;
fdt.property_u32("cache-sets", l2_cache_sets)?;
fdt.property_u32("cache-level", 2)?;
if l3_cache_size != 0 {
fdt.property_u32("next-level-cache", L3_CACHE_PHANDLE)?;
}
fdt.end_node(l2_cache_node)?;
}
if cache_exist && l3_cache_size != 0 {
let l3_cache_name = "l3-cache0";
let l3_cache_node = fdt.begin_node(l3_cache_name)?;
fdt.property_u32("phandle", L3_CACHE_PHANDLE)?;
fdt.property_string("compatible", "cache")?;
fdt.property_null("cache-unified")?;
fdt.property_u32("cache-size", l3_cache_size)?;
fdt.property_u32("cache-line-size", l3_cache_line_size)?;
fdt.property_u32("cache-sets", l3_cache_sets)?;
fdt.property_u32("cache-level", 3)?;
fdt.end_node(l3_cache_node)?;
}
if let Some(topology) = vcpu_topology {
let (threads_per_core, cores_per_package, packages) = topology;
let cpu_map_node = fdt.begin_node("cpu-map")?;