Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/platform/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod interrupt;
pub mod numa;
pub mod pci;

pub use interrupt::InterruptModel;
Expand Down
87 changes: 87 additions & 0 deletions src/platform/numa.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use crate::{
AcpiTables,
Handler,
sdt::{
slit::{DistanceMatrix, Slit},
srat::{LocalApicAffinityFlags, MemoryAffinityFlags, Srat, SratEntry},
},
};
use alloc::{alloc::Global, vec::Vec};
use core::alloc::Allocator;

/// Information about the setup of NUMA (Non-Uniform Memory Architecture) resources within the
/// sytem.
pub struct NumaInfo<A: Allocator = Global> {
pub processor_affinity: Vec<ProcessorAffinity, A>,
pub memory_affinity: Vec<MemoryAffinity, A>,
pub num_proximity_domains: usize,
pub distance_matrix: Vec<u8, A>,
}

impl NumaInfo<Global> {
pub fn new(tables: AcpiTables<impl Handler>) -> NumaInfo<Global> {
Self::new_in(tables, Global)
}
}

impl<A: Allocator + Clone> NumaInfo<A> {
pub fn new_in(tables: AcpiTables<impl Handler>, allocator: A) -> NumaInfo<A> {
let mut processor_affinity = Vec::new_in(allocator.clone());
let mut memory_affinity = Vec::new_in(allocator.clone());

if let Some(srat) = tables.find_table::<Srat>() {
for entry in srat.get().entries() {
match entry {
SratEntry::LocalApicAffinity(entry) => processor_affinity.push(ProcessorAffinity {
local_apic_id: entry.apic_id as u32,
proximity_domain: entry.proximity_domain(),
is_enabled: { entry.flags }.contains(LocalApicAffinityFlags::ENABLED),
}),
SratEntry::LocalApicX2Affinity(entry) => processor_affinity.push(ProcessorAffinity {
local_apic_id: entry.x2apic_id,
proximity_domain: entry.proximity_domain,
is_enabled: { entry.flags }.contains(LocalApicAffinityFlags::ENABLED),
}),
SratEntry::MemoryAffinity(entry) => memory_affinity.push(MemoryAffinity {
base_address: entry.base_address(),
length: entry.length(),
proximity_domain: entry.proximity_domain,
is_enabled: { entry.flags }.contains(MemoryAffinityFlags::ENABLED),
is_hot_pluggable: { entry.flags }.contains(MemoryAffinityFlags::HOT_PLUGGABLE),
is_non_volatile: { entry.flags }.contains(MemoryAffinityFlags::NON_VOLATILE),
}),
_ => (),
}
}
}

let (num_proximity_domains, distance_matrix) = if let Some(slit) = tables.find_table::<Slit>() {
(slit.get().num_proximity_domains as usize, slit.get().matrix_raw().to_vec_in(allocator.clone()))
} else {
(0, Vec::new_in(allocator.clone()))
};

NumaInfo { processor_affinity, memory_affinity, num_proximity_domains, distance_matrix }
}

pub fn distance_matrix(&self) -> DistanceMatrix<'_> {
DistanceMatrix { num_proximity_domains: self.num_proximity_domains as u64, matrix: &self.distance_matrix }
}
}

#[derive(Clone, Debug)]
pub struct ProcessorAffinity {
pub local_apic_id: u32,
pub proximity_domain: u32,
pub is_enabled: bool,
}

#[derive(Clone, Debug)]
pub struct MemoryAffinity {
pub base_address: u64,
pub length: u64,
pub proximity_domain: u32,
pub is_enabled: bool,
pub is_hot_pluggable: bool,
pub is_non_volatile: bool,
}
13 changes: 11 additions & 2 deletions src/sdt/madt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use core::{
mem,
pin::Pin,
};
use log::warn;

#[derive(Clone, Copy, Debug)]
pub enum MadtError {
Expand Down Expand Up @@ -114,8 +115,16 @@ impl<'a> Iterator for MadtEntryIter<'a> {
let entry_pointer = self.pointer;
let header = unsafe { *(self.pointer as *const EntryHeader) };

self.pointer = unsafe { self.pointer.offset(header.length as isize) };
self.remaining_length -= header.length as u32;
if header.length as u32 > self.remaining_length {
warn!(
"Invalid entry of type {} in MADT - extending past length of table. Ignoring",
header.entry_type
);
return None;
}

self.pointer = unsafe { self.pointer.byte_offset(header.length as isize) };
self.remaining_length = self.remaining_length.saturating_sub(header.length as u32);

macro_rules! construct_entry {
($entry_type:expr,
Expand Down
2 changes: 2 additions & 0 deletions src/sdt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ pub mod fadt;
pub mod hpet;
pub mod madt;
pub mod mcfg;
pub mod slit;
pub mod spcr;
pub mod srat;

use crate::AcpiError;
use core::{fmt, mem::MaybeUninit, str};
Expand Down
62 changes: 62 additions & 0 deletions src/sdt/slit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::{
AcpiTable,
sdt::{SdtHeader, Signature},
};
use core::{marker::PhantomPinned, mem, pin::Pin, slice};
use log::warn;

/// The SLIT (System Locality Information Table) provides a matrix of relative distances between
/// all proximity domains. It encodes a list of N*N entries, where each entry is `u8` and the
/// relative distance between proximity domains `(i, j)` is the entry at `i*N+j`. The distance
/// between a proximity domain and itself is normalised to a value of `10`.
#[derive(Debug)]
#[repr(C, packed)]
pub struct Slit {
pub header: SdtHeader,
pub num_proximity_domains: u64,
_pinned: PhantomPinned,
}

unsafe impl AcpiTable for Slit {
const SIGNATURE: Signature = Signature::SLIT;

fn header(&self) -> &SdtHeader {
&self.header
}
}

impl Slit {
pub fn matrix(self: Pin<&Self>) -> DistanceMatrix<'_> {
DistanceMatrix { num_proximity_domains: self.num_proximity_domains, matrix: self.matrix_raw() }
}

pub fn matrix_raw(self: Pin<&Self>) -> &[u8] {
let mut num_entries = self.num_proximity_domains * self.num_proximity_domains;
if (mem::size_of::<Slit>() + num_entries as usize * num_entries as usize * mem::size_of::<u8>())
> self.header.length as usize
{
warn!("SLIT too short for given number of proximity domains! Returning empty matrix");
num_entries = 0;
}

unsafe {
let ptr = Pin::into_inner_unchecked(self) as *const Slit as *const u8;
slice::from_raw_parts(ptr.byte_add(mem::size_of::<Slit>()), num_entries as usize)
}
}
}

pub struct DistanceMatrix<'a> {
pub num_proximity_domains: u64,
pub matrix: &'a [u8],
}

impl DistanceMatrix<'_> {
pub fn distance(&self, i: u32, j: u32) -> Option<u8> {
if i as u64 <= self.num_proximity_domains && j as u64 <= self.num_proximity_domains {
Some(self.matrix[i as usize + j as usize * self.num_proximity_domains as usize])
} else {
None
}
}
}
Loading
Loading