From 65a23c6fc615e10e9a6b8221b2f0286c32a81c75 Mon Sep 17 00:00:00 2001 From: Sebastien Boeuf Date: Thu, 27 Aug 2020 19:32:03 +0200 Subject: [PATCH] vmm: acpi: Create the SRAT table The SRAT table (System Resource Affinity Table) is needed to describe NUMA nodes and how memory ranges and CPUs are attached to them. For now it simply attaches a list of Memory Affinity structures based on the list of NUMA nodes created from the VMM. Signed-off-by: Sebastien Boeuf --- vmm/src/acpi.rs | 86 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/vmm/src/acpi.rs b/vmm/src/acpi.rs index 488ec9876..2984c2fcc 100644 --- a/vmm/src/acpi.rs +++ b/vmm/src/acpi.rs @@ -2,21 +2,17 @@ // // SPDX-License-Identifier: Apache-2.0 // +use crate::cpu::CpuManager; +use crate::device_manager::DeviceManager; +use crate::memory_manager::MemoryManager; use acpi_tables::{ aml::Aml, rsdp::RSDP, sdt::{GenericAddress, SDT}, }; -use vm_memory::{GuestAddress, GuestMemoryMmap}; - -use vm_memory::{Address, ByteValued, Bytes}; - -use std::sync::{Arc, Mutex}; - -use crate::cpu::CpuManager; -use crate::device_manager::DeviceManager; -use crate::memory_manager::MemoryManager; use arch::layout; +use std::sync::{Arc, Mutex}; +use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap, GuestMemoryRegion}; #[repr(packed)] #[derive(Default)] @@ -28,6 +24,22 @@ struct PCIRangeEntry { _reserved: u32, } +#[repr(packed)] +#[derive(Default)] +struct MemoryAffinity { + pub type_: u8, + pub length: u8, + pub proximity_domain: u32, + _reserved1: u16, + pub base_addr_lo: u32, + pub base_addr_hi: u32, + pub length_lo: u32, + pub length_hi: u32, + _reserved2: u32, + pub flags: u32, + _reserved3: u64, +} + pub fn create_dsdt_table( device_manager: &Arc>, cpu_manager: &Arc>, @@ -125,6 +137,60 @@ pub fn create_acpi_tables( .expect("Error writing MCFG table"); tables.push(mcfg_offset.0); + // SRAT + // Only created if the NUMA nodes list is not empty. + let numa_nodes = memory_manager.lock().unwrap().numa_nodes().clone(); + let (prev_tbl_len, prev_tbl_off) = if numa_nodes.is_empty() { + (mcfg.len(), mcfg_offset) + } else { + let mut srat = SDT::new(*b"SRAT", 36, 3, *b"CLOUDH", *b"CHSRAT ", 1); + // SRAT reserved 12 bytes + srat.append_slice(&[0u8; 12]); + + // Check the MemoryAffinity structure is the right size as expected by + // the ACPI specification. + assert_eq!(std::mem::size_of::(), 40); + + for (node_id, node) in numa_nodes.iter() { + for region in node.memory_regions() { + let proximity_domain = *node_id as u32; + let base_addr = region.start_addr().raw_value(); + let base_addr_lo = (base_addr & 0xffff_ffff) as u32; + let base_addr_hi = (base_addr >> 32) as u32; + let length = region.len() as u64; + let length_lo = (length & 0xffff_ffff) as u32; + let length_hi = (length >> 32) as u32; + + // Flags + // - Enabled = 1 (bit 0) + // - Hot Pluggable = 0 (bit 1) + // - NonVolatile = 0 (bit 2) + // - Reserved bits 3-31 + let flags = 1; + + srat.append(MemoryAffinity { + type_: 1, + length: 40, + proximity_domain, + base_addr_lo, + base_addr_hi, + length_lo, + length_hi, + flags, + ..Default::default() + }); + } + } + + let srat_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap(); + guest_mem + .write_slice(srat.as_slice(), srat_offset) + .expect("Error writing SRAT table"); + tables.push(srat_offset.0); + + (srat.len(), srat_offset) + }; + // XSDT let mut xsdt = SDT::new(*b"XSDT", 36, 1, *b"CLOUDH", *b"CHXSDT ", 1); for table in tables { @@ -132,7 +198,7 @@ pub fn create_acpi_tables( } xsdt.update_checksum(); - let xsdt_offset = mcfg_offset.checked_add(mcfg.len() as u64).unwrap(); + let xsdt_offset = prev_tbl_off.checked_add(prev_tbl_len as u64).unwrap(); guest_mem .write_slice(xsdt.as_slice(), xsdt_offset) .expect("Error writing XSDT table");