in src/arch/src/aarch64/fdt.rs [122:224]
fn create_cpu_nodes(fdt: &mut FdtWriter, vcpu_mpidr: &[u64]) -> Result<()> {
// Since the L1 caches are not shareable among CPUs and they are direct attributes of the
// cpu in the device tree, we process the L1 and non-L1 caches separately.
// We use sysfs for extracting the cache information.
let mut l1_caches: Vec<CacheEntry> = Vec::new();
let mut non_l1_caches: Vec<CacheEntry> = Vec::new();
// We use sysfs for extracting the cache information.
read_cache_config(&mut l1_caches, &mut non_l1_caches)
.map_err(|e| Error::ReadCacheInfo(e.to_string()))?;
// See https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/arm/cpus.yaml.
let cpus = fdt.begin_node("cpus")?;
// As per documentation, on ARM v8 64-bit systems value should be set to 2.
fdt.property_u32("#address-cells", 0x02)?;
fdt.property_u32("#size-cells", 0x0)?;
let num_cpus = vcpu_mpidr.len();
for (cpu_index, mpidr) in vcpu_mpidr.iter().enumerate() {
let cpu = fdt.begin_node(&format!("cpu@{:x}", cpu_index))?;
fdt.property_string("device_type", "cpu")?;
fdt.property_string("compatible", "arm,arm-v8")?;
// The power state coordination interface (PSCI) needs to be enabled for
// all vcpus.
fdt.property_string("enable-method", "psci")?;
// Set the field to first 24 bits of the MPIDR - Multiprocessor Affinity Register.
// See http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0488c/BABHBJCI.html.
fdt.property_u64("reg", mpidr & 0x7FFFFF)?;
for cache in l1_caches.iter() {
// Please check out
// https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf,
// section 3.8.
if let Some(size) = cache.size_ {
fdt.property_u32(cache.type_.of_cache_size(), size as u32)?;
}
if let Some(line_size) = cache.line_size {
fdt.property_u32(cache.type_.of_cache_line_size(), line_size as u32)?;
}
if let Some(number_of_sets) = cache.number_of_sets {
fdt.property_u32(cache.type_.of_cache_sets(), number_of_sets as u32)?;
}
}
// Some of the non-l1 caches can be shared amongst CPUs. You can see an example of a shared scenario
// in https://github.com/devicetree-org/devicetree-specification/releases/download/v0.3/devicetree-specification-v0.3.pdf,
// 3.8.1 Example.
let mut prev_level = 1;
let mut cache_node: Option<FdtWriterNode> = None;
for cache in non_l1_caches.iter() {
// We append the next-level-cache node (the node that specifies the cache hierarchy)
// in the next iteration. For example,
// L2-cache {
// cache-size = <0x8000> ----> first iteration
// next-level-cache = <&l3-cache> ---> second iteration
// }
// The cpus per unit cannot be 0 since the sysfs will also include the current cpu
// in the list of shared cpus so it needs to be at least 1. Firecracker trusts the host.
// The operation is safe since we already checked when creating cache attributes that
// cpus_per_unit is not 0 (.e look for mask_str2bit_count function).
let cache_phandle = LAST_CACHE_PHANDLE
- (num_cpus * (cache.level - 2) as usize + cpu_index / cache.cpus_per_unit as usize)
as u32;
if prev_level != cache.level {
fdt.property_u32("next-level-cache", cache_phandle)?;
if prev_level > 1 && cache_node.is_some() {
fdt.end_node(cache_node.take().unwrap())?;
}
}
if cpu_index % cache.cpus_per_unit as usize == 0 {
cache_node = Some(fdt.begin_node(&format!(
"l{}-{}-cache",
cache.level,
cpu_index / cache.cpus_per_unit as usize
))?);
fdt.property_u32("phandle", cache_phandle)?;
fdt.property_string("compatible", "cache")?;
fdt.property_u32("cache-level", cache.level as u32)?;
if let Some(size) = cache.size_ {
fdt.property_u32(cache.type_.of_cache_size(), size as u32)?;
}
if let Some(line_size) = cache.line_size {
fdt.property_u32(cache.type_.of_cache_line_size(), line_size as u32)?;
}
if let Some(number_of_sets) = cache.number_of_sets {
fdt.property_u32(cache.type_.of_cache_sets(), number_of_sets as u32)?;
}
if let Some(cache_type) = cache.type_.of_cache_type() {
fdt.property_null(cache_type)?;
}
prev_level = cache.level;
}
}
if let Some(node) = cache_node {
fdt.end_node(node)?;
}
fdt.end_node(cpu)?;
}
fdt.end_node(cpus)?;
Ok(())
}