use crate::{
AcpiTable,
sdt::{SdtHeader, Signature},
};
use core::{marker::PhantomPinned, mem, pin::Pin, slice};
use log::warn;
#[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
}
}
}