|
| 1 | +use crate::{ |
| 2 | + AcpiTable, |
| 3 | + sdt::{SdtHeader, Signature}, |
| 4 | +}; |
| 5 | +use bit_field::BitField; |
| 6 | +use core::{ |
| 7 | + marker::{PhantomData, PhantomPinned}, |
| 8 | + mem, |
| 9 | + pin::Pin, |
| 10 | +}; |
| 11 | +use log::warn; |
| 12 | + |
| 13 | +/// Represents the SRAT (System Resource Affinity Table). This is a variable length table that |
| 14 | +/// allows devices (processors, memory ranges, and generic 'initiators') to be associated with |
| 15 | +/// system locality / proximity domains and clock domains. |
| 16 | +#[derive(Debug)] |
| 17 | +#[repr(C, packed)] |
| 18 | +pub struct Srat { |
| 19 | + pub header: SdtHeader, |
| 20 | + _reserved0: u32, |
| 21 | + _reserved1: u64, |
| 22 | + _pinned: PhantomPinned, |
| 23 | +} |
| 24 | + |
| 25 | +unsafe impl AcpiTable for Srat { |
| 26 | + const SIGNATURE: Signature = Signature::SRAT; |
| 27 | + |
| 28 | + fn header(&self) -> &SdtHeader { |
| 29 | + &self.header |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +impl Srat { |
| 34 | + pub fn entries(self: Pin<&Self>) -> SratEntryIter<'_> { |
| 35 | + let ptr = unsafe { Pin::into_inner_unchecked(self) as *const Srat as *const u8 }; |
| 36 | + SratEntryIter { |
| 37 | + pointer: unsafe { ptr.add(mem::size_of::<Srat>()) }, |
| 38 | + remaining_length: self.header.length - mem::size_of::<Srat>() as u32, |
| 39 | + _phantom: PhantomData, |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +#[derive(Debug)] |
| 45 | +pub struct SratEntryIter<'a> { |
| 46 | + pointer: *const u8, |
| 47 | + /* |
| 48 | + * The iterator can only have at most `u32::MAX` remaining bytes, because the length of the |
| 49 | + * whole SDT can only be at most `u32::MAX`. |
| 50 | + */ |
| 51 | + remaining_length: u32, |
| 52 | + _phantom: PhantomData<&'a ()>, |
| 53 | +} |
| 54 | + |
| 55 | +#[derive(Debug)] |
| 56 | +pub enum SratEntry<'a> { |
| 57 | + LocalApicAffinity(&'a LocalApicAffinity), |
| 58 | + MemoryAffinity(&'a MemoryAffinity), |
| 59 | + LocalApicX2Affinity(&'a LocalApicX2Affinity), |
| 60 | + GiccAffinity(&'a GiccAffinity), |
| 61 | + GicItsAffinity(&'a GicItsAffinity), |
| 62 | + GicInitiatorAffinity(&'a GicInitiatorAffinity), |
| 63 | +} |
| 64 | + |
| 65 | +impl<'a> Iterator for SratEntryIter<'a> { |
| 66 | + type Item = SratEntry<'a>; |
| 67 | + |
| 68 | + fn next(&mut self) -> Option<Self::Item> { |
| 69 | + while self.remaining_length > 0 { |
| 70 | + let entry_pointer = self.pointer; |
| 71 | + let header = unsafe { *(self.pointer as *const EntryHeader) }; |
| 72 | + |
| 73 | + if header.length as u32 > self.remaining_length { |
| 74 | + warn!("Invalid entry of type {} in SRAT - extending past length of table. Ignoring", header.typ); |
| 75 | + return None; |
| 76 | + } |
| 77 | + |
| 78 | + self.pointer = unsafe { self.pointer.byte_offset(header.length as isize) }; |
| 79 | + self.remaining_length = self.remaining_length.saturating_sub(header.length as u32); |
| 80 | + |
| 81 | + match header.typ { |
| 82 | + 0 => { |
| 83 | + return Some(SratEntry::LocalApicAffinity(unsafe { |
| 84 | + &*(entry_pointer as *const LocalApicAffinity) |
| 85 | + })); |
| 86 | + } |
| 87 | + 1 => { |
| 88 | + return Some(SratEntry::MemoryAffinity(unsafe { &*(entry_pointer as *const MemoryAffinity) })); |
| 89 | + } |
| 90 | + 2 => { |
| 91 | + return Some(SratEntry::LocalApicX2Affinity(unsafe { |
| 92 | + &*(entry_pointer as *const LocalApicX2Affinity) |
| 93 | + })); |
| 94 | + } |
| 95 | + 3 => return Some(SratEntry::GiccAffinity(unsafe { &*(entry_pointer as *const GiccAffinity) })), |
| 96 | + 4 => { |
| 97 | + return Some(SratEntry::GicItsAffinity(unsafe { &*(entry_pointer as *const GicItsAffinity) })); |
| 98 | + } |
| 99 | + 5 => { |
| 100 | + return Some(SratEntry::GicInitiatorAffinity(unsafe { |
| 101 | + &*(entry_pointer as *const GicInitiatorAffinity) |
| 102 | + })); |
| 103 | + } |
| 104 | + other => warn!("Unrecognised entry in SRAT of type {}", other), |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + None |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +#[derive(Clone, Copy, Debug)] |
| 113 | +#[repr(C, packed)] |
| 114 | +pub struct EntryHeader { |
| 115 | + pub typ: u8, |
| 116 | + pub length: u16, |
| 117 | +} |
| 118 | + |
| 119 | +#[derive(Clone, Copy, Debug)] |
| 120 | +#[repr(C, packed)] |
| 121 | +pub struct LocalApicAffinity { |
| 122 | + pub header: EntryHeader, |
| 123 | + pub proximity_domain_low: u8, |
| 124 | + pub apic_id: u8, |
| 125 | + pub flags: u32, |
| 126 | + pub local_sapic_eid: u8, |
| 127 | + pub proximity_domain_high: [u8; 3], |
| 128 | + pub clock_domain: u32, |
| 129 | +} |
| 130 | + |
| 131 | +impl LocalApicAffinity { |
| 132 | + pub fn proximity_domain(&self) -> u32 { |
| 133 | + u32::from_le_bytes([ |
| 134 | + self.proximity_domain_low, |
| 135 | + self.proximity_domain_high[0], |
| 136 | + self.proximity_domain_high[1], |
| 137 | + self.proximity_domain_high[2], |
| 138 | + ]) |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +#[derive(Clone, Copy, Debug)] |
| 143 | +#[repr(C, packed)] |
| 144 | +pub struct MemoryAffinity { |
| 145 | + pub header: EntryHeader, |
| 146 | + pub proximity_domain: u32, |
| 147 | + _reserved0: u16, |
| 148 | + pub base_address_low: u32, |
| 149 | + pub base_address_high: u32, |
| 150 | + pub length_low: u32, |
| 151 | + pub length_high: u32, |
| 152 | + _reserved1: u32, |
| 153 | + pub flags: u32, |
| 154 | + _reserved2: u64, |
| 155 | +} |
| 156 | + |
| 157 | +impl MemoryAffinity { |
| 158 | + pub fn base_address(&self) -> u64 { |
| 159 | + let mut address = self.base_address_low as u64; |
| 160 | + address.set_bits(32..64, self.base_address_high as u64); |
| 161 | + address |
| 162 | + } |
| 163 | + |
| 164 | + pub fn length(&self) -> u64 { |
| 165 | + let mut length = self.length_low as u64; |
| 166 | + length.set_bits(32..64, self.base_address_high as u64); |
| 167 | + length |
| 168 | + } |
| 169 | +} |
| 170 | + |
| 171 | +#[derive(Clone, Copy, Debug)] |
| 172 | +#[repr(C, packed)] |
| 173 | +pub struct LocalApicX2Affinity { |
| 174 | + pub header: EntryHeader, |
| 175 | + _reserved0: u16, |
| 176 | + pub proximity_domain: u32, |
| 177 | + pub x2apic_id: u32, |
| 178 | + pub flags: u32, |
| 179 | + pub clock_domain: u32, |
| 180 | + _reserved1: u32, |
| 181 | +} |
| 182 | + |
| 183 | +#[derive(Clone, Copy, Debug)] |
| 184 | +#[repr(C, packed)] |
| 185 | +pub struct GiccAffinity { |
| 186 | + pub header: EntryHeader, |
| 187 | + pub proximity_domain: u32, |
| 188 | + pub acpi_processor_uid: u32, |
| 189 | + pub flags: u32, |
| 190 | + pub clock_domain: u32, |
| 191 | +} |
| 192 | + |
| 193 | +#[derive(Clone, Copy, Debug)] |
| 194 | +#[repr(C, packed)] |
| 195 | +pub struct GicItsAffinity { |
| 196 | + pub header: EntryHeader, |
| 197 | + pub proximity_domain: u32, |
| 198 | + _reserved0: u16, |
| 199 | + pub its_id: u32, |
| 200 | +} |
| 201 | + |
| 202 | +#[derive(Clone, Copy, Debug)] |
| 203 | +#[repr(C, packed)] |
| 204 | +pub struct GicInitiatorAffinity { |
| 205 | + pub header: EntryHeader, |
| 206 | + _reserved0: u8, |
| 207 | + pub device_handle_type: u8, |
| 208 | + pub proximity_domain: u32, |
| 209 | + pub device_handle: [u8; 16], |
| 210 | + pub flags: u32, |
| 211 | + _reserved1: u32, |
| 212 | +} |
0 commit comments