diff --git a/arch/src/aarch64/fdt.rs b/arch/src/aarch64/fdt.rs index 7845e7010..a8bed8938 100644 --- a/arch/src/aarch64/fdt.rs +++ b/arch/src/aarch64/fdt.rs @@ -98,7 +98,7 @@ pub enum CacheLevel { L3 = 3, } -/// NOTE: CACHE SIZE file directory example, +/// 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(); @@ -111,7 +111,7 @@ pub fn get_cache_size(cache_level: CacheLevel) -> u32 { let file_path = Path::new(&file_directory); if !file_path.exists() { - error!("File: {} not exist.", file_directory); + warn!("File: {} does not exist.", file_directory); 0 } else { info!("File: {} exist.", file_directory); @@ -132,7 +132,7 @@ pub fn get_cache_size(cache_level: CacheLevel) -> u32 { } } -/// NOTE: CACHE COHERENCY LINE SIZE file directory example, +/// NOTE: 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(); @@ -145,7 +145,7 @@ pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 { let file_path = Path::new(&file_directory); if !file_path.exists() { - error!("File: {} not exist.", file_directory); + warn!("File: {} does not exist.", file_directory); 0 } else { info!("File: {} exist.", file_directory); @@ -155,7 +155,7 @@ pub fn get_cache_coherency_line_size(cache_level: CacheLevel) -> u32 { } } -/// NOTE: CACHE NUMBER OF SETS file directory example, +/// NOTE: 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(); @@ -168,7 +168,7 @@ pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 { let file_path = Path::new(&file_directory); if !file_path.exists() { - error!("File: {} not exist.", file_directory); + warn!("File: {} does not exist.", file_directory); 0 } else { info!("File: {} exist.", file_directory); @@ -178,6 +178,41 @@ pub fn get_cache_number_of_sets(cache_level: CacheLevel) -> u32 { } } +/// NOTE: shared_cpu_list file directory example, +/// "/sys/devices/system/cpu/cpu0/cache/index0/shared_cpu_list". +pub fn get_cache_shared(cache_level: CacheLevel) -> bool { + let mut file_directory: String = "/sys/devices/system/cpu/cpu0/cache".to_string(); + let mut result = true; + + match cache_level { + CacheLevel::L1D | CacheLevel::L1I => result = false, + CacheLevel::L2 => file_directory += "/index2/shared_cpu_list", + CacheLevel::L3 => file_directory += "/index3/shared_cpu_list", + } + + if !result { + return false; + } + + let file_path = Path::new(&file_directory); + if !file_path.exists() { + warn!("File: {} does not exist.", file_directory); + result = false; + } else { + info!("File: {} exist.", file_directory); + + let src = fs::read_to_string(file_directory).expect("File not exists or file corrupted."); + let src = src.trim(); + if src.is_empty() { + result = false; + } else { + result = src.contains('-') || src.contains(','); + } + } + + result +} + /// Creates the flattened device tree for this aarch64 VM. #[allow(clippy::too_many_arguments)] pub fn create_fdt( @@ -255,6 +290,11 @@ fn create_cpu_nodes( fdt.property_u32("#size-cells", 0x0)?; let num_cpus = vcpu_mpidr.len(); + let threads_per_core = vcpu_topology.unwrap_or_default().0; + let cores_per_package = vcpu_topology.unwrap_or_default().1; + let packages = vcpu_topology.unwrap_or_default().2; + + let max_cpus: u32 = (threads_per_core * cores_per_package * packages).into(); // Add cache info. // L1 Data Cache Info. @@ -277,10 +317,14 @@ fn create_cpu_nodes( let mut l3_cache_line_size: u32 = 0; let mut l3_cache_sets: u32 = 0; + // Cache Shared Info. + let mut l2_cache_shared: bool = false; + let mut l3_cache_shared: bool = false; + 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."); + warn!("cache sysfs system does not exist."); } else { info!("cache sysfs system exists."); // L1 Data Cache Info. @@ -302,6 +346,14 @@ fn create_cpu_nodes( 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); + + // Cache Shared Info. + if l2_cache_size != 0 { + l2_cache_shared = get_cache_shared(CacheLevel::L2); + } + if l3_cache_size != 0 { + l3_cache_shared = get_cache_shared(CacheLevel::L3); + } } for (cpu_id, mpidr) in vcpu_mpidr.iter().enumerate().take(num_cpus) { @@ -318,21 +370,6 @@ 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() { @@ -343,37 +380,89 @@ fn create_cpu_nodes( } } + 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 && !l2_cache_shared { + fdt.property_u32( + "next-level-cache", + cpu_id as u32 + max_cpus + FIRST_VCPU_PHANDLE + L2_CACHE_PHANDLE, + )?; + + let l2_cache_name = "l2-cache0"; + let l2_cache_node = fdt.begin_node(l2_cache_name)?; + // PHANDLE is used to mark device node, and PHANDLE is unique. To avoid phandle + // conflicts with other device nodes, consider the previous CPU PHANDLE, so the + // CPU L2 cache PHANDLE must start from the largest CPU PHANDLE plus 1. + fdt.property_u32( + "phandle", + cpu_id as u32 + max_cpus + FIRST_VCPU_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 && l3_cache_shared { + let package_id: u32 = cpu_id as u32 / cores_per_package as u32; + fdt.property_u32( + "next-level-cache", + package_id + + num_cpus as u32 + + max_cpus + + FIRST_VCPU_PHANDLE + + L2_CACHE_PHANDLE + + L3_CACHE_PHANDLE, + )?; + } + + fdt.end_node(l2_cache_node)?; + } + if l2_cache_size != 0 && l2_cache_shared { + warn!("L2 cache shared with other cpus"); + } + } + 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 cache_exist && l3_cache_size != 0 && !l2_cache_shared && l3_cache_shared { + let mut i: u32 = 0; + while i < packages.into() { + let l3_cache_name = "l3-cache0"; + let l3_cache_node = fdt.begin_node(l3_cache_name)?; + // ARM L3 cache is generally shared within the package (socket), so the + // L3 cache node pointed to by the CPU in the package has the same L3 + // cache PHANDLE. The L3 cache phandle must start from the largest L2 + // cache PHANDLE plus 1 to avoid duplication. + fdt.property_u32( + "phandle", + i + num_cpus as u32 + + max_cpus + + FIRST_VCPU_PHANDLE + + L2_CACHE_PHANDLE + + L3_CACHE_PHANDLE, + )?; - if l3_cache_size != 0 { - fdt.property_u32("next-level-cache", 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)?; + + i += 1; } - - 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 {